利用python进行数据分析之pandas入门(一)

字数 7907阅读 1878

目录:

5.1 pandas 的数据结构介绍

5.1.1 Series

5.1.2 DataFrame

5.1.3索引对象

5.2基本功能

5.2.1重新索引

5.2.2丢弃指定轴上的项

5.2.3索引、选取和过滤

5.2.4算术运算和数据对齐

5.2.4.1在算术方法中填充值

5.2.4.2 DataFrame和Series之间的运算

5.2.5函数应用和映射

5.2.6排序和排名

5.2.7带有重复的轴索引

5.3汇总和计算描述性统计

5.3.1相关系数和协方差

5.3.2唯一值、值计数以及成员资格

5.4处理缺失数据

5.4.1滤除缺失数据

5.4.2填充缺失数据

5.5层次化索引

5.5.1重排分级顺序

5.5.2根据级别汇总统计

5.5.3使用DataFrame的列

5.6其他有关pandas的话题

5.6.1整数索引

第5章 pandas入门

pandas 引入约定

In [1]: from pandas import Series,DataFrame

In [2]: import pandas as pd

5.1 pandas 的数据结构介绍

要使用pandas,首先要熟悉他的两个主要的数据结构:Series和DataFrame。

5.1.1 Series

Series 是一种类似于一维数组的对象,由一组数据(各种numpy数据类型)以及一组与之相关的数据标签(即索引)组成。

仅由一组数据即可产生最简单的Series:

In [3]: obj=Series([4,7,-5,3])

In [4]: obj

Out[4]:

0    4

1    7

2  -5

3    3

dtype: int64

serice 的字符串表现形式为:索引在左边,值在右边。

由于我们没有为数据指定索引,于是会自动创建一个0到N-1(N位数据的长度)的整数的索引。

可以通过series的values和index属性获取其数组表现形式和索引对象。

In [6]: obj.values #表现形式

Out[6]: array([ 4,  7, -5,  3], dtype=int64)

In [7]: obj.index #索引对象

Out[7]: RangeIndex(start=0, stop=4, step=1)

通常我们希望所创建的Series带有一个可以对各个数据点进行标记的索引:

In [11]: obj2['a']

Out[11]: -5

In [12]: obj2['d']=6

In [13]: obj2[['c','a','d']]

Out[13]:

c    3

a  -5

d    6

dtype: int64

NumPy数组运算(若根据布尔型数组进行过滤,标量乘法,应用数学函数等)都会保留索引和值之间的链接:

In [14]: obj2

Out[14]:

d    6

b    7

a  -5

c    3

dtype: int64

In [15]: obj2[obj2>0]

Out[15]:

d    6

b    7

c    3

dtype: int64

In [16]: obj2*2

Out[16]:

d    12

b    14

a  -10

c    6

dtype: int64

In [19]: np.exp(obj2)

Out[19]:

d    403.428793

b    1096.633158

a      0.006738

c      20.085537

dtype: float64

我们也可以将Serice看成一个定长的有序字典,因为它是索引值到数据值的一个映射。可以用在许多原本需要字典参数的函数中:

In [20]: 'b' in obj2

Out[20]: True

In [21]: 'e' in obj2

Out[21]: False

如果数据被存放在一个python字典中,可以直接通过这个字典来创建Series

In [4]: sdata={'Ohio':35000,'Texas':71000,'Oregon':16000,'Utah':5000}

In [5]: obj3=Series(sdata)

In [6]: obj3

Out[6]:

Ohio      35000

Oregon    16000

Texas    71000

Utah      5000

dtype: int64

只传入一个字典,则结果Series中索引就是原字典的键(有序排列)

In [7]: states=['California','Ohio','Oregon','Texas']

In [8]: obj4=Series(sdata,index=states)

In [9]: obj4

Out[9]:

California        NaN    #“California ”的值找不到,结果用NaN来代替。

Ohio          35000.0

Oregon        16000.0

Texas        71000.0

dtype: float64

pandas的isnull和notnull函数可以用于检测缺失数据:

In [10]: pd.isnull(obj4)

Out[10]:

California    True

Ohio          False

Oregon        False

Texas        False

dtype: bool

In [11]: pd.notnull(obj4)

Out[11]:

California    False

Ohio          True

Oregon        True

Texas          True

dtype: bool

Series也有类似的实例方法:

In [12]: obj4.isnull()

Out[12]:

California    True

Ohio          False

Oregon        False

Texas        False

dtype: bool

Series重要的一个功能是:它在算术中会自动对齐不同索引的数据。

In [13]: obj3

Out[13]:

Ohio      35000

Oregon    16000

Texas    71000

Utah      5000

dtype: int64

In [14]: obj4

Out[14]:

California        NaN

Ohio          35000.0

Oregon        16000.0

Texas        71000.0

dtype: float64

In [15]: obj3+obj4

Out[15]:

California        NaN

Ohio          70000.0

Oregon        32000.0

Texas        142000.0

Utah              NaN

dtype: float64

Series对象本身及其索引都有一个name属性,该属性跟pandas其他关键功能关系非常密切:

In [16]: obj4.name='population'

In [17]: obj4.index.name='state'

In [18]: obj4

Out[18]:

state

California        NaN

Ohio          35000.0

Oregon        16000.0

Texas        71000.0

Name: population, dtype: float64

Series 的索引可以通过赋值的方式就地修改:

In [20]: obj=Series([4,7,-5,3])

In [21]: obj.index=['Bob','Steve','Jeff','Ryan']

In [22]: obj

Out[22]:

Bob      4

Steve    7

Jeff    -5

Ryan    3

dtype: int64

5.1.2 DataFrame

DataFrame是一个表格型的数据结构,含有一组有序的列,每列可以是不同的值类型(数值,字符串,布尔值等)

DataFrame既有行索引也有列索引,可以被看做是由Series组成的字典。

跟其他的类似的数据结构相比(如R的data.frame),DataFrame中面向行和列的操作基本是平衡的。

DataFrame中的数据是以一个或多个二维块存放的。

构建DataFrame的办法有很多,最常用的一种是直接传入一个由等长列表或numpy组成的数组组成的字典:

In [5]: from pandas import Series,DataFrame

In [6]: import pandas as pd

In [7]: data={'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],'year':[2000,2001,2002,2001,2002],'pop':[1.5,1.7,3.6,2.4,2.9]}

In [8]: frame=DataFrame(data)

结果DataFrame'会自动加上索引(跟Series一样),且全部列会被有序排列:

In [10]: frame

Out[10]:

pop  state  year

0  1.5    Ohio  2000

1  1.7    Ohio  2001

2  3.6    Ohio  2002

3  2.4  Nevada  2001

4  2.9  Nevada  2002

指定列序列,DataFrame的列就会按照指定顺序进行排列:

In [11]: DataFrame(data,columns=['year','state','pop'])

Out[11]:

year  state  pop

0  2000    Ohio  1.5

1  2001    Ohio  1.7

2  2002    Ohio  3.6

3  2001  Nevada  2.4

4  2002  Nevada  2.9

跟Series一样,如果传入的列在数据中找不到,就会产生NA值:

In [11]:  frame2=DataFrame(data,columns=['year','state','pop','debt']

...: ,index=['one','two','three','four','five'])

In [12]: frame2

Out[12]:

year  state  pop debt

one    2000    Ohio  1.5  NaN

two    2001    Ohio  1.7  NaN

three  2002    Ohio  3.6  NaN

four  2001  Nevada  2.4  NaN

five  2002  Nevada  2.9  NaN

In [26]: frame2.columns

Out[26]: Index([u'years', u'state', u'pop', u'debt'], dtype='object')

通过类似于字典标记的方式或属性的方式,可以将DataFrame的列获取为一个Series:

In [27]: frame2['state']

Out[27]:

one        Ohio

two        Ohio

three      Ohio

four    Nevada

five    Nevada

Name: state, dtype: object

In [18]: frame2.year

Out[18]:

one      2000

two      2001

three    2002

four    2001

five    2002

Name: year, dtype: int64

注意,返回的Series拥有原DataFrame相同的索引,且其name属性也已经被相应的设置好了。

行也可以通过位置或名称的方式来进行获取。

In [19]: frame2.ix['three']

Out[19]:

year    2002

state    Ohio

pop      3.6

debt      NaN

Name: three, dtype: object

列可以通过赋值的方式进行修改。如下,我们可以给空的”debt“列赋值一个标量或一组值。

In [20]: frame2['debt']=16.5

In [21]: frame2

Out[21]:

year  state  pop  debt

one    2000    Ohio  1.5  16.5

two    2001    Ohio  1.7  16.5

three  2002    Ohio  3.6  16.5

four  2001  Nevada  2.4  16.5

five  2002  Nevada  2.9  16.5

In [24]: frame2['debt']=np.arange(5.)

In [25]: frame2

Out[25]:

year  state  pop  debt

one    2000    Ohio  1.5  0.0

two    2001    Ohio  1.7  1.0

three  2002    Ohio  3.6  2.0

four  2001  Nevada  2.4  3.0

five  2002  Nevada  2.9  4.0

将列表或数组赋值给某个列的时候,其长度必须要跟DataFrame的长度向匹配。如果赋值的是一个个Series ,就会精确的匹配DataFrame的索引,所有的空位都将被填上的缺失值。

In [26]: val=Series([-1.2,-1.5,-1.7],index=['two','four','five'])

In [27]: frame2['debt']=val

In [28]: frame2

Out[28]:

year  state  pop  debt

one    2000    Ohio  1.5  NaN

two    2001    Ohio  1.7  -1.2

three  2002    Ohio  3.6  NaN

four  2001  Nevada  2.4  -1.5

five  2002  Nevada  2.9  -1.7

为不存在的列赋值会创建一个新列。关键字del用于删除列:

In [29]: frame2['eastern']=frame2.state=='Ohio'

In [30]: frame2

Out[30]:

year  state  pop  debt eastern

one    2000    Ohio  1.5  NaN    True

two    2001    Ohio  1.7  -1.2    True

three  2002    Ohio  3.6  NaN    True

four  2001  Nevada  2.4  -1.5  False

five  2002  Nevada  2.9  -1.7  False

In [31]: del frame2['eastern']

In [32]: frame2.columns

Out[32]: Index([u'year', u'state', u'pop', u'debt'], dtype='object')

另一种常见的数据形式是嵌套字典(也就是字典的字典):

In [33]: pop={'Nevada':{2001:2.4,2002:2.9},'Ohio':{2000:1.5,2001:1.7,

...: 2002:3.6}}

将它传给DataFrame,就会被解释为:外层字典的键作为列,内层键作为行索引。

In [34]: frame3=DataFrame(pop)

In [35]: frame3

Out[35]:

Nevada  Ohio

2000    NaN  1.5

2001    2.4  1.7

2002    2.9  3.6

也可以对结果进行转置:

In [36]: frame3.T

Out[36]:

2000  2001  2002

Nevada  NaN  2.4  2.9

Ohio    1.5  1.7  3.6

内层字典的键会被合并、排序以及形成最终的索引。若指定了显式索引,则不会这样:

In [37]: DataFrame(pop,index=[2001,2002,2003])

Out[37]:

Nevada  Ohio

2001    2.4  1.7

2002    2.9  3.6

2003    NaN  NaN

由Series组成的字典差不多也是一样的用法:

In [40]: pdata={'Ohio':frame3['Ohio'][:-1],'Nevada':frame3['Nevada'][:2]}

In [41]: DataFrame(pdata)

Out[41]:

Nevada  Ohio

2000    NaN  1.5

2001    2.4  1.7

如果设置了Data.Frame的index属性和columns的name属性,

In [42]: frame3.index.name='year';frame3.columns.name='state'

In [43]: frame3

Out[43]:

state  Nevada  Ohio

year

2000      NaN  1.5

2001      2.4  1.7

2002      2.9  3.6

In [44]: frame3.values

Out[44]:

array([[ nan,  1.5],

[ 2.4,  1.7],

[ 2.9,  3.6]])

In [45]: frame3.values

Out[45]:

array([[ nan,  1.5],

[ 2.4,  1.7],

[ 2.9,  3.6]])

5.1.3索引对象

pandas的索引对象负责管理标签和其他元数据(比如轴名称等)。构建Series或DataFrame时,所用到的任何数组或其他序列的标签都会被转换成一个Index:

In [2]: import numpy as np

In [3]: import pandas as pd

In [5]: from pandas import Series,DataFrame

In [6]: obj=Series(range(3),index=['a','b','c'])

In [7]: index=obj.index

In [8]: index

Out[8]: Index([u'a', u'b', u'c'], dtype='object')

In [9]: index[1:]

Out[9]: Index([u'b', u'c'], dtype='object')

Index对象是不可修改的,因此用户不能对其修改:

In [10]: index[1]='d'

---------------------------------------------------------------------------

TypeError                                Traceback (most recent call last)

in ()

----> 1 index[1]='d'

H:\Anaconda2-4.3.0.1\lib\site-packages\pandas\indexes\base.pyc in __setitem__(self, key, value)

1402

1403    def __setitem__(self, key, value):

-> 1404        raise TypeError("Index does not support mutable operations")

1405

1406    def __getitem__(self, key):

TypeError: Index does not support mutable operations

不可修改性非常重要,因为这样才能使得index对象在多个数据结构之间安全共享:

In [12]: index=pd.Index(np.arange(3))

In [13]: obj2=Series([1.5,-2.5,0],index=index)

In [14]: obj2=Series([1.5,-2.5,0],index=index)

In [16]: obj2.index is index

Out[16]: True

除了长得像数组,index的功能也类似一个固定大小的集合:

In [43]: frame3

Out[43]:

state  Nevada  Ohio

year

2000      NaN  1.5

2001      2.4  1.7

2002      2.9  3.6

In [46]: 'Ohio' in frame3.columns

Out[46]: True

In [47]: 2003 in frame3.index

Out[47]: False

5.2基本功能

介绍操作Series和DataFrame中的数据的基本手段。

5.2.1重新索引

pandas对象的一个重要的方法就是reindex,作用是创建一个适应新索引的新对象。

In [33]:  import pandas as pd

from pandas import Series,DataFrame

In [34]: obj=Series([4.5,7.2,-5.3,3.6],index=['d','b','a','c'])

In [35]: obj

Out[35]:

d    4.5

b    7.2

a  -5.3

c    3.6

dtype: float64

调用该Series的reindex将会根据新索引进行重排。如果某个索引值当前不存,就引入缺失值:

In [36]: obj2=obj.reindex(['a','b','c','d','e'])

In [37]: obj2

Out[37]:

a  -5.3

b    7.2

c    3.6

d    4.5

e    NaN

dtype: float64

In [38]:  obj.reindex(['a','b','c','d','e'],fill_value=0)

Out[38]:

a  -5.3

b    7.2

c    3.6

d    4.5

e    0.0

dtype: float64

对于时间序列这样的有序数据,重新索引时可能需要做一些插值处理。method选项即可用达到此目的。例如:ffill可以实现向前值填充:

In [39]: obj3=Series(['blue','purple','yellow'],index=[0,2,4])

In [40]: obj3.reindex(range(6),method='ffill')

Out[40]:

0      blue

1      blue

2    purple

3    purple

4    yellow

5    yellow

dtype: object

下表中列出了可用的method选项。

参数 说明

fill或pad 前向填充(或搬运)值

bfill或backfill 后向填充(或搬运)值

对于DataFrame,reindex可以修改(行)索引,列,或两个都修改。如果仅传入一个序列,则会重新索引行:

In [41]: frame=DataFrame(np.arange(9).reshape((3,3)),index=['a','c','d'],columns=['Ohio','Texas','California',])

In [52]: frame

Out[53]:

Ohio  Texas  California

a    0      1          2

c    3      4          5

d    6      7          8

In [54]: frame2=frame.reindex(['a','b','c','d'])

In [55]:frame2

Out[55]:

Ohio  Texas  California

a  0.0    1.0        2.0

b  NaN    NaN        NaN

c  3.0    4.0        5.0

d  6.0    7.0        8.0

使用columns关键字即可以重新索引。

In [56]: states=['Texas','Utah','California']

frame.reindex(columns=states)

Out[57]:

Texas  Utah  California

a      1  NaN          2

c      4  NaN          5

d      7  NaN          8

也可以同时对行和列进行重新索引,而插值则只能按行应用(即轴0):

frame.reindex(index=['a','b','c','d'],method='ffill',columns=states)

Out[58]:

Texas  Utah  California

a      1  NaN          2

b      1  NaN          2

c      4  NaN          5

d      7  NaN          8

利用ix的标签的=索引功能,重新索引任务可以变得简洁:

frame.ix[['a','b','c','d'],states]

Out[59]:

Texas  Utah  California

a    1.0  NaN        2.0

b    NaN  NaN        NaN

c    4.0  NaN        5.0

d    7.0  NaN        8.0

5.2.2丢弃指定轴上的项

丢弃某条轴上的一个或多个项,只要有一个索引数组或列表即可。

由于需要执行一些数据整理和集合逻辑,所以drop方法返回的是一个在指定轴上删除了指定值的新对象:

In [60]: obj=Series(np.arange(5.),index=['a','b','c','d','e'])

In [61]: new_obj=obj.drop('c')

In [62]: new_obj

Out[62]:

a    0.0

b    1.0

d    3.0

e    4.0

dtype: float64

In[63]: obj.drop(['d','c'])

Out[63]:

a    0.0

b    1.0

e    4.0

dtype: float64

对于DataFrame,可以删除任意轴上的索引值:

In [66]: data=DataFrame(np.arange(16).reshape((4,4)),index=['Ohio','Colorado','Utah','New York'],columns=['one','two','three','four'])

In[67]: data.drop(['Colorado','Ohio'])

Out[67]:

one  two  three  four

Utah        8    9    10    11

New York  12  13    14    15

In [68]: data.drop('two',axis=1)

Out[68]:

one  three  four

Ohio        0      2    3

Colorado    4      6    7

Utah        8    10    11

New York  12    14    15

In [69]: data.drop(['two','four'],axis=1)

Out[69]:

one  three

Ohio        0      2

Colorado    4      6

Utah        8    10

New York  12    14

5.2.3索引、选取和过滤

Series索引 (obj[...])的工作方式类似于NumPy数组的索引,只不过Series的索引值不只是整数。例:

In [5]: obj=Series(np.arange(4.),index=['a','b','c','d'])

In [6]: obj['b']

Out[6]: 1.0

In [7]: obj[1]

Out[7]: 1.0

In [8]: obj[2:4]

Out[8]:

c    2.0

d    3.0

dtype: float64

In [10]: obj[['b','a','d']]

Out[10]:

b    1.0

a    0.0

d    3.0

dtype: float64

In [11]: obj[[1,3]]

Out[11]:

b    1.0

d    3.0

dtype: float64

In [12]: obj[obj<2]

Out[12]:

a    0.0

b    1.0

dtype: float64

利用标签的切片运算与普通的python切片运算不同,其末端是包含的(inclusive)

In [19]: obj['b':'c']

Out[19]:

b    1.0

c    2.0

dtype: float64

设置方式如下:

In [20]: obj['b':'c']=5

In [21]: obj

Out[21]:

a    0.0

b    5.0

c    5.0

d    3.0

dtype: float64

如你所见,对DataFrame进行索引其实就是获取一个或多个列:

In [24]: data=DataFrame(np.arange(16).reshape((4,4)),

index=['Ohio','Colorado','Utah','New York'],columns=['one','two','three','four'])

In [25]: data

Out[25]:

one  two  three  four

Ohio        0    1      2    3

Colorado    4    5      6    7

Utah        8    9    10    11

New York  12  13    14    15

In [26]: data['two']

Out[26]:

Ohio        1

Colorado    5

Utah        9

New York    13

Name: two, dtype: int32

In [28]: data[['three','one']]

Out[28]:

three  one

Ohio          2    0

Colorado      6    4

Utah        10    8

New York    14  12

In [30]: data[['three','one']]

Out[30]:

three  one

Ohio          2    0

Colorado      6    4

Utah        10    8

New York    14  12

这种索引方式有几个特殊情况。首先通过切片或布尔数组进行选取行:

In [29]: data[:2]

Out[29]:

one  two  three  four

Ohio        0    1      2    3

Colorado    4    5      6    7

In [31]: data[data['three']>5]

Out[31]:

one  two  three  four

Colorado    4    5      6    7

Utah        8    9    10    11

New York  12  13    14    15

另一种用法使通过布尔型DataFrame进行索引:

In [32]: data<5

Out[32]:

one    two  three  four

Ohio      True  True  True  True

Colorado  True  False  False  False

Utah      False  False  False  False

New York  False  False  False  False

In [33]: data[data<5]=0

In [34]: data

Out[34]:

one  two  three  four

Ohio        0    0      0    0

Colorado    0    5      6    7

Utah        8    9    10    11

New York  12  13    14    15

这段代码使得DataFrame在语法上像ndarray

为了在DataFrame的行上进行标签索引,我们引入专门的索引字段ix。使得你通过numpy式的标记法以及轴标签的从DataFrame中选取行和列的子集。这是重现索引的简单手段:

In [35]: data.ix['Colorado',['two','three']]

Out[35]:

two      5

three    6

Name: Colorado, dtype: int32

In [36]: data.ix[['Colorado','Utah'],[3,0,1]]

Out[36]:

four  one  two

Colorado    7    0    5

Utah        11    8    9

In [37]: data.ix[2]

Out[37]:

one      8

two      9

three    10

four    11

Name: Utah, dtype: int32

In [38]: data.ix[:'Utah','two']

Out[38]:

Ohio        0

Colorado    5

Utah        9

Name: two, dtype: int32

In [39]: data.ix[data.three>5,:3]

Out[39]:

one  two  three

Colorado    0    5      6

Utah        8    9    10

New York  12  13    14

5.2.4算术运算和数据对齐

In [5]: s1=Series([7.3,-2.5,3.4,1.5],index=['a','c','d','e'])

In [6]: s2=Series([-2.1,3.6,-1.5,4,3.1],index=['a','c','e','f','g'])

In [7]: s1

Out[7]:

a 7.3

c -2.5

d 3.4

e 1.5

dtype: float64

In [8]: s2

Out[8]:

a -2.1

c 3.6

e -1.5

f 4.0

g 3.1

dtype: float64

把他们相加:

In [9]: s1+s2

Out[9]:

a 5.2

c 1.1

d NaN

e 0.0

f NaN

g NaN

dtype: float64

自动的数据对其操作在不重叠的索引处引入了NA值。缺失值会在算术运算过程中传播。

对于DataFrame,对齐操作会同时发生在行和列上:

In [6]: df1=DataFrame(np.arange(9.).reshape((3,3)),columns=list('bcd'),index=['Ohio','Texas','Colorado'])

In [7]: df2=DataFrame(np.arange(12.).reshape((4,3)),columns=list('bde'),index=['Utah','Ohio','Texas','Oregon'])

In [8]: df1

Out[8]:

b c d

Ohio 0.0 1.0 2.0

Texas 3.0 4.0 5.0

Colorado 6.0 7.0 8.0

In [9]: df2

Out[9]:

b d e

Utah 0.0 1.0 2.0

Ohio 3.0 4.0 5.0

Texas 6.0 7.0 8.0

Oregon 9.0 10.0 11.0

将他们相加后,会返回一个新的DataFrame,其索引和列为原来的那两个DataFrame的并集:

In [10]: df1+df2

Out[10]:

b c d e

Colorado NaN NaN NaN NaN

Ohio 3.0 NaN 6.0 NaN

Oregon NaN NaN NaN NaN

Texas 9.0 NaN 12.0 NaN

Utah NaN NaN NaN NaN

5.2.4.1在算术方法中填充值

在不同索引的对象进行算术运算时,你可能希望当一个对象中某个轴标签在另一个对象张找不到时填充一个特殊值:

In [20]: df1=DataFrame(np.arange(12.).reshape((3,4)),columns=list('abcd'))

In [21]: df2=DataFrame(np.arange(20.).reshape((4,5)),columns=list('abcde'))

In [22]: df1

Out[22]:

a b c d

0 0.0 1.0 2.0 3.0

1 4.0 5.0 6.0 7.0

2 8.0 9.0 10.0 11.0

In [23]: df2

Out[23]:

a b c d e

0 0.0 1.0 2.0 3.0 4.0

1 5.0 6.0 7.0 8.0 9.0

2 10.0 11.0 12.0 13.0 14.0

3 15.0 16.0 17.0 18.0 19.0

将他们相加时,没有重叠的位置就会产生NA值:

In [24]: df1+df2

Out[24]:

a b c d e

0 0.0 2.0 4.0 6.0 NaN

1 9.0 11.0 13.0 15.0 NaN

2 18.0 20.0 22.0 24.0 NaN

3 NaN NaN NaN NaN NaN

使用df1的add方法,传入df2以及一个fill_value参数:

In [26]: df1.add(df2,fill_value=0)

Out[26]:

a b c d e

0 0.0 2.0 4.0 6.0 4.0

1 9.0 11.0 13.0 15.0 9.0

2 18.0 20.0 22.0 24.0 14.0

3 15.0 16.0 17.0 18.0 19.0

对Series或DataFrame重新索引时,也可以指定一个填充值:

In [28]: df1.reindex(columns=df2.columns,fill_value=0)

Out[28]:

a b c d e

0 0.0 1.0 2.0 3.0 0

1 4.0 5.0 6.0 7.0 0

2 8.0 9.0 10.0 11.0 0

表5-7 灵活的算术方法

方法 说明

add 用于加法(+)的方法

sub 用于减法(-)的方法

div 用于乘法(*)的方法

mul 用于除法(/)的方法

5.2.4.2 DataFrame和Series之间的运算

跟NumPy数组一样,DataFrame和Series的=之间的算术运算也是有明确规定的。

下面来计算一个二维数组与其某行之间的差:

In [29]: arr=np.arange(12.).reshape((3,4))

In [30]: arr

Out[30]:

array([[ 0., 1., 2., 3.],

[ 4., 5., 6., 7.],

[ 8., 9., 10., 11.]])

In [31]: arr[0]

Out[31]: array([ 0., 1., 2., 3.])

In [32]: arr-arr[0]

Out[32]:

array([[ 0., 0., 0., 0.],

[ 4., 4., 4., 4.],

[ 8., 8., 8., 8.]])

上面的运算就叫做,广播。

DataFrame和Series之间的运算差不多也是如此:

In [33]: frame=DataFrame(np.arange(12.).reshape((4,3)),columns=list('bde'),index=['Utah','Ohio','Texas','Oregon'])

In [34]: series=frame.ix[0]

In [35]: frame

Out[35]:

b d e

Utah 0.0 1.0 2.0

Ohio 3.0 4.0 5.0

Texas 6.0 7.0 8.0

Oregon 9.0 10.0 11.0

In [36]: series

Out[36]:

b 0.0

d 1.0

e 2.0

Name: Utah, dtype: float64

默认情况下,DataFrame和Series之间的算术运算符将Series的索引匹配到DataFrame的列,然后沿着行一直向下广播:

In [37]: frame - series

Out[37]:

b d e

Utah 0.0 0.0 0.0

Ohio 3.0 3.0 3.0

Texas 6.0 6.0 6.0

Oregon 9.0 9.0 9.0

如果某个索引值在DataFrame的列或Series的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集:

In [38]: series2=Series(range(3),index=['b','e','f'])

In [39]: frame+series2

Out[39]:

b d e f

Utah 0.0 NaN 3.0 NaN

Ohio 3.0 NaN 6.0 NaN

Texas 6.0 NaN 9.0 NaN

Oregon 9.0 NaN 12.0 NaN

如果你希望匹配行且在列上广播,则必须使用算术运算方法:

In [40]: series3=frame['d']

In [41]: frame

Out[41]:

b d e

Utah 0.0 1.0 2.0

Ohio 3.0 4.0 5.0

Texas 6.0 7.0 8.0

Oregon 9.0 10.0 11.0

In [42]: series3

Out[42]:

Utah 1.0

Ohio 4.0

Texas 7.0

Oregon 10.0

Name: d, dtype: float64

In [43]: frame.sub(series3,axis=0)

Out[43]:

b d e

Utah -1.0 0.0 1.0

Ohio -1.0 0.0 1.0

Texas -1.0 0.0 1.0

Oregon -1.0 0.0 1.0

传入的轴号就是希望匹配的轴。

5.2.5函数应用和映射

Numpy的ufuncs(元素级数组方法)也可以用于操作pandas对象:

In [44]: frame=DataFrame(np.random.randn(4,3),columns=list('bde'),index=['Utah','Ohio','Texas','Oregon'])

In [45]: frame

Out[45]:

b d e

Utah -0.172344 1.823441 -0.067380

Ohio -0.338604 -0.189082 -0.145676

Texas 1.310289 -0.518146 -0.231740

Oregon -1.880954 -0.400772 0.228320

In [46]: np.abs(frame)

Out[46]:

b d e

Utah 0.172344 1.823441 0.067380

Ohio 0.338604 0.189082 0.145676

Texas 1.310289 0.518146 0.231740

Oregon 1.880954 0.400772 0.228320

另一个常见的操作,将函数应用到由各列或行所形成的一维数组上。DataFrame的apply方法即可实现此功能:

In [47]: f=lambda x:x.max() - x.min()

In [48]: frame.apply(f)

Out[48]:

b 3.191243

d 2.341587

e 0.460059

dtype: float64

In [49]: frame.apply(f,axis=1)

Out[49]:

Utah 1.995785

Ohio 0.192928

Texas 1.828435

Oregon 2.109274

dtype: float64

除标量外,传递给apply的函数还可以返回由多个值组成的Series:

In [52]: def f(x):

...: return Series([x.min(),x.max()],index=['min','max'])

...:

In [53]: frame.apply(f)

Out[53]:

b d e

min -1.880954 -0.518146 -0.23174

max 1.310289 1.823441 0.22832

此外,元素级的python函数也是可以用的。

假如想得到frame中各个浮点数的格式化字符串,使用applymap即可:

In [54]: format=lambda x:'%.2f' %x

In [55]: frame.applymap(format)

Out[55]:

b d e

Utah -0.17 1.82 -0.07

Ohio -0.34 -0.19 -0.15

Texas 1.31 -0.52 -0.23

Oregon -1.88 -0.40 0.23

之所以叫做applymap,是因为Series有一个用于应用元素级函数的map的方法:

In [56]: frame['e'].map(format)

Out[56]:

Utah -0.07

Ohio -0.15

Texas -0.23

Oregon 0.23

Name: e, dtype: object

5.2.6排序和排名

根据条件对数据集排序也是一种重要的内置运算。要对行或列索引进行排序(按字典顺序),可以使用sort_index方法,它将返回一个已经排序的新对象:

In [57]: obj=Series(range(4),index=['d','a','b','c'])

In [58]: obj.sort_index()

Out[58]:

a 1

b 2

c 3

d 0

dtype: int64

而对于DataFrame,则可以根据任意一个轴上的索引进行排序:

In [59]: frame=DataFrame(np.arange(8).reshape((2,4)),index=['three','one'],columns=['d','a','b','c'])

In [60]: frame.sort_index()

Out[60]:

d a b c

one 4 5 6 7

three 0 1 2 3

In [61]: frame.sort_index(axis=1)

Out[61]:

a b c d

three 1 2 3 0

one 5 6 7 4

数据默认是按升序排列的,但也可以降序排序:

In [64]: frame.sort_index(axis=1,ascending=False)

Out[64]:

d c b a

three 0 3 2 1

one 4 7 6 5

若要按值对Series进行排序,可以使用order方法:

In [65]: obj=Series([4,7,-3,2])

In [66]: obj.order()

Out[66]:

2 -3

3 2

0 4

1 7

dtype: int64

在排序的时候,缺失值默认都会被放在了Series的末尾:

In [67]: obj=Series([4,np.nan,7,np.nan,-3,2])

In [68]: obj.order()

Out[68]:

4 -3.0

5 2.0

0 4.0

2 7.0

1 NaN

3 NaN

dtype: float64

在DataFrame上,你可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给by选项即可达到该目的:

In [69]: frame=DataFrame({'b':[4,7,-3,2],'a':[0,1,0,1]})

In [70]: frame

Out[70]:

a b

0 0 4

1 1 7

2 0 -3

3 1 2

In [71]: frame.sort_index(by='b')

Out[71]:

a b

2 0 -3

3 1 2

0 0 4

1 1 7

要根据多个列进行排序,传入名称的列表即可:

In [73]: frame.sort_index(by=['a','b'])

Out[73]:

a b

2 0 -3

0 0 4

3 1 2

1 1 7

排名(ranking)跟排序关系密切,且会增设一个排名值(从1开始,一直到数组中有效数据的数量),跟numpy.argsort产生的间接排序索引差不多,只不过它可以根据某种规则破坏平级关系。

下面介绍Series和DataFrame的rank方法。默认下:rank是通过“为各组分配一个平均排名”的方式来破坏平级关系。

In [75]: obj=Series([7,-5,7,4,2,0,4])

In [76]: obj.rank()

Out[76]:

0 6.5

1 1.0

2 6.5

3 4.5

4 3.0

5 2.0

6 4.5

dtype: float64

也可以根据值在原数据中出现的顺序给出排名:

In [77]: obj.rank(method='first')

Out[77]:

0 6.0

1 1.0

2 7.0

3 4.0

4 3.0

5 2.0

6 5.0

dtype: float64

也可以按降序进行排名:

In [78]: obj.rank(ascending=False,method='max')

Out[78]:

0 2.0

1 7.0

2 2.0

3 4.0

4 5.0

5 6.0

6 4.0

dtype: float64

表5-8 列出了所有用于破坏平级关系的method选项。DataFrame可以在行或列上计算排名:

In [79]: frame=DataFrame({'b':[4.3,7,-3,2],'a':[0,1,0,1],'c':[-2,5,8,-2.5]})

In [80]: frame

Out[80]:

a b c

0 0 4.3 -2.0

1 1 7.0 5.0

2 0 -3.0 8.0

3 1 2.0 -2.5

In [81]: frame.rank(axis=1)

Out[81]:

a b c

0 2.0 3.0 1.0

1 1.0 3.0 2.0

2 2.0 1.0 3.0

3 2.0 3.0 1.0

表5-8 :排名时用于破坏平级关系的method选项

method 说明

‘average’ 默认:在相等分组中,为各个值分配平均排‘’

‘min’ 使用整个分组的最小排名

‘max’ 使用整个分组的最大排名

‘first’ 按值在原始数据中的出现顺序分配排名

5.2.7带有重复的轴索引

我们看看下面这个简单的带有重复索引值的Series:

In [82]: obj=Series(range(5),index=['a','a','b','b','c'])

In [83]: obj

Out[83]:

a 0

a 1

b 2

b 3

c 4

dtype: int64

索引的is_unique属性可以告诉你他的值是否是唯一的:

In [84]: obj.index.is_unique

Out[84]: False

对于重复的索引,数据选取的行为将会有些不同。如果某个索引对应的多个值,则返回一个Series,而对应单个值,则返回一个标量:

In [85]: obj['a']

Out[85]:

a 0

a 1

dtype: int64

In [86]: obj['c']

Out[86]: 4

对DataFrame的行进行索引时候也是如此:

In [87]: df=DataFrame(np.random.randn(4,3),index=['a','a','b','b'])

In [88]: df

Out[88]:

0 1 2

a 0.056598 1.592208 -0.576368

a 0.842511 -0.085418 0.818032

b 1.347421 -0.239196 -0.543597

b -0.598395 0.966395 0.285722

In [89]: df.ix['b']

Out[89]:

0 1 2

b 1.347421 -0.239196 -0.543597

b -0.598395 0.966395 0.285722

推荐阅读更多精彩内容