Pandas库

Pandas库是一个专门用于数据分析的开源Python库,有Series(序列)和DataFrame(数据框)这两种数据结构。

9 排序和排位次

另外一种使用索引机制的基础操作是排序(sorting)。对数据进行排序通常为必要操作,因此简化它的实现非常重要。pandas的sort_index()函数返回一个跟原对象元素相同但顺序不同的新对象。

首先看一下Series对象各项的排序方法。要排序的索引只有一列,因此操作很简单。

>>> ser = pd.Series([5,0,3,8,4], index=['red','blue','yellow','white','green'])
>>> ser
red       5
blue      0
yellow    3
white     8
green     4
dtype: int64
>>> ser.sort_index()
blue      0
green     4
red       5
white     8
yellow    3
dtype: int64

输出结果中,各元素按照以字母表顺序升序排列(A~Z)的标签进行排序。这是默认的排序方法,但若指定ascending选项,将其值置为False,则可按照降序排列。

>>> ser.sort_index(ascending=False)
yellow    3
white     8
red       5
green     4
blue      0
dtype: int64

对于DataFrame对象,可分别对两条轴中的任意一条进行排序。如果要根据索引对行进行排序,可依旧使用sort_index()函数,不用指定参数,前面已经讲过;如果要按列进行排序,则需要指定axis选项,其值为1。

>>> frame = pd.DataFrame(np.arange(16).reshape((4,4)),
...                   index=['red','blue','yellow','white'],
...                   columns=['ball','pen','pencil','paper'])
>>> frame
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
white     12   13      14     15
>>> frame.sort_index()
        ball  pen  pencil  paper
blue       4    5       6      7
red        0    1       2      3
white     12   13      14     15
yellow     8    9      10     11
>>> frame.sort_index(axis=1)
        ball  paper  pen  pencil
red        0      3    1       2
blue       4      7    5       6
yellow     8     11    9      10
white     12     15   13      14

至此已经讲解了根据索引进行排序的方法。但往往还需要对数据结构中的元素进行排序,对于这个问题,Series和DataFrame对象有所不同,要区别对待。

对Series对象排序,使用order()函数。

>>> ser.order()
blue      0
yellow    3
green     4
red       5
white     8
dtype: int64

对DataFrame对象排序,使用前面用过的sort_index()函数,只不过要用by选项指定根据哪一列进行排序。

>>> frame.sort_index(by='pen')
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
white     12   13      14     15

如果要基于两列或更多的列进行排序,则把这些列的名称放到数组中,赋给by选项。

>>> frame.sort_index(by=['pen','pencil'])
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
white     12   13      14     15

排位次操作(ranking)跟排序操作紧密相关,该操作为序列的每个元素安排一个位次(初始值为1,依次加1),位次越靠前,所使用的数值越小。

>>> ser.rank()
red       4
blue      1
yellow    2
white     5
green     3
dtype: float64

还可以把数据在数据结构中的顺序(没有进行排序操作)作为它的位次。只要使用method选项把first赋给它即可。

>>> ser.rank(method='first')
red       4
blue      1
yellow    2
white     5
green     3
dtype: float64

默认位次使用升序。要按照降序排列,就把ascending选项的值置为False。

>>> ser.rank(ascending=False)
red       2
blue      5
yellow    4
white     1
green     3
dtype: float64

10 相关性和协方差

相关性(correlation)和协方差(covariance)是两个重要的统计量,pandas计算这两个量的函数分别是corr()和cov()。这两个量的计算通常涉及两个Series对象。

>>> seq2 = pd.Seri
es([3,4,3,4,5,4,3,2],['2006','2007','2008','2009','2010','2011','2012','2013'])
>>> seq = pd.Seri
es([1,2,3,4,4,3,2,1],['2006','2007','2008','2009','2010','2011','2012','2013'])
>>> seq.corr(seq2)
0.77459666924148329
>>> seq.cov(seq2)
0.8571428571428571

另外一种情况是,计算单个DataFrame对象的相关性和协方差,返回两个新DataFrame对象形式的矩阵。

>>> frame2 = DataFrame([[1,4,3,6],[4,5,6,1],[3,3,1,5],[4,1,6,4]],
...                      index=['red','blue','yellow','white'],
...                      columns=['ball','pen','pencil','paper'])
>>> frame2
        ball  pen  pencil  paper
red        1    4       3      6
blue       4    5       6      1
yellow     3    3       1      5
white      4    1       6      4

>>> frame2.corr()
            ball        pen     pencil      paper
ball    1.000000  -0.276026   0.577350  -0.763763
pen    -0.276026   1.000000  -0.079682  -0.361403
pencil  0.577350  -0.079682   1.000000  -0.692935
paper  -0.763763  -0.361403  -0.692935   1.000000
>>> frame2.cov()
            ball        pen     pencil      paper
ball    2.000000  -0.666667   2.000000  -2.333333
pen    -0.666667   2.916667  -0.333333  -1.333333
pencil  2.000000  -0.333333   6.000000  -3.666667
paper  -2.333333  -1.333333  -3.666667   4.666667

用corrwith()方法可以计算DataFrame对象的列或行与Series对象或其他DataFrame对象元素两两之间的相关性。

>>> serred       0
blue     1
yellow   2
white    3
green    9
dtype: float64
>>> frame2.corrwith(ser)
ball      0.730297
pen      -0.831522
pencil    0.210819
paper    -0.119523
dtype: float64
>>> frame2.corrwith(frame)
ball      0.730297
pen      -0.831522
pencil    0.210819
paper    -0.119523
dtype: float64

11 NaN数据

补上缺失的数值很容易,它们在数据结构中用NaN来表示,以便于识别。在数据分析过程中,有些元素在某个数据结构中没有定义。

pandas意在更好地管理这种可能出现的情况。缺失值的处理方法,这样许多问题就可以避免。比如,pandas库在计算各种描述性统计量时,其实没有考虑NaN值。

11.1 为元素赋NaN值

有时需要为数据结构中的元素赋NaN值,这时用NumPy的np.NaN(或np.nan)即可。

>>> ser = pd.Series([0,1,2,np.NaN,9], index=['red','blue','yellow','white','green'])
>>> ser
red        0
blue       1
yellow     2
white    NaN
green      9
dtype: float64
>>> ser['white'] = None
>>> ser
red        0
blue       1
yellow     2
white    NaN
green      9
dtype: float64

11.2 过滤NaN

数据分析过程中,有几种去除NaN的方法。然而,若要人工逐一删除NaN元素很麻烦,也很不安全,因为无法确保删除了所有的NaN。而dropna()函数可以解决这个问题。

>>> ser.dropna()
red       0
blue      1
yellow    2
green     9
dtype: float64

另外一种方法是,用notnull()函数作为选取元素的条件,实现直接过滤。

>>> ser[ser.notnull()]
red       0
blue      1
yellow    2
green     9
dtype: float64

DataFrame处理起来要稍微复杂点。如果对这类对象使用dropna()方法,只要行或列有一个NaN元素,该行或列的全部元素都会被删除。

>>> frame3 = pd.DataFrame([[6,np.nan,6],[np.nan,np.nan,np.nan],[2,np.nan,5]],
...                        index = ['blue','green','red'],
...                        columns = ['ball','mug','pen'])

>>> frame3
       ball  mug  pen
blue      6  NaN    6
green   NaN  NaN  NaN
red       2  NaN    5
>>> frame3.dropna()
Empty DataFrame
Columns: [ball, mug, pen]
Index: []

因此,为了避免删除整行或整列,需使用how选项,指定其值为all,告知dropna()函数只删除所有元素均为NaN的行或列。

>>> frame3.dropna(how='all')
      ball  mug  pen
blue     6 NaN     6
red      2 NaN     5

11.3 为NaN元素填充其他值

删除NaN元素,可能会删除跟数据分析相关的其他数据,所以与其冒着风险去过滤NaN元素,不如用其他数值替代NaN。fillna()函数能够满足大多数需要。这个函数以替换NaN的元素作为参数。所有NaN可以替换为同一个元素,如下所示:

>>> frame3.fillna(0)
       ball  mug  pen
blue      6    0    6
green     0    0    0
red       2    0    5

或者,若要将不同列的NaN替换为不同的元素,依次指定列名称及要替换成的元素即可。

>>> frame3.fillna({'ball':1,'mug':0,'pen':99})
       ball  mug  pen
blue      6    0    6
green     1    0   99
red       2    0    5

12 等级索引和分级

等级索引(hierarchical indexing)是pandas的一个重要功能,单条轴可以有多级索引。可以像操作两维结构那样处理多维数据。

举个简单的例子:创建包含两列索引的Series对象,也就是说,创建一个包含两层的数据结构。

>>> mser = pd.Series(np.random.rand(8),
...        index=[['white','white','white','blue','blue','red','red','red'],
...        ['up','down','right','up','down','up','down','left']])
>>> mser
white  up       0.461689
       down     0.643121
       right    0.956163
blue   up       0.728021
       down     0.813079
red    up       0.536433
       down     0.606161
       left     0.996686
dtype: float64

>>> mser.index
MultiIndex(levels=[[u'blue', u'red', u'white'], [u'down', u'left', u'right', u'up']],
           labels=[[2, 2, 2, 0, 0, 1, 1, 1], [3, 0, 2, 3, 0, 3, 0, 1]])

通过指定等级索引,二级元素的选取操作得以简化。

可以选取第一列索引中某一索引项的元素,使用最经典的做法即可:

>>> mser['white']
up       0.461689
down     0.643121
right    0.956163
dtype: float64

或者像下面这样,选取第二列索引中某一索引项的元素:

>>> mser[:,'up']
white    0.461689
blue     0.728021
red      0.536433
dtype: float64

若要选取某一特定的元素,指定两个索引即可

>>> mser['white','up']
0.46168915430531676

等级索引在调整数据形状和进行基于组的操作(比如创建数据透视表)方面起着非常重要的作用。可以使用unstack()函数调整DataFrame中的数据。这个函数把使用的等级索引Series对象转换为一个简单的DataFrame对象,其中把第二列索引转换为相应的列。

>>> mser.unstack()
           down      left     right        up
blue   0.813079       NaN       NaN  0.728021
red    0.606161  0.996686       NaN  0.536433
white  0.643121       NaN  0.956163  0.461689

如果想进行逆操作,把DataFrame对象转换为Series对象,可使用stack()函数。

>>> frame
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
white     12   13      14     15
>>> frame.stack()
red     ball       0
        pen        1
        pencil     2
        paper      3
blue    ball       4
        pen        5
        pencil     6
        paper      7
yellow  ball       8
        pen        9
        pencil    10
        paper     11
white   ball      12
        pen       13
        pencil    14
        paper     15
dtype: int32

对于DataFrame对象,可以为它的行和列都定义等级索引。声明DataFrame对象时,为index选项和columns选项分别指定一个元素为数组的数组。

>>> mframe = pd.DataFrame(np.random.randn(16).reshape(4,4),
...      index=[['white','white','red','red'], ['up','down','up','down']],
...      columns=[['pen','pen','paper','paper'],[1,2,1,2]])
>>> mframe
                 pen               paper
                   1         2         1         2
white up   -1.964055  1.312100 -0.914750 -0.941930
      down -1.886825  1.700858 -1.060846 -0.197669
red   up   -1.561761  1.225509 -0.244772  0.345843
      down  2.668155  0.528971 -1.633708  0.921735

12.1 重新调整顺序和为层级排序

有时,需要调整某一条轴上各层级的顺序或者调整某一层中各元素的顺序。
swaplevel()函数以要互换位置的两个层级的名称为参数,返回交换位置后的一个新对象,其中各元素的顺序保持不变。

>>> mframe.columns.names = ['objects','id']
>>> mframe.index.names = ['colors','status']
>>> mframe
objects             pen               paper
id                    1         2         1        2
colors status
white  up     -1.964055  1.312100 -0.914750 -0.941930
       down   -1.886825  1.700858 -1.060846 -0.197669
red    up     -1.561761  1.225509 -0.244772  0.345843
       down    2.668155  0.528971 -1.633708  0.921735

>>> mframe.swaplevel('colors','status')
objects             pen               paper
id                    1         2         1         2
status colors
up     white  -1.964055  1.312100 -0.914750 -0.941930
down   white  -1.886825  1.700858 -1.060846 -0.197669
up     red    -1.561761  1.225509 -0.244772  0.345843
down   red     2.668155  0.528971 -1.633708  0.921735

而sortlevel()函数只根据一个层级对数据排序。

>>> mframe.sortlevel('colors')
objects             pen              paper
id                    1        2         1         2
colors status
red    down   2.668155  0.528971 -1.633708  0.921735
       up    -1.561761  1.225509 -0.244772  0.345843
white  down  -1.886825  1.700858 -1.060846 -0.197669
       up    -1.964055  1.312100 -0.914750 -0.941930

12.2 按层级统计数据

DataFrame或Series对象的很多描述性和概括统计量都有level选项,可用它指定要获取哪个层级的描述性和概括统计量。

想对行一层级进行统计,把层级的名称赋给level选项即可。

>>> mframe.sum(level='colors')
objects       pen                paper
id              1         2          1         2
colors
red      1.106394  1.754480  -1.878480  1.267578
white   -3.850881  3.012959  -1.975596 -1.139599

若想对某一层级的列进行统计,例如id,则需要把axis选项的值设置为1,把第二条轴作为参数。

>>> mframe.sum(level='id', axis=1)
id                    1         2
colors status
white  up     -2.878806  0.370170
       down   -2.947672  1.503189
red    up     -1.806532  1.571352
       down    1.034447  1.450706