Skip to content

Latest commit

 

History

History
1689 lines (1230 loc) · 46.8 KB

File metadata and controls

1689 lines (1230 loc) · 46.8 KB

三、Pandas 数据结构

本章是本书中最重要的部分。 现在,我们将开始研究 Pandas 的肉和骨头。 我们首先浏览 NumPy ndarrays,这是一种不在 Pandas 中而是 NumPy 的数据结构。 NumPy ndarrays的知识很有用,因为它构成了 Pandas 数据结构的基础。 NumPy 数组的另一个主要优点是它们执行称为向量化的操作,这些操作需要在 Python 数组上遍历/循环的操作要快得多。

我们将在本章中介绍的主题包括:

  • 浏览numpy.ndarray数据结构。
  • pandas.Series一维1D)Pandas 数据结构
  • pandas.DatcaFrame二维2D)Pandas 表格数据结构
  • pandas.Panel3 维3D)Pandas 数据结构

在本章中,我将通过使用 IPython(一个基于浏览器的界面,使用户可以交互地向 Python 解释器键入命令)的众多示例来介绍这些资料。 上一章提供了安装 IPython 的说明。

NumPy ndarray

NumPy 库是一个非常重要的包,用于使用 Python 进行数值计算。 其主要功能包括:

  • numpy.ndarray类型,同构多维数组
  • 访问大量数学函数 – 线性代数,统计信息等
  • 能够集成 C,C++ 和 Fortran 代码

有关 NumPy 的更多信息,请参见这里

NumPy 中的主要数据结构是数组类ndarray。 它是元素的齐次多维(n 维)表,它们像常规数组一样由整数索引。 但是,numpy.ndarray(也称为numpy.array)与标准 Python array.array类不同,后者提供的功能要少得多。 这里提供了有关各种操作的更多信息。

NumPy 数组创建

可以通过调用各种 NumPy 方法以多种方式创建 NumPy 数组。

numpy.array和 NumPy 数组

NumPy 数组可以直接通过numpy.array构造器创建:

In [1]: import numpy as np
In [2]: ar1=np.array([0,1,2,3])# 1 dimensional array
In [3]: ar2=np.array ([[0,3,5],[2,8,7]]) # 2D array
In [4]: ar1
Out[4]: array([0, 1, 2, 3])
In [5]: ar2
Out[5]: array([[0, 3, 5],
 [2, 8, 7]])

数组的形状通过ndarray.shape给出:

In [5]: ar2.shape
Out[5]: (2, 3)

尺寸数量使用ndarray.ndim获得:

In [7]: ar2.ndim
Out[7]: 2

numpy.arange和 NumPy 数组

ndarray.arange是 Python 的range函数的 NumPy 版本:In [10]:产生从 0 到 11 的整数,不包括 12。

In [10]: ar3=np.arange(12); ar3
Out[10]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
In [11]: # start, end (exclusive), step size
 ar4=np.arange(3,10,3); ar4
Out[11]: array([3, 6, 9])

numpy.linspace和 NumPy 数组

ndarray.linspace在起点和终点之间生成线性均匀间隔的元素:

In [13]:# args - start element,end element, number of elements
 ar5=np.linspace(0,2.0/3,4); ar5
Out[13]:array([ 0.,  0.22222222,  0.44444444,  0.66666667])

各种其他函数和 NumPy 数组

这些函数包括numpy.zerosnumpy.onesnumpy.eyenrandom.randnumpy.random.randnnumpy.empty

在每种情况下,该参数都必须是一个元组。 对于一维数组,您只需指定元素数,而无需元组。

numpy.ones

以下命令行说明了该函数:

In [14]:# Produces 2x3x2 array of 1's.
 ar7=np.ones((2,3,2)); ar7
Out[14]: array([[[ 1.,  1.],
 [ 1.,  1.],
 [ 1.,  1.]],
 [[ 1.,  1.],
 [ 1.,  1.],
 [ 1.,  1.]]])

numpy.zeros

以下命令行说明了该函数:

In [15]:# Produce 4x2 array of zeros.
 ar8=np.zeros((4,2));ar8
Out[15]: array([[ 0.,  0.],
 [ 0.,  0.], 
 [ 0.,  0.],
 [ 0.,  0.]])

numpy.eye

以下命令行说明了该函数:

In [17]:# Produces identity matrix
 ar9 = np.eye(3);ar9
Out[17]: array([[ 1.,  0.,  0.],
 [ 0.,  1.,  0.],
 [ 0.,  0.,  1.]])

numpy.diag

以下命令行说明了该函数:

In [18]: # Create diagonal array
 ar10=np.diag((2,1,4,6));ar10
Out[18]: array([[2, 0, 0, 0],
 [0, 1, 0, 0],
 [0, 0, 4, 0],
 [0, 0, 0, 6]])

numpy.random.rand

以下命令行说明了该函数:

In [19]: # Using the rand, randn functions
 # rand(m) produces uniformly distributed random numbers with range 0 to m
 np.random.seed(100)   # Set seed
 ar11=np.random.rand(3); ar11
Out[19]: array([ 0.54340494,  0.27836939,  0.42451759])
In [20]: # randn(m) produces m normally distributed (Gaussian) random numbers
 ar12=np.random.rand(5); ar12
Out[20]: array([ 0.35467445, -0.78606433, -0.2318722 ,    0.20797568,  0.93580797])

numpy.empty

使用np.empty创建未初始化的数组比分配np.onesnp.zerosmalloccmalloc)是一种更便宜,更快捷的分配数组的方法。 但是,只有在确定所有元素稍后都会初始化时,才应使用它:

In [21]: ar13=np.empty((3,2)); ar13
Out[21]: array([[ -2.68156159e+154,   1.28822983e-231],
 [  4.22764845e-307,   2.78310358e-309],
 [  2.68156175e+154,   4.17201483e-309]])

np.tile

np.tile函数允许通过根据参数重复几次来从较小的数组构造一个数组:

In [334]: np.array([[1,2],[6,7]])
Out[334]: array([[1, 2],
 [6, 7]])
In [335]: np.tile(np.array([[1,2],[6,7]]),3)
Out[335]: array([[1, 2, 1, 2, 1, 2],
 [6, 7, 6, 7, 6, 7]])
In [336]: np.tile(np.array([[1,2],[6,7]]),(2,2))
Out[336]: array([[1, 2, 1, 2],
 [6, 7, 6, 7],
 [1, 2, 1, 2],
 [6, 7, 6, 7]])

NumPy 数据类型

我们可以使用dtype参数指定数字数组的内容类型:

In [50]: ar=np.array([2,-1,6,3],dtype='float'); ar
Out[50]: array([ 2., -1.,  6.,  3.])
In [51]: ar.dtype
Out[51]: dtype('float64')
In [52]: ar=np.array([2,4,6,8]); ar.dtype
Out[52]: dtype('int64')
In [53]: ar=np.array([2.,4,6,8]); ar.dtype
Out[53]: dtype('float64')

NumPy 中的默认dtypefloat。 对于字符串,dtype是数组中最长字符串的长度:

In [56]: sar=np.array(['Goodbye','Welcome','Tata','Goodnight']); sar.dtype
Out[56]: dtype('S9')

您不能在 NumPy 中创建长度可变的字符串,因为 NumPy 需要知道为该字符串分配多少空间。 dtypes也可以是布尔值,复数等等:

In [57]: bar=np.array([True, False, True]); bar.dtype
Out[57]: dtype('bool')

ndarray的数据类型可以用与其他语言(例如 Java 或 C/C++)相同的方式进行更改。 例如,floatint等。 执行此操作的机制是使用numpy.ndarray.astype()函数。 这是一个例子:

In [3]: f_ar = np.array([3,-2,8.18])
 f_ar
Out[3]: array([ 3\.  , -2\.  ,  8.18])
In [4]: f_ar.astype(int)
Out[4]: array([ 3, -2,  8])

有关转换的更多信息,请参见官方文档

NumPy 索引和切片

NumPy 中的数组索引以0开头,例如 Python,Java 和 C++ 之类的语言,而 Fortran,Matlab 和 Octave 的数组索引以1开头。 数组可以以标准方式建立索引,就像我们将索引到任何其他 Python 序列中一样:

# print entire array, element 0, element 1, last element.
In [36]: ar = np.arange(5); print ar; ar[0], ar[1], ar[-1]
[0 1 2 3 4]
Out[36]: (0, 1, 4)
# 2nd, last and 1st elements
In [65]: ar=np.arange(5); ar[1], ar[-1], ar[0]
Out[65]: (1, 4, 0)

可以使用::-1惯用法反转数组,如下所示:

In [24]: ar=np.arange(5); ar[::-1]
Out[24]: array([4, 3, 2, 1, 0])

多维数组使用整数元组建立索引:

In [71]: ar = np.array([[2,3,4],[9,8,7],[11,12,13]]); ar
Out[71]: array([[ 2,  3,  4],
 [ 9,  8,  7],
 [11, 12, 13]])
In [72]: ar[1,1]
Out[72]: 8

在这里,我们将row1column1的条目设置为5

In [75]: ar[1,1]=5; ar
Out[75]: array([[ 2,  3,  4],
 [ 9,  5,  7],
 [11, 12, 13]])

检索第 2 行:

In [76]:  ar[2]
Out[76]: array([11, 12, 13])
In [77]: ar[2,:]
Out[77]: array([11, 12, 13])

检索列 1:

In [78]: ar[:,1]
Out[78]: array([ 3,  5, 12])

如果指定的索引超出数组范围,则将引发IndexError

In [6]: ar = np.array([0,1,2])
In [7]: ar[5]
 ---------------------------------------------------------------------------
 IndexError                  Traceback (most recent call last)
 <ipython-input-7-8ef7e0800b7a> in <module>()
 ----> 1 ar[5]
 IndexError: index 5 is out of bounds for axis 0 with size 3

因此,对于 2D 数组,第一维表示行,第二维表示列。 冒号(:)表示对维度所有元素的选择。

数组切片

可以使用以下语法对数组进行切片:ar[startIndex: endIndex: stepValue]

In [82]: ar=2*np.arange(6); ar
Out[82]: array([ 0,  2,  4,  6,  8, 10])
In [85]: ar[1:5:2]
Out[85]: array([2, 6])

请注意,如果我们希望包含endIndex值,则需要超过它,如下所示:

In [86]: ar[1:6:2]
Out[86]: array([ 2,  6, 10])

使用ar[:n]获得前 n 个元素:

In [91]: ar[:4]
Out[91]: array([0, 2, 4, 6])

这里的隐含假设是startIndex=0, step=1

从元素 4 开始直到结束:

In [92]: ar[4:]
Out[92]: array([ 8, 10])

stepValue=3的切片数组:

In [94]: ar[::3]
Out[94]: array([0, 6])

为了说明 NumPy 中索引的范围,让我们参考此图,该图取自 SciPy 2013 上的 NumPy 演讲,可在这个链接中找到:

Array slicing

现在让我们检查上图中的表达式的含义:

  • 表达式a[0,3:5]表示从第 0 行和第 3-5 列开始,其中不包括第 5 列。
  • 在表达式a[4:,4:]中,前 4 个表示第 4 行的起点,并将给出所有列,即数组[[40, 41, 42, 43, 44, 45], [50, 51, 52, 53, 54, 55]]。 第二个 4 显示了在第 4 列开始处的截止,以产生数组[[44, 45], [54, 55]]
  • 表达式a[:,2]给出了列 2 中的所有行。
  • 现在,在最后一个表达式a[2::2,::2]中,2::2指示起点在第 2 行,此处的步长值也为 2。这将为我们提供数组[[20, 21, 22, 23, 24, 25], [40, 41, 42, 43, 44, 45]。 此外,::2指定我们以 2 的步骤检索列,从而产生最终结果数组([[20, 22, 24], [40, 42, 44]])。

可以将分配和切片结合在一起,如以下代码片段所示:

In [96]: ar
Out[96]: array([ 0,  2,  4,  6,  8, 10])
In [100]: ar[:3]=1; ar
Out[100]: array([ 1,  1,  1,  6,  8, 10])
In [110]: ar[2:]=np.ones(4);ar
Out[110]: array([1, 1, 1, 1, 1, 1])

数组遮罩

在这里,NumPy 数组可用作遮罩,以选择或滤除原始数组的元素。 例如,请参见以下代码段:

In [146]: np.random.seed(10)
 ar=np.random.random_integers(0,25,10); ar
Out[146]: array([ 9,  4, 15,  0, 17, 25, 16, 17,  8,  9])
In [147]: evenMask=(ar % 2==0); evenMask
Out[147]: array([False,  True, False,  True, False, False,  True, False,  True, False], dtype=bool)
In [148]: evenNums=ar[evenMask]; evenNums
Out[148]: array([ 4,  0, 16,  8])

在下面的示例中,我们随机生成一个 0 到 25 之间的 10 个整数的数组。然后,我们创建一个布尔掩码数组,该数组用于仅滤除偶数。 例如,如果我们希望通过将默认值替换为缺失值来消除缺失值,则此掩码功能可能非常有用。 在这里,缺失值''被替换为'USA'作为默认国家/地区。 请注意,''也是一个空字符串:

In [149]: ar=np.array(['Hungary','Nigeria', 
 'Guatemala','','Poland',
 '','Japan']); ar
Out[149]: array(['Hungary', 'Nigeria', 'Guatemala', 
 '', 'Poland', '', 'Japan'], 
 dtype='|S9')
In [150]: ar[ar=='']='USA'; ar
Out[150]: array(['Hungary', 'Nigeria', 'Guatemala', 
 'USA', 'Poland', 'USA', 'Japan'], dtype='|S9')

整数数组也可以用于索引一个数组以生成另一个数组。 请注意,这会产生多个值。 因此,输出必须是ndarray类型的数组。 以下代码段对此进行了说明:

In [173]: ar=11*np.arange(0,10); ar
Out[173]: array([ 0, 11, 22, 33, 44, 55, 66, 77, 88, 99])
In [174]: ar[[1,3,4,2,7]]
Out[174]: array([11, 33, 44, 22, 77])

在前面的代码中,选择对象是一个列表,并且选择了索引 1、3、4、2 和 7 的元素。 现在,假设我们将其更改为以下内容:

In [175]: ar[1,3,4,2,7]

由于数组是一维的,因此我们收到IndexError错误,并且指定的索引太多,无法访问它。

IndexError          Traceback (most recent call last)
<ipython-input-175-adbcbe3b3cdc> in <module>()
----> 1 ar[1,3,4,2,7]

IndexError: too many indices

数组索引也可以进行此分配,如下所示:

In [176]: ar[[1,3]]=50; ar
Out[176]: array([ 0, 50, 22, 50, 44, 55, 66, 77, 88, 99])

通过使用数组索引列表从另一个数组创建新数组时,新数组具有相同的形状。

复杂索引

在这里,我们说明了如何使用复杂的索引将值从较小的数组分配到较大的数组:

In [188]: ar=np.arange(15); ar
Out[188]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])

In [193]: ar2=np.arange(0,-10,-1)[::-1]; ar2
Out[193]: array([-9, -8, -7, -6, -5, -4, -3, -2, -1,  0])

切出ar的前 10 个元素,并用ar2中的元素替换它们,如下所示:

In [194]: ar[:10]=ar2; ar
Out[194]: array([-9, -8, -7, -6, -5, -4, -3, -2, -1,  0, 10, 11, 12, 13, 14])

副本和视图

NumPy 数组上的视图只是描绘其包含的数据的一种特殊方式。 创建视图不会导致数组的新副本,而是可以按特定顺序排列其中包含的数据,或者仅显示某些数据行。 因此,如果将数据替换为基础数组的数据,则无论何时通过索引访问数据,这都会反映在视图中。

切片时不会将初始数组复制到内存中,因此效率更高。 np.may_share_memory方法可用于查看两个数组是否共享同一存储块。 但是,应谨慎使用,因为它可能会产生误报。 修改视图会修改原始数组:

In [118]:ar1=np.arange(12); ar1
Out[118]:array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

In [119]:ar2=ar1[::2]; ar2
Out[119]: array([ 0,  2,  4,  6,  8, 10])

In [120]: ar2[1]=-1; ar1
Out[120]: array([ 0,  1, -1,  3,  4,  5,  6,  7,  8,  9, 10, 11])

为了强制 NumPy 复制数组,我们使用np.copy函数。 正如我们在以下数组中看到的,修改复制的数组时,原始数组不受影响:

In [124]: ar=np.arange(8);ar
Out[124]: array([0, 1, 2, 3, 4, 5, 6, 7])

In [126]: arc=ar[:3].copy(); arc
Out[126]: array([0, 1, 2])

In [127]: arc[0]=-1; arc
Out[127]: array([-1,  1,  2])

In [128]: ar
Out[128]: array([0, 1, 2, 3, 4, 5, 6, 7])

操作

在这里,我们介绍 NumPy 中的各种操作。

基本操作

基本算术运算使用标量操作数逐个元素地工作。 它们是- +-*/**

In [196]: ar=np.arange(0,7)*5; ar
Out[196]: array([ 0,  5, 10, 15, 20, 25, 30])

In [198]: ar=np.arange(5) ** 4 ; ar
Out[198]: array([  0,   1,  16,  81, 256])

In [199]: ar ** 0.5
Out[199]: array([  0.,   1.,   4.,   9.,  16.])

当另一个数组是第二个操作数时,操作也按元素方式工作,如下所示:

In [209]: ar=3+np.arange(0, 30,3); ar
Out[209]: array([ 3,  6,  9, 12, 15, 18, 21, 24, 27, 30])

In [210]: ar2=np.arange(1,11); ar2
Out[210]: array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

在下面的代码段中,我们看到了逐元素的减法,除法和乘法:

In [211]: ar-ar2
Out[211]: array([ 2,  4,  6,  8, 10, 12, 14, 16, 18, 20])

In [212]: ar/ar2
Out[212]: array([3, 3, 3, 3, 3, 3, 3, 3, 3, 3])

In [213]: ar*ar2
Out[213]: array([  3,  12,  27,  48,  75, 108, 147, 192, 243, 300])

使用 NumPy 进行此操作比使用纯 Python 更快。 IPython 中的%timeit函数被称为魔术函数,它使用 Python timeit模块来定时执行 Python 语句或表达式,其解释如下:

In [214]: ar=np.arange(1000)
 %timeit ar**3
 100000 loops, best of 3: 5.4 µs per loop

In [215]:ar=range(1000)
 %timeit [ar[i]**3 for i in ar]
 1000 loops, best of 3: 199 µs per loop

数组乘法与矩阵乘法不同; 它是元素方式的,意味着相应的元素被相乘在一起。 对于矩阵乘法,请使用点运算符。 有关更多信息,请参考这里

In [228]: ar=np.array([[1,1],[1,1]]); ar
Out[228]: array([[1, 1],
 [1, 1]])

In [230]: ar2=np.array([[2,2],[2,2]]); ar2
Out[230]: array([[2, 2],
 [2, 2]])

In [232]: ar.dot(ar2)
Out[232]: array([[4, 4],

 [4, 4]])

比较和逻辑运算也是基于元素的:

In [235]: ar=np.arange(1,5); ar
Out[235]: array([1, 2, 3, 4])

In [238]: ar2=np.arange(5,1,-1);ar2
Out[238]: array([5, 4, 3, 2])

In [241]: ar < ar2
Out[241]: array([ True,  True, False, False], dtype=bool)

In [242]: l1 = np.array([True,False,True,False])
 l2 = np.array([False,False,True, False])
 np.logical_and(l1,l2)
Out[242]: array([False, False,  True, False], dtype=bool)

其他 NumPy 运算(例如logsincosexp)也是按元素排列的:

In [244]: ar=np.array([np.pi, np.pi/2]); np.sin(ar)
Out[244]: array([  1.22464680e-16,   1.00000000e+00])

请注意,对于在两个 NumPy 数组上的按元素进行操作,两个数组必须为具有相同的形状,否则将导致错误,因为该操作的参数必须是两个数组中的对应元素:

In [245]: ar=np.arange(0,6); ar
Out[245]: array([0, 1, 2, 3, 4, 5])

In [246]: ar2=np.arange(0,8); ar2
Out[246]: array([0, 1, 2, 3, 4, 5, 6, 7])

In [247]: ar*ar2
 ---------------------------------------------------------------------------
 ValueError                                Traceback (most recent call last)
 <ipython-input-247-2c3240f67b63> in <module>()
 ----> 1 ar*ar2
 ValueError: operands could not be broadcast together with shapes (6) (8)

此外,NumPy 数组可以如下进行转置:

In [249]: ar=np.array([[1,2,3],[4,5,6]]); ar
Out[249]: array([[1, 2, 3],
 [4, 5, 6]])

In [250]:ar.T
Out[250]:array([[1, 4],
 [2, 5],
 [3, 6]])

In [251]: np.transpose(ar)
Out[251]: array([[1, 4],
 [2, 5],
 [3, 6]])

假设我们希望不按元素比较而是按数组比较数组。 我们可以通过使用np.array_equal运算符实现以下目标:

In [254]: ar=np.arange(0,6)
 ar2=np.array([0,1,2,3,4,5])
 np.array_equal(ar, ar2)
Out[254]: True

在这里,我们看到返回的是布尔值而不是布尔数组。 仅当两个数组中的全部对应元素匹配时,该值才为True。 前面的表达式等效于以下内容:

In [24]: np.all(ar==ar2)
Out[24]: True

归约操作

诸如np.sumnp.prod之类的运算符对数组执行归约运算。 也就是说,它们将多个元素组合为一个值:

In [257]: ar=np.arange(1,5)
 ar.prod()
Out[257]: 24

在多维数组的情况下,我们可以使用axis参数指定是要按行还是按列应用约简运算符:

In [259]: ar=np.array([np.arange(1,6),np.arange(1,6)]);ar
Out[259]: array([[1, 2, 3, 4, 5],
 [1, 2, 3, 4, 5]])
# Columns
In [261]: np.prod(ar,axis=0)
Out[261]: array([ 1,  4,  9, 16, 25])
# Rows
In [262]: np.prod(ar,axis=1)
Out[262]: array([120, 120])

对于多维数组,不指定轴会导致将操作应用于数组的所有元素,如以下示例中所述:

In [268]: ar=np.array([[2,3,4],[5,6,7],[8,9,10]]); ar.sum()
Out[268]: 54

In [269]: ar.mean()
Out[269]: 6.0
In [271]: np.median(ar)
Out[271]: 6.0

统计运算符

这些运算符用于将标准统计运算应用于 NumPy 数组。 名称是不言自明的:np.std()np.mean()np.median()np.cumsum()

In [309]: np.random.seed(10)
 ar=np.random.randint(0,10, size=(4,5));ar
Out[309]: array([[9, 4, 0, 1, 9],
 [0, 1, 8, 9, 0],
 [8, 6, 4, 3, 0],
 [4, 6, 8, 1, 8]])
In [310]: ar.mean()
Out[310]: 4.4500000000000002

In [311]: ar.std()
Out[311]: 3.4274626183227732

In [312]: ar.var(axis=0)  # across rows
Out[312]: array([ 12.6875,   4.1875,  11\.    ,  10.75  ,  18.1875])

In [313]: ar.cumsum()
Out[313]: array([ 9, 13, 13, 14, 23, 23, 24, 32, 41, 41, 49, 55, 
 59, 62, 62, 66, 72, 80, 81, 89])

逻辑运算符

逻辑运算符可用于数组比较/检查。 它们如下:

  • np.all():用于计算所有元素的逐元素 AND
  • np.any():用于计算所有元素的逐元素 OR

生成ints4×4随机数组,并检查是否有任何元素可以被 7 整除,并且所有元素都小于 11:

In [320]: np.random.seed(100)
 ar=np.random.randint(1,10, size=(4,4));ar
Out[320]: array([[9, 9, 4, 8],
 [8, 1, 5, 3],
 [6, 3, 3, 3],
 [2, 1, 9, 5]])

In [318]: np.any((ar%7)==0)
Out[318]: False

In [319]: np.all(ar<11)
Out[319]: True

广播

在广播中,我们利用 NumPy 组合形状不完全相同的数组的功能。 这是一个例子:

In [357]: ar=np.ones([3,2]); ar
Out[357]: array([[ 1.,  1.],
 [ 1.,  1.],
 [ 1.,  1.]])

In [358]: ar2=np.array([2,3]); ar2
Out[358]: array([2, 3])

In [359]: ar+ar2
Out[359]: array([[ 3.,  4.],
 [ 3.,  4.],
 [ 3.,  4.]])

因此,我们可以看到,通过将ar2添加到ar的每一行中,从而产生广播。 这是另一个示例,显示广播在各个维度上均有效:

In [369]: ar=np.array([[23,24,25]]); ar
Out[369]: array([[23, 24, 25]])
In [368]: ar.T
Out[368]: array([[23],
 [24],
 [25]])
In [370]: ar.T+ar
Out[370]: array([[46, 47, 48],
 [47, 48, 49],
 [48, 49, 50]])

在这里,广播了行和列数组,最后得到了3×3数组。

数组形状处理

数组的形状处理有许多步骤。

展平多维数组

np.ravel()函数允许您按以下方式展平多维数组:

In [385]: ar=np.array([np.arange(1,6), np.arange(10,15)]); ar
Out[385]: array([[ 1,  2,  3,  4,  5],
 [10, 11, 12, 13, 14]])

In [386]: ar.ravel()
Out[386]: array([ 1,  2,  3,  4,  5, 10, 11, 12, 13, 14])

In [387]: ar.T.ravel()
Out[387]: array([ 1, 10,  2, 11,  3, 12,  4, 13,  5, 14])

您还可以使用np.flatten进行相同的操作,除了它在np.ravel返回视图的同时返回副本。

重塑

整形函数可用于更改数组的形状或使其不展平:

In [389]: ar=np.arange(1,16);ar
Out[389]: array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15])
In [390]: ar.reshape(3,5)
Out[390]: array([[ 1,  2,  3,  4,  5],
 [ 6,  7,  8,  9, 10],
 [11, 12, 13, 14, 15]])

np.reshape函数返回数据视图,表示基础数组保持不变。 但是,在特殊情况下,如果不复制数据,则无法更改形状。 有关此的更多详细信息,请参见文档

调整大小

有两个大小调整操作符,numpy.ndarray.resize是用于调整大小的ndarray操作符,numpy.resize是用于返回具有指定形状的新数组的numpy.resize。 在这里,我们说明numpy.ndarray.resize函数:

In [408]: ar=np.arange(5); ar.resize((8,));ar
Out[408]: array([0, 1, 2, 3, 4, 0, 0, 0])

请注意,只有在没有其他引用此数组的情况下,此函数才起作用。 否则,ValueError结果:

In [34]: ar=np.arange(5); 
 ar
Out[34]: array([0, 1, 2, 3, 4])
In [35]: ar2=ar
In [36]: ar.resize((8,));
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-36-394f7795e2d1> in <module>()
----> 1 ar.resize((8,));

ValueError: cannot resize an array that references or is referenced by another array in this way.  Use the resize function 

解决此问题的方法是改用numpy.resize函数:

In [38]: np.resize(ar,(8,))
Out[38]: array([0, 1, 2, 3, 4, 0, 1, 2])

添加大小

np.newaxis函数为数组添加了额外的维度:

In [377]: ar=np.array([14,15,16]); ar.shape
Out[377]: (3,)
In [378]: ar
Out[378]: array([14, 15, 16])
In [379]: ar=ar[:, np.newaxis]; ar.shape
Out[379]: (3, 1)
In [380]: ar
Out[380]: array([[14],
 [15],
 [16]])

数组排序

数组可以以多种方式排序。

  1. 沿轴对数组排序; 首先,让我们沿 y 轴进行讨论:

    In [43]: ar=np.array([[3,2],[10,-1]])
     ar
    Out[43]: array([[ 3,  2],
     [10, -1]])
    In [44]: ar.sort(axis=1)
     ar
    Out[44]: array([[ 2,  3],
     [-1, 10]])
  2. 在这里,我们将解释沿 x 轴的排序:

    In [45]: ar=np.array([[3,2],[10,-1]])
     ar
    Out[45]: array([[ 3,  2],
     [10, -1]])
    In [46]: ar.sort(axis=0)
     ar
    Out[46]: array([[ 3, -1],
     [10,  2]])
  3. 按就地(np.array.sort)和就地(np.sort)函数排序。

  4. 可用于数组排序的其他操作包括:

    • np.min():返回数组中的最小元素
    • np.max():返回数组中的最大元素
    • np.std():返回数组中元素的标准差
    • np.var():它返回数组中元素的方差
    • np.argmin():最小索引
    • np.argmax():最大索引
    • np.all():返回所有元素的按元素 AND
    • np.any():返回所有元素的按元素 OR

Pandas 中的数据结构

Pandas 由 Wed McKinney 于 2008 年创建,原因是他在 R 中处理时间序列数据时遇到挫折。它是在 NumPy 之上构建的,并提供了其中不可用的功能。 它提供了快速,易于理解的数据结构,并有助于填补 Python 与 R 之类的语言之间的空白。

我在此处演示的各种操作的关键参考是官方的 Pandas 数据结构文档

Pandas 有三种主要的数据结构:

  • 序列
  • 数据帧
  • 面板

序列

序列实际上是引擎盖下的一维 NumPy 数组。 它由一个 NumPy 数组和一个标签数组组成。

序列创建

创建序列数据结构的一般构造如下:

import pandas as pd 
ser=pd.Series(data, index=idx)

数据可以是以下之一:

  • ndarray
  • Python 字典
  • 标量值

使用numpy.ndarray

在这种情况下,索引必须与数据长度相同。 如果未指定索引,则将创建以下默认索引[0,... n-1],其中n是数据的长度。 下面的示例创建一个由 0 至 1 之间的七个随机数组成的序列结构; 未指定索引:

In [466]: import numpy as np
 np.random.seed(100)
 ser=pd.Series(np.random.rand(7)); ser
Out[466]:0    0.543405
 1    0.278369
 2    0.424518
 3    0.844776
 4    0.004719
 5    0.121569
 6    0.670749
 dtype: float64

以下示例使用指定的月份名称索引创建一年中前 5 个月的序列结构:

In [481]: import calendar as cal
 monthNames=[cal.month_name[i] for i in np.arange(1,6)]
 months=pd.Series(np.arrange(1,6),index=monthNames);months

Out[481]: January     1
 February    2
 March       3
 April       4
 May         5
 dtype: int64

In [482]: months.index
Out[482]: Index([u'January', u'February', u'March', u'April', u'May'], dtype=object)

使用 Python 字典

如果数据是字典并提供了索引,则将从中构造标签; 否则,字典的键将用作标签。 字典的值用于填充序列结构。

In [486]: currDict={'US' : 'dollar', 'UK' : 'pound', 
 'Germany': 'euro', 'Mexico':'peso',
 'Nigeria':'naira',
 'China':'yuan', 'Japan':'yen'}
 currSeries=pd.Series(currDict); currSeries
Out[486]: China        yuan
 Germany      euro
 Japan         yen
 Mexico       peso
 Nigeria     naira
 UK          pound
 US         dollar
 dtype: object

Pandas 序列结构的索引类型为pandas.core.index.Index,可以将其视为有序多集。

在以下情况下,我们指定一个索引,但是该索引包含一个条目,该条目不是相应的dict中的键。 结果是将将的值分配为NaN,表明它丢失了。 我们将在后面的部分中处理缺失值。

In [488]: stockPrices = {'GOOG':1180.97,'FB':62.57, 
 'TWTR': 64.50, 'AMZN':358.69,
 'AAPL':500.6}
 stockPriceSeries=pd.Series(stockPrices,
 index=['GOOG','FB','YHOO', 
 'TWTR','AMZN','AAPL'],
 name='stockPrices')
 stockPriceSeries
Out[488]: GOOG    1180.97
 FB        62.57
 YHOO        NaN
 TWTR      64.50
 AMZN     358.69
 AAPL     500.60
 Name: stockPrices, dtype: float64

请注意,序列还具有可以如前面的片段中所示设置的name属性。 name属性在将序列对象组合到数据帧结构等任务中很有用。

使用标量值

对于标量数据,必须提供索引。 将为尽可能多的索引值重复该值。 此方法的一种可能用途是提供一种快速而肮脏的初始化方法,并在以后填充序列结构。 让我们看看如何使用标量值创建序列:

In [491]: dogSeries=pd.Series('chihuahua', 
                   index=['breed','countryOfOrigin',
 'name', 'gender'])
 dogSeries
Out[491]: breed              chihuahua
 countryOfOrigin    chihuahua
 name               chihuahua
 gender             chihuahua
 dtype: object

无法提供索引只会导致返回标量值,如下所示:

In [494]: dogSeries=pd.Series('pekingese'); dogSeries
Out[494]: 'pekingese'

In [495]: type(dogSeries)
Out[495]: str

序列操作

序列的行为与上一节中讨论的numpy数组的行为非常相似,其中一个警告是切片等操作也会对索引进行切片。

赋值

可以使用类似于字典的方式使用索引标签设置和访问值:

In [503]: currDict['China']
Out[503]: 'yuan'

In [505]: stockPriceSeries['GOOG']=1200.0
 stockPriceSeries
Out[505]: GOOG    1200.00
 FB        62.57
 YHOO        NaN
 TWTR      64.50
 AMZN     358.69
 AAPL     500.60
 dtype: float64

dict一样,如果尝试检索丢失的标签,则会引发KeyError

In [506]: stockPriceSeries['MSFT']
KeyError: 'MSFT'

通过显式使用get可以避免此错误,如下所示:

In [507]: stockPriceSeries.get('MSFT',np.NaN)
Out[507]: nan

在这种情况下,将默认值np.NaN指定为序列结构中不存在该键时要返回的值。

切片

切片操作的行为与 NumPy 数组相同:

In [498]: stockPriceSeries[:4]
Out[498]: GOOG    1180.97
 FB        62.57
 YHOO        NaN
 TWTR      64.50
 dtype: float64

逻辑切片也如下工作:

In [500]: stockPriceSeries[stockPriceSeries > 100]
Out[500]: GOOG    1180.97
 AMZN     358.69
 AAPL     500.60
 dtype: float64

其他操作

可以应用算术和统计运算,就像使用 NumPy 数组一样:

In [501]: np.mean(stockPriceSeries)
Out[501]: 433.46600000000001
In [502]: np.std(stockPriceSeries)
Out[502]: 410.50223047384287

按元素操作也可以按顺序执行:

In [506]: ser
Out[506]: 0    0.543405
 1    0.278369
 2    0.424518
 3    0.844776
 4    0.004719
 5    0.121569
 6    0.670749
 dtype: float64
In [508]: ser*ser
Out[508]: 0    0.295289
 1    0.077490
 2    0.180215
 3    0.713647
 4    0.000022
 5    0.014779
 6    0.449904
 dtype: float64
In [510]: np.sqrt(ser)
Out[510]: 0    0.737160
 1    0.527607
 2    0.651550
 3    0.919117
 4    0.068694
 5    0.348668
 6    0.818993
 dtype: float64

序列的一个重要功能是根据标签自动对齐数据:

In [514]: ser[1:]
Out[514]: 1    0.278369
 2    0.424518
 3    0.844776
 4    0.004719
 5    0.121569
 6    0.670749
 dtype: float64
In [516]:ser[1:] + ser[:-2]
Out[516]: 0         NaN
 1    0.556739
 2    0.849035
 3    1.689552
 4    0.009438
 5         NaN
 6         NaN
 dtype: float64

因此,我们可以看到,对于不匹配的标签,插入了NaN。 默认行为是为未对齐的序列结构生成索引的并集。 这是可取的,因为信息可以保留而不是丢失。 在本书的下一章中,我们将处理 Pandas 中缺失的值。

数据帧

数据帧是一个二维标签数组。 它的列类型可以是异构的:即具有不同的类型。 它类似于 NumPy 中的结构化数组,并添加了可变性。 它具有以下属性:

  • 从概念上讲类似于数据表或电子表格。
  • 类似于 NumPy ndarray,但不是np.ndarray的子类。
  • 列可以是异构类型:float64intbool等。
  • 数据帧的列是序列结构。
  • 可以将其视为序列结构的字典,在该结构中,对列和行均进行索引,对于行,则表示为“索引”,对于列,则表示为“列”。
  • 它的大小可变:可以插入和删除列。

序列/数据帧中的每个轴都有索引,无论是否默认。 需要索引才能快速查找以及正确对齐和连接 Pandas 中的数据。 轴也可以命名,例如以月的形式表示列的数组 Jan Feb Mar ...Dec。这是索引数据帧的表示形式,其命名列的两端以及字符 V,W, X,Y,Z:

 columns nums strs bools decs 
 index 
 V            11       cat   True   1.4
 W            -6      hat   False  6.9 
 X             25     bat   False  -0.6
 Y               8     mat  True   3.7
 Z             -17    sat    False  18.

数据帧创建

数据帧是 Pandas 中最常用的数据结构。 构造器接受许多不同类型的参数:

  • 一维ndarray,列表,字典或序列结构的字典
  • 2D NumPy 数组
  • 结构化或记录ndarray
  • 序列结构
  • 另一个数据帧结构

行标签索引和列标签可以与数据一起指定。 如果未指定,则将以直观的方式从输入数据生成它们,例如,从dict.的键(对于列标签)或通过在行标签的情况下使用np.range(n)生成, 其中n对应于行数。

使用序列字典

在这里,我们通过使用序列对象的字典来创建数据帧结构。

In [97]:stockSummaries={
'AMZN': pd.Series([346.15,0.59,459,0.52,589.8,158.88], 
 index=['Closing price','EPS',
 'Shares Outstanding(M)',
 'Beta', 'P/E','Market Cap(B)']),
'GOOG': pd.Series([1133.43,36.05,335.83,0.87,31.44,380.64],
 index=['Closing price','EPS','Shares Outstanding(M)',
 'Beta','P/E','Market Cap(B)']),
'FB': pd.Series([61.48,0.59,2450,104.93,150.92], 
 index=['Closing price','EPS','Shares Outstanding(M)',
 'P/E', 'Market Cap(B)']),
'YHOO': pd.Series([34.90,1.27,1010,27.48,0.66,35.36],
 index=['Closing price','EPS','Shares Outstanding(M)',
 'P/E','Beta', 'Market Cap(B)']),
'TWTR':pd.Series([65.25,-0.3,555.2,36.23],
 index=['Closing price','EPS','Shares Outstanding(M)',
 'Market Cap(B)']), 
'AAPL':pd.Series([501.53,40.32,892.45,12.44,447.59,0.84],
 index=['Closing price','EPS','Shares Outstanding(M)','P/E',
 'Market Cap(B)','Beta'])}

In [99]: stockDF=pd.DataFrame(stockSummaries); stockDF
Out[99]:
  AAPL AMZN FB GOOG TWTR YHOO
Beta 0.84 0.52 NaN 0.87 NaN 0.66
Closing Price 501.53 346.15 61.48 1133.43 65.25 34.9
EPS 40.32 0.59 0.59 36.05 -0.3 1.27
Market Cap(B) 447.59 158.88 150.92 380.64 36.23 35.36
P/E 12.44 589.8 104.93 31.44 NaN 27.48
Shares Outstanding(M) 892.45 459 2450 335.83 555.2 1010
In [100]:stockDF=pd.DataFrame(stockSummaries,
 index=['Closing price','EPS',
 'Shares Outstanding(M)',
 'P/E', 'Market Cap(B)','Beta']);stockDF
Out [100]:
  AAPL AMZN FB GOOG TWTR YHOO
Closing price 501.53 346.15 61.48 1133.43 65.25 34.9
EPS 40.32 0.59 0.59 36.05 -0.3 1.27
Shares Outstanding(M) 892.45 459 2450 NaN 555.2 1010
P/E 12.44 589.8 104.93 31.44 NaN 27.48
Market Cap(B) 447.59 158.88 150.92 380.64 36.23 35.36
Beta 0.84 0.52 NaN 0.87 NaN 0.66
In [102]:stockDF=pd.DataFrame(stockSummaries,
 index=['Closing price','EPS','Shares Outstanding(M)',
 'P/E', 'Market Cap(B)','Beta'],
 columns=['FB','TWTR','SCNW'])
 stockDF
Out [102]:
FB TWTR SCNW
Closing price 61.48 65.25 NaN
EPS 0.59 -0.3 NaN
Shares Outstanding(M) 2450 555.2 NaN
P/E 104.93 NaN NaN
Market Cap(B) 150.92 36.23 NaN
Beta NaN NaN NaN

可以通过indexcolumns属性访问行索引标签和列标签:

In [527]: stockDF.index
Out[527]: Index([u'Closing price', u'EPS',
 u'Shares      Outstanding(M)', 
 u'P/E', u'Market Cap(B)', u'Beta'], dtype=object)
In [528]: stockDF.columns
Out[528]: Index([u'AAPL', u'AMZN', u'FB', u'GOOG', u'TWTR',
 u'YHOO'], dtype=object)

上述数据的来源是 Google 财经,2014 年 2 月 3 日访问。

使用ndarrays/列表字典

在这里,我们从列表的字典中创建一个数据帧结构。 键将成为数据帧结构中的列标签,列表中的数据将成为列值。 注意如何使用np.range(n)生成行标签索引。

In [529]:algos={'search':['DFS','BFS','Binary Search',
 'Linear','ShortestPath (Djikstra)'],
 'sorting': ['Quicksort','Mergesort', 'Heapsort',
 'Bubble Sort', 'Insertion Sort'],
 'machine learning':['RandomForest',
 'K Nearest Neighbor',
 'Logistic Regression',
 'K-Means Clustering',
 'Linear Regression']}
algoDF=pd.DataFrame(algos); algoDF
Out[529]: 
 machine learning  search   sorting
0   RandomForest   DFS   Quicksort
1   K Nearest Neighbor   BFS   Mergesort
2   Logistic Regression   Binary   Search   Heapsort
3   K-Means Clustering	 Linear   Bubble Sort
4   Linear Regression   ShortestPath (Djikstra)   Insertion Sort

In [530]: pd.DataFrame(algos,index=['algo_1','algo_2','algo_3','algo_4',
'algo_5'])
Out[530]: 
 machine learning  search     sorting
algo_1   RandomForest        DFS     Quicksort
algo_2   K Nearest Neighbor  BFS     Mergesort
algo_3   Logistic Regression  Binary Search Heapsort
algo_4   K-Means Clustering  Linear     Bubble Sort
algo_5   Linear Regression  ShortestPath (Djikstra) Insertion Sort

使用结构化数组

在这种情况下,我们使用结构化数组,即记录或structs的数组。 有关结构化数组的更多信息,请参考这个内容

In [533]: memberData = np.zeros((4,), 
 dtype=[('Name','a15'),
 ('Age','i4'),
 ('Weight','f4')])
 memberData[:] = [('Sanjeev',37,162.4),
 ('Yingluck',45,137.8),
 ('Emeka',28,153.2),
 ('Amy',67,101.3)]
 memberDF=pd.DataFrame(memberData);memberDF
Out[533]:         Name       Age    Weight
 0   Sanjeev    37  162.4
 1   Yingluck   45  137.8
 2   Emeka        28  153.2
 3   Amy        67  101.3
In [534]: pd.DataFrame(memberData, index=['a','b','c','d'])
Out[534]:    Name       Age    Weight
 a   Sanjeev    37  162.4
 b   Yingluck   45  137.8
 c   Emeka        28  153.2
 d   Amy        67  101.3

使用序列结构

在这里,我们展示如何从序列结构构造一个数据帧结构:

In [ 540]: currSeries.name='currency'
 pd.DataFrame(currSeries)
Out[540]:        currency
 China   yuan
 Germany euro
 Japan   yen
 Mexico   peso
 Nigeria naira
 UK   pound
 US   dollar

还有一些数据帧的替代构造器。 它们可以总结如下:

  • DataFrame.from_dict:它使用字典或序列的字典并返回数据帧。
  • DataFrame.from_records:需要一个元组或结构化ndarray的列表。
  • DataFrame.from_items:需要一些(键,值)对。 键是列或索引名,值是列或行值。 如果希望键为行索引名,则必须指定orient ='index'作为参数并指定列名。
  • pandas.io.parsers.read_csv:这是一个辅助函数,可将 CSV 文件读取到 Pandas 数据帧结构中。
  • pandas.io.parsers.read_table:这是一个辅助函数,它将定界文件读入 Pandas 数据帧结构。
  • pandas.io.parsers.read_fwf:这是一个辅助函数,它将固定宽度的线表读入 Pandas 数据帧结构。

操作

在这里,我将简要描述各种数据帧操作。

选取

特定的列可以作为序列结构获得:

In [543]: memberDF['Name']
Out[543]: 0    Sanjeev
 1    Yingluck
 2    Emeka
 3    Amy
 Name: Name, dtype: object

赋值

可以通过分配添加新列,如下所示:

In [545]:   memberDF['Height']=60;memberDF
Out[545]:          Name        Age  Weight  Height
 0                Sanjeev     37   162.4   60
 1                Yingluck    45   137.8   60
 2                Emeka       28   153.2   60
 3                Amy         67   101.3   60

删除

可以删除列,就像使用dict一样:

In [546]: del memberDF['Height']; memberDF
Out[546]:         Name       Age  Weight
 0               Sanjeev    37   162.4
 1               Yingluck   45   137.8
 2               Emeka      28   153.2
 3

Amy        67   101.3

也可以像字典一样弹出它:

In [547]: memberDF['BloodType']='O'
 bloodType=memberDF.pop('BloodType'); bloodType
Out[547]: 0    O
 1    O
 2    O
 3    O
 Name: BloodType, dtype: object

基本上,可以将数据帧结构看作是序列对象的字典。 列在末尾插入; 要在特定位置插入列,可以使用insert函数:

In [552]: memberDF.insert(2,'isSenior',memberDF['Age']>60);
 memberDF
Out[552]:      Name      Age  isSenior  Weight
 0            Sanjeev   37   False      162.4
 1            Yingluck  45   False     137.8
 2            Emeka     28   False     153.2
 3            Amy       67   True      101.3

对齐

数据帧对象以与序列对象相似的方式对齐,只不过它们在列和索引标签上都对齐。 结果对象是列标签和行标签的并集:

In [559]: ore1DF=pd.DataFrame(np.array([[20,35,25,20],
 [11,28,32,29]]),
 columns=['iron','magnesium',
 'copper','silver'])
 ore2DF=pd.DataFrame(np.array([[14,34,26,26],
 [33,19,25,23]]),
 columns=['iron','magnesium',
 'gold','silver'])
 ore1DF+ore2DF
Out[559]:     copper  gold  iron  magnesium  silver
 0           NaN     NaN   34    69         46
 1           NaN     NaN   44    47         52

在没有共同的行标签或列标签的情况下,该值用NaN填充,例如,铜和金。 如果将数据帧对象和序列对象组合在一起,则默认行为是在各行之间广播序列对象:

In [562]: ore1DF + pd.Series([25,25,25,25],
 index=['iron','magnesium',
 'copper','silver'])
Out[562]:    iron  magnesium   copper   silver
 0          45    60          50       45
 1          36    53          57       54

其他数学运算

可以将数学运算符明智地应用于数据帧结构:

In [565]: np.sqrt(ore1DF)
Out[565]:        iron       magnesium   copper         silver
 0              4.472136   5.916080    5.000000       4.472136
 1              3.316625   5.291503    5.656854       5.385165

面板

面板是 3D 数组。 它不如序列或数据帧广泛使用。 由于其 3D 性质,它不像其他两个屏幕那样容易在屏幕上显示或可视化。面板数据结构是 Pandas 中数据结构拼图的最后一部分。 它使用较少,用于 3D 数据。 三个轴名称如下:

  • item:这是轴 0。每个项目均对应一个数据帧结构。
  • major_axis:这是轴 1。每个项目对应于数据帧结构的行。
  • minor_axis:这是轴 2。每个项目对应于每个数据帧结构的列。

至于序列和数据帧,有创建面板对象的不同方法。 它们将在后面的章节中进行解释。

将 3D NumPy 数组与轴标签一起使用

在这里,我们展示了如何从 3D NumPy 数组构造面板对象。

In 586[]: stockData=np.array([[[63.03,61.48,75],
 [62.05,62.75,46],
 [62.74,62.19,53]],
 [[411.90, 404.38, 2.9],
 [405.45, 405.91, 2.6],
 [403.15, 404.42, 2.4]]])
 stockData
Out[586]: array([[[  63.03,   61.48,   75\.  ],
 [  62.05,   62.75,   46\.  ],
 [  62.74,   62.19,   53\.  ]],
 [[ 411.9 ,  404.38,    2.9 ],
 [ 405.45,  405.91,    2.6 ],
 [ 403.15,  404.42,    2.4 ]]])
In [587]: stockHistoricalPrices = pd.Panel(stockData, 
 items=['FB', 'NFLX'],
 major_axis=pd.date_range('2/3/2014', periods=3),
minor_axis=['open price', 'closing price', 'volume'])
 stockHistoricalPrices
Out[587]: <class 'pandas.core.panel.Panel'>
 Dimensions: 2 (items) x 3 (major_axis) x 3 (minor_axis)
 Items axis: FB to NFLX
 Major_axis axis: 2014-02-03 00:00:00 to 2014-02-05 00:00:00
 Minor_axis axis: open price to volume

使用数据帧对象的 Python 字典

我们通过使用数据帧结构的 Python 字典来构造面板结构。

In [591]: USData=pd.DataFrame(np.array([[249.62  , 8900],
 [ 282.16,12680],
 [309.35,14940]]),
 columns=['Population(M)','GDP($B)'], 
 index=[1990,2000,2010])
 USData
Out[591]:       Population(M)   GDP($B)
 1990    249.62          8900
 2000    282.16          12680
 2010    309.35          14940
In [590]: ChinaData=pd.DataFrame(np.array([[1133.68, 390.28],
 [ 1266.83,1198.48],
 [1339.72, 6988.47]]),

 columns=['Population(M)','GDP($B)'],
 index=[1990,2000,2010])
 ChinaData
Out[590]:          Population(M)   GDP($B)
 1990    1133.68         390.28
 2000    1266.83         1198.48
 2010    1339.72         6988.47
In [592]:US_ChinaData={'US' : USData,
 'China': ChinaData}
 pd.Panel(US_ChinaData)
Out[592]: <class 'pandas.core.panel.Panel'>
 Dimensions: 2 (items) x 3 (major_axis) x 2 (minor_axis)
 Items axis: China to US
 Major_axis axis: 1990 to 2010

使用DataFrame.to_panel方法

此方法将具有多重索引的数据帧结构转换为面板结构:

In [617]: mIdx = pd.MultiIndex(levels=[['US', 'China'], 
 [1990,2000, 2010]],
 labels=[[1,1,1,0,0,0],[0,1,2,0,1,2]])
mIdx
Out[617]: MultiIndex
 [(u'China', 1990), (u'China', 2000), (u'China', 2010), 
 (u'US', 1990), (u'US', 2000), (u'US', 2010)]

ChinaUSDF = pd.DataFrame({'Population(M)' : [1133.68, 1266.83, 
 1339.72, 249.62, 
 282.16,309.35], 
 'GDB($B)': [390.28, 1198.48, 6988.47, 
 8900,12680, 14940]}, index=mIdx)
ChinaUSDF
In [618]: ChinaUSDF = pd.DataFrame({'Population(M)' : [1133.68, 
 1266.83, 
 1339.72, 
 249.62, 
 282.16,
 309.35], 
 'GDB($B)': [390.28, 1198.48, 
 6988.47, 8900,
 12680,14940]}, 
 index=mIdx)
 ChinaUSDF

Out[618]:                       GDB($B)       Population(M)
 China       1990     390.28        1133.68
 2000     1198.48       1266.83
 2010     6988.47       1339.72
 US          1990     8900.00        249.62
 2000     12680.00       282.16
 2010     14940.00       309.35
In [622]: ChinaUSDF.to_panel()
Out[622]: <class 'pandas.core.panel.Panel'>
 Dimensions: 2 (items) x 2 (major_axis) x 3 (minor_axis)
 Items axis: GDB($B) to Population(M)
 Major_axis axis: US to China
 Minor_axis axis: 1990 to 2010

美国/中国经济数据的来源是以下站点:

其他操作

插入,删除和逐项操作的行为与数据帧相同。 面板结构可以通过转置重新排列。面板的操作功能集相对欠发达,不如序列和数据帧丰富。

总结

总结本章,numpy.ndarray是 Pandas 数据结构所基于的基岩数据结构。 Pandas 的数据结构由 NumPy ndarray数据和一个或多个标签数组组成。

Pandas 中有三种主要的数据结构:序列,数据帧架和面板。 与 Numpy ndarrays相比,pandas 数据结构更易于使用且更加用户友好,因为在数据帧和面板的情况下,它们提供行索引和列索引。数据帧对象是 Pandas 中最流行和使用最广泛的对象。 在下一章中,我们将讨论 Pandas 索引的主题。