Martin
Pandas入门上 pandas数据结构介绍基本功能算数运算和数据对齐要使用pandas首先得熟悉它的两个数据结构:Series和DataFrame。
SeriesSeries是一种类似于一维数组的对象,它由一组数据(各种Numpy数据类型)以及一组与之相关的数据标签(即标签)组成。仅由一组数据即可产生最简单的Series:
>>> obj = Series([4,7,-5,3]) >>> obj 0 4 1 7 2 -5 3 3 dtype: int64Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引,于是会自动创建一个0到N-1(N为数据长度)的整数型索引。你可以通过Series的values和index属性获取其数组形式和索引对象:
>>> obj.values array([ 4, 7, -5, 3]) >>> obj.index RangeIndex(start=0, stop=4, step=1) # 开始索引下标为0,结束为4,步长为1但是一般情况下,我们希望创建一个可以各个数据点进行标记的索引:
>>> obj2 = Series([4,7,-5,3],index=['d','b','a','c']) >>> obj2 d 4 b 7 a -5 c 3 dtype: int64与普通数组相比,你可以通过索引的方式选取Series中的单个或一组值:
>>> obj2['a'] -5 >>> obj2['b'] 7 >>> obj2[['b','a','d']] b 7 a -5 d 4 dtype: int64如果数据被存放在一个python字典中,也可以直接通过这个字典来创建Series,并且如果只传入一个字典,则结果Series中的索引就是原字典的键(有序字典排序)。
>>> sdata = {'Ohio':35000,'Texas':71000,'Oregon':16000,'Utah':5000} >>> obj3 = Series(sdata) >>> obj3 Ohio 35000 Oregon 16000 Texas 71000 Utah 5000 dtype: int64再来下面这个例子:
>>> sdata = {'Ohio':35000,'Texas':71000,'Oregon':16000,'Utah':5000} >>> states = ['California','Ohio','Oregon','Texas'] >>> obj4 = Series(sdata,index=states) >>> obj4 California NaN Ohio 35000.0 Oregon 16000.0 Texas 71000.0 dtype: float64在这个例子中,sdata中跟states索引相匹配的那3个值会被找出来并放到相应位置上,但由于California所对应的sdata值找不到,所以结果就是NaN(即“非数字”not a number),在pandas中它用于表示缺失或NA值,以后将会使用NA表示数据缺失。pandas的isnull和notnull函数可用于检测缺失数据:
>>> pd.isnull(obj4) # 顶层函数调用 California True Ohio False Oregon False Texas False dtype: bool >>> obj4.isnull() # 实例方法调用 California True Ohio False Oregon False Texas False dtype: bool >>> pd.notnull(obj4) California False Ohio True Oregon True Texas True dtype: boolSeries最重要的一个功能就是:在算数运算中能自动对齐不同索引的数据。
>>> obj3 Ohio 35000 Oregon 16000 Texas 71000 Utah 5000 dtype: int64 >>> obj4 California NaN Ohio 35000.0 Oregon 16000.0 Texas 71000.0 dtype: float64 >>> obj3+obj4 California NaN # obj3中没有此项,自动变为NA值 Ohio 70000.0 Oregon 32000.0 # 自动对齐数据并运算 Texas 142000.0 Utah NaN # obj4中没有此项,自动变为NA值 dtype: float64Series对象本身及其索引都有一个name属性,该属性跟pandas其他的关键功能关系非常密切:
>>> obj4.name = 'population' >>> obj4.index.name = 'state' >>> obj4 state California NaN Ohio 35000.0 Oregon 16000.0 Texas 71000.0 Name: population, dtype: float64Series的索引可以通过赋值的方式就地修改:
>>> obj.index = ['Bob','Steve','Jeff','Ryan'] >>> obj Bob 4 Steve 7 Jeff -5 Ryan 3 dtype: int64 DataFrameDataFrame是一个表格型的数据结构。它含有一组有序的的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame既有行索引也有列索引,它可以被看成是有Series组成的字典(共用一个索引)。
构建DataFrame的办法有很多,常用的有两种方式:
一种是直接传入一个由等长列表或Numpy数组构成的字典另一种是嵌套字典(也就是字典的字典)下面来看一下第一种常用方式:
>>> data = {'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],'year':[2000,2001,2002,2001,2002],'pop':[1.5,1.7,3.6,2.4,2.9]} >>> frame = DataFrame(data) >>> frame 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结果会自动加上索引(跟Series一样),且全部列会被有序排列。
如果指定了列序列,则DataFrame的列就会按照指定顺序进行排列,指定列顺序用参数columns完成:
>>> DataFrame(data,columns=['year','state','pop']) 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值:
>>> frame2 = DataFrame(data,columns=['year','state','pop','debt'],index=['one','two','three','four','five']) >>> frame2 year state pop debt # debt列在data数据中找不到,故标记为NA 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通过类似字典获取value的方式,对DataFrame列也可以使用,返回为一个Series对象:
>>> frame2['year'] # 选取列数据 one 2000 two 2001 three 2002 four 2001 five 2002 Name: year, dtype: int64 >>> frame2.year # 这种方式跟上面的效果一样 one 2000 two 2001 three 2002 four 2001 five 2002 Name: year, dtype: int64注意:返回的Series拥有原DataFrame相同的索引,且其name属性已经被设置好。但是这种获取方式仅适用于列,对于行也就是axis=0来说,就要用相应的特殊方法.ix。
>>> frame2.ix['three'] # 获取`three`行的数据 year 2002 state Ohio pop 3.6 debt NaN Name: three, dtype: object列可以通过赋值方式进行修改,例如,可以给那个空列debt赋值:
>>> frame2['debt'] = 1 >>> frame2 year state pop debt one 2000 Ohio 1.5 1 two 2001 Ohio 1.7 1 three 2002 Ohio 3.6 1 four 2001 Nevada 2.4 1 five 2002 Nevada 2.9 1修改行数据就要采用刚才说的那个特殊方法ix:
>>> frame2.ix['one'] = [1999,'Califorina',1.7,0] >>> frame2 year state pop debt one 1999 Califorina 1.7 0 two 2001 Ohio 1.7 1 three 2002 Ohio 3.6 1 four 2001 Nevada 2.4 1 five 2002 Nevada 2.9 1如果进行某一特定值的修改而不是某整行或某整列时规则跟修改Numpy数组一样,定位行列即可,但是要注意的是DataFrame选取行列定位的顺序是先列后行,与Numpy先行后列不同,一定要注意,如果非要先选行后选列就要用ix。下面来看例子
>>> frame3 = DataFrame(np.arange(15).reshape(5,3),index=['one','two','three','four','five'],columns=['year','state','pop']) >>> frame3 year state pop one 0 1 2 two 3 4 5 three 6 7 8 four 9 10 11 five 12 13 14如果我想要修改某一项具体值,可以这样做:
>>> frame3['year']['one'] = 99 # 记住要先列后行 >>> frame3 year state pop one 99 1 2 two 3 4 5 three 6 7 8 four 9 10 11 five 12 13 14如果没有遵守先列后行的原则的话,则会报错:
>>> frame3['one']['year'] = 99 # 未遵循先列后行 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/martin/anaconda2/lib/python2.7/site-packages/pandas/core/frame.py", line 1997, in __getitem__如一定要先行后列就要采用ix方法:
>>> frame3.ix['one','year'] = 0 >>> frame3 year state pop one 0 1 2 two 3 4 5 three 6 7 8 four 9 10 11 five 12 13 14但是,重点来了:这里给出的frame3里面的数据都是Numpy数组类型,所以这个先列后行的原则是适用的,但是如果DataFrame里面的数据是别的类型,比如字典类型的话就需要特别处理了,下面来看例子:
>>> frame2 year state pop one 1999 Ohio 1.5 two 2001 Ohio 1.7 three 2002 Ohio 3.6 four 2001 Nevada 2.4 five 2002 Nevada 2.9应该还记得,frame2是之前给的例子,它里面的的数据是dict字典类型的,我本来也以为它会和Numpy的数组类型是一样的数据赋值,但是通过测试并查找文档发现,这里面还是有猫腻的,来看例子:
# 为了确保会出现警告提示,可以在试验例子之前加一句这个 >>>pd.set_option('mode.chained_assignment','raise') >>> frame['year']['one'] = 2000 # 继续使用先列后行,但是奇怪的是报了错 Traceback (most recent call last): File "<stdin>", line 1, in <module> ... raise SettingWithCopyError(t) pandas.core.common.SettingWithCopyError: A value is trying to be set on a copy of a slice from a DataFrame后来我查了文档,发现文档中有这样一句话,给大家截了官方文档的图片并附上文档地址: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
发现“This can work at times,but is not guaranteed,and so should be avoided”这句话了吧,然后再看看它下面的例子,是不是也是跟我讲的是一样的运用方式呢。这句话意思是:这么做有时可以生效,但不总能保证有效,所以请避免这样使用它。那么对于dict字典数据的DataFrame我该怎么修改具体的某个值呢?
往上看,就会找到这样一句话“This is the correct access method”,告诉了我们它下面的使用方式是正确的,也就是使用local函数或者ix函数,遵从先行后列原则。所以我们按照官方文档的方式试试我们的例子:
>>> frame2.loc['one','year'] = 2000 # 一定要先行后列 >>> frame2 year state pop one 2000 Ohio 1.5 # 用loc函数将1999改成了2000 two 2001 Ohio 1.7 three 2002 Ohio 3.6 four 2001 Nevada 2.4 five 2002 Nevada 2.9 >>> frame2.ix['one','year'] = 1999 >>> frame2 year state pop one 1999 Ohio 1.5 # 用ix函数将2000又改回1999 two 2001 Ohio 1.7 three 2002 Ohio 3.6 four 2001 Nevada 2.4 five 2002 Nevada 2.9可能看到这大家不由自主的会有一个疑问,为什么DataFrame类型的数据结构对于数据的操作会这样,把行的处理要单独给于一个函数来处理,但对于列的处理就容易的多了,这比Numpy数组难用多了。我有幸看到了设计Pandas作者的一些想法:
在设计pandas时,我觉得得必须输入frame[:,col]才能选取列实在啰嗦(而且还很容易出错),因为列的选取在报表中是一种常用的操作。于是,我就把所有的标签索引功能都放到了ix或者loc中了。
为不存在的列赋值会创建出一个新列。关键字del用于删除列且仅适用于列:
>>> frame2['eastern'] = frame2.state == 'Ohio' >>> frame2 year state pop eastern # eastern本不存在,赋值后自动生成 one 1999 Ohio 1.5 True two 2001 Ohio 1.7 True three 2002 Ohio 3.6 True four 2001 Nevada 2.4 False five 2002 Nevada 2.9 False >>> del frame2['eastern'] >>> frame2 year state pop one 1999 Ohio 1.5 two 2001 Ohio 1.7 three 2002 Ohio 3.6 four 2001 Nevada 2.4 five 2002 Nevada 2.9上面的内容就是构造DataFrame时一个比较常用的构造方式:利用由Numpy数组构成的字典。下面来讲下第二种常用构造方式:嵌套字典(字典的字典)。先给举个栗子 :)
>>> pop = {'Nevada':{2001:2.4,2002:2.9},'Ohio':{2000:1.5,2002:3.6}}如果将pop传入DataFrame,它会被解释为:外层字典的键作为列,内层字典的键作为行索引:
>>> frame3 = DataFrame(pop) >>> frame3 Nevada Ohio 2000 NaN 1.5 2001 2.4 NaN 2002 2.9 3.6内层字典的键会被合并、排序以形成最终的索引。如果显式指定了索引,则不会这样:
>>> DataFrame(pop,index=[2001,2002,2003]) Nevada Ohio 2001 2.4 NaN 2002 2.9 3.6 2003 NaN NaN由Series组成的字典差不多也是一样的用法:(DataFrame每列提取出来都是一个Series类型的数据)
>>> pdata = {'Ohio':frame3['Ohio'][:-1],'Nevada':frame3['Nevada'][:2]} >>> DataFrame(pdata) Nevada Ohio 2000 NaN 1.5 2001 2.4 NaN上面介绍了最常用的构造DataFrame的两种方式,下表给出了可以输入给DataFrame构造器的数据。
类型说明二维ndarray数据矩阵,还可以传入行标和列标由数组、列表或元组组成的字典每个序列会变成DataFrame的一列。所有序列长度必须相同Numpy结构化/记录数组类似于有数组组成的字典有Series组成的字典每个Series会成一列。如果没有显式指定索引则各Series的索引被合并成结果的行索引由字典组成的字典各内层字典会组成一列。键会被合并成结果行索引,跟Series组成的字典情况一样字典或Series的列表各项将会成为DataFrame的一行,字典键或Series索引的并集将会成为DataFrame的列标。由列表或元组组成的列表类似于二维ndarray另一个DataFrame该DataFrame的索引将会被沿用,除非显式指定其他索引如果设置了DataFrame的index和columns的name属性,则这些信息也会被显示出来:
>>> frame3 Nevada Ohio 2000 NaN 1.5 2001 2.4 NaN 2002 2.9 3.6 >>> frame3.index.name = 'year' # 设置索引name属性 >>> frame3.columns.name = 'state' # 设置列name属性 >>> frame3 state Nevada Ohio year 2000 NaN 1.5 2001 2.4 NaN 2002 2.9 3.6跟Series一样,values属性也会以二维ndarray的形式返回DataFrame中的数据:
>>> frame3.values array([[ nan, 1.5], [ 2.4, nan], [ 2.9, 3.6]])这一节中将介绍操作Series和DataFrame中的数据的基本手段。
重新索引pandas对象的一个重要方法是reindex,其作用是创建一个适应新索引的新对象。还是给个例子
>>> obj = Series([4.5,7.2,-5.3,3.6],index=['d','b','a','c']) >>> obj d 4.5 b 7.2 a -5.3 c 3.6 dtype: float64调用该Series的reindex将会根据新索引进行重排。如果某个索引值当前不存在,就引入缺失值:
>>> obj2 = obj.reindex(['a','b','c','d','e']) >>> obj2 a -5.3 b 7.2 c 3.6 d 4.5 e NaN # 引入NA值 dtype: float64 >>> obj2 = obj.reindex(['a','b','c','d','e'],fill_value=0) # 填充缺失值为0 >>> obj2 a -5.3 b 7.2 c 3.6 d 4.5 e 0.0 dtype: float64注意:其实上面的reindx函数可以这样替代:
>>> obj2 = obj[['a','b','c','d']] >>> obj2 a -5.3 b 7.2 c 3.6 d 4.5 dtype: float64但仅仅就局限于Series对象,对于DataFrame对象使用此方法会报错。
对于DataFrame,reindex可以修改(行)索引、列或者两个都修改。如果想重新索引列,必须传入columns关键字,因为默认没有关键字是只重新排列索引的(即axis=0)。
>>> frame2.reindex(['five','four','three','two','one']) year state pop five 2002 Nevada 2.9 four 2001 Nevada 2.4 three 2002 Ohio 3.6 two 2001 Ohio 1.7 one 1999 Ohio 1.5同时修改索引和列必须要传入关键字index和columns:
>>> frame2.reindex(index=['five','four','three','two','one'],columns=['pop','state','year']) pop state year five 2.9 Nevada 2002 four 2.4 Nevada 2001 three 3.6 Ohio 2002 two 1.7 Ohio 2001 one 1.5 Ohio 1999那么替代DataFrame对象的reindex`方法该这么做:
>>> frame2 year state pop one 1999 Ohio 1.5 two 2001 Ohio 1.7 three 2002 Ohio 3.6 four 2001 Nevada 2.4 five 2002 Nevada 2.9 >>> frame_test = DataFrame(frame2,index=['five','four','three','two','one']) >>> frame_test year state pop five 2002 Nevada 2.9 four 2001 Nevada 2.4 three 2002 Ohio 3.6 two 2001 Ohio 1.7 one 1999 Ohio 1.5下表列出了reindex函数的参数:
参数说明index索引关键字method插值填充方式,分为ffill和bfill两种fill_value在重新索引过程中,需要引入缺失值时使用的替代值limit前向或者后向填充时的最大填充量level在MultiIndex的指定级别上的匹配简单索引,否则选取子集copy默认为True,无论如何都复制,如果为False,则新旧相等就不复制 丢弃指定轴上的项丢弃某轴上的一个或者多个项很简单,只要有一个索引数组或列表即可。由于需要执行一些数据整理和集合逻辑,所以drop方法返回的是一个在指定轴上删除了指定值的新对象。
>>> obj = Series(np.arange(5),index=['a','b','c','d','e']) >>> obj a 0 b 1 c 2 d 3 e 4 dtype: int64 >>> new_obj = obj.drop('c') >>> new_obj a 0 b 1 d 3 e 4 dtype: int64对于DataFrame,可以删除任意轴上的索引值:
>>> data = DataFrame(np.arange(16).reshape((4,4)),index=['Ohio','Colorado','Utah','New York'],columns=['one','two','three','four']) >>> data 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 >>> data.drop(['Colorado','Ohio']) one two three four Utah 8 9 10 11 New York 12 13 14 15如果不写axis=1,默认是删除行,如果想删除列,必须加上axis=1。
>>> data.drop('two',axis=1) one three four Ohio 0 2 3 Colorado 4 6 7 Utah 8 10 11 New York 12 14 15 >>> data.drop(['two','four'],axis=1) # 传入的是序列 one three Ohio 0 2 Colorado 4 6 Utah 8 10 New York 12 14 索引、选取和过滤Series索引的工作方式类似于Numpy数组的索引,只不过Series的索引值不只是整数,下面是几个例子:
>>> obj a 0 b 1 c 2 d 3 e 4 dtype: int64 >>> obj['b'] 1 >>> obj[1] 1 >>> obj[2:4] c 2 d 3 dtype: int64 >>> obj[['b','a','d']] b 1 a 0 d 3 dtype: int64利用标签的切片运算与普通的python切片运算不同,期末端是包含的。
>>> obj['b':'c'] b 1 c 2 dtype: int64设置值的方式也很简单:
>>> obj['b':'c'] = 5 >>> obj a 0 b 5 c 5 d 3 e 4 dtype: int64你可能猜到了,对DataFrame进行索引其实就是获取一个或多个列。
>>> data 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 >>> data['two'] Ohio 1 Colorado 5 Utah 9 New York 13 Name: two, dtype: int64 >>> data[['three','one']] three one Ohio 2 0 Colorado 6 4 Utah 10 8 New York 14 12 >>> data['Utah':'New York'] # DataFrame依然可以标签索引,但是对象是行标签 one two three four Utah 8 9 10 11 New York 12 13 14 15为了在DataFrame上能进行行标签索引,引入了ix,但是不能进行标签切片,只能进行普通切片。
>>> data.ix[['Utah','New York'],['one','two']] one two Utah 8 9 New York 12 13 >>> data.ix[1:3,0:2] one two Colorado 4 5 Utah 8 9下表给出DataFrame的索引选项。
类型说明obj[val]选取DataFrame的单个列或一组列。在一些特殊情况下会比较便利:布尔型数组(过滤行)、切片(行切片)、布尔型DataFrameobj.ix[val]选取DataFrame的单个行或一组行obj.ix[:,val]选取单个列或列子集obj.ix[val1,val2]同时选取行和列Pandas最重要的一个功能是,他可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集。看一个例子:
>>> s1 = Series([7.3,-2.5,3.4,1.5],index=['a','c','d','e']) >>> s2 = Series([-2.1,3.6,-1.5,4,3.1],index=['a','c','e','f','g']) >>> s1 a 7.3 c -2.5 d 3.4 e 1.5 dtype: float64 >>> s2 a -2.1 c 3.6 e -1.5 f 4.0 g 3.1 dtype: float64将它们相加就会产生:
>>> s1 + s2 a 5.2 c 1.1 d NaN e 0.0 f NaN g NaN dtype: float64自动的数据对其操作在不重叠的索引处引入了NA值。缺失值会在算数运算过程中传播。
对于DataFrame,对齐操作会同时发生在行和列:
>>> df1 = DataFrame(np.arange(9).reshape((3,3)),columns=list('bcd'),index=['Ohio','Texas','Colorado']) >>> df2 = DataFrame(np.arange(12).reshape((4,3)),columns=list('bde'),index=['Utah','Ohio','Texas','Oregon']) >>> df1 b c d Ohio 0 1 2 Texas 3 4 5 Colorado 6 7 8 >>> df2 b d e Utah 0 1 2 Ohio 3 4 5 Texas 6 7 8 Oregon 9 10 11把他们相加后将会返回一个新的DataFrame,其索引和列为原来那两个DataFrame的并集:
>>> df1 + df2 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 在算数运算中填充值在对不同索引对象进行算数运算是,你可能希望当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值(比如0):
>>> df1 = DataFrame(np.arange(12).reshape((3,4)),columns=list('abcd')) >>> df2 = DataFrame(np.arange(20).reshape((4,5)),columns=list('abcde')) >>> df1 a b c d 0 0 1 2 3 1 4 5 6 7 2 8 9 10 11 >>> df2 a b c d e 0 0 1 2 3 4 1 5 6 7 8 9 2 10 11 12 13 14 3 15 16 17 18 19将它们相加时,没有重叠的位置就会产生NA值:
>>> df1 + df2 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参数:
>>> df1.add(df2,fill_value=0) a b c d e 0 0.0 2.0 4.0 6.0 4.0 # look,NA值变成了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还记得之前讲的reindex吗,在对Series和DataFrame重新索引是,也可以指定一个填充值:
>>> df1.reindex(columns=df2.columns,fill_value=0) a b c d e 0 0 1 2 3 0 1 4 5 6 7 0 2 8 9 10 11 0下面给出基本的算数运算函数:
方法说明add用于加法sub用于减法div用于除法mul用于乘法 DataFrame和Series之间的运算跟Numpy数组一样,DataFrame和Series之间的运算也是有明确规定的。先上一个例子:
>>> arr = np.arange(12).reshape((3,4)) >>> arr array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> arr[0] array([0, 1, 2, 3]) >>> arr - arr[0] array([[0, 0, 0, 0], [4, 4, 4, 4], [8, 8, 8, 8]])这种运算叫做广播,意思就是可以把某一数据扩散传播并参与运算到整个数组。DataFrame和Series之间的运算也差不多是这样:
>>> frame = DataFrame(np.arange(12).reshape((4,3)),columns=list('bde'),index=['Utah','Ohio','Texas','Orgegon']) >>> series = frame.ix[0] >>> frame b d e Utah 0 1 2 Ohio 3 4 5 Texas 6 7 8 Orgegon 9 10 11 >>> series b 0 d 1 e 2 Name: Utah, dtype: int64默认情况下,DataFrame和Series之间的运算会将Series的索引匹配到DataFrame的所有列,然后沿着行方向一直向下传播:
>>> frame - series b d e Utah 0 0 0 Ohio 3 3 3 Texas 6 6 6 Orgegon 9 9 9如果希望匹配行且在列上广播,则必须使用算数运算方法:
>>> series2 = frame['d'] >>> frame b d e Utah 0 1 2 Ohio 3 4 5 Texas 6 7 8 Orgegon 9 10 11 >>> series2 Utah 1 Ohio 4 Texas 7 Orgegon 10 Name: d, dtype: int64 >>> frame.sub(series2,axis=0) b d e Utah -1 0 1 Ohio -1 0 1 Texas -1 0 1 Orgegon -1 0 1传入的轴号就是希望匹配的轴,如果不写轴号默认是axis=1,会出错。
函数应用和映射Numpy的ufunc(元素级数组方法),也可用与操作Pandas对象:
>>> frame = DataFrame(np.random.randn(4,3),columns=list('bde'),index=['Utah','Ohio','Texas','Oregon']) >>> frame b d e Utah 0.228682 0.256469 -1.233977 Ohio -1.021476 0.796296 1.715231 Texas 0.205654 -0.371884 -2.273169 Oregon 0.390541 -0.310140 1.070018 >>> np.abs(frame) b d e Utah 0.228682 0.256469 1.233977 Ohio 1.021476 0.796296 1.715231 Texas 0.205654 0.371884 2.273169 Oregon 0.390541 0.310140 1.070018另一个常见的操作是将函数应用到由各列或各行所形成的一维数组上。DataFrame的apply方法即可实现此功能。
>>> f = lambda x:x.max()-x.min() # lambda表达式 >>> frame.apply(f) b 1.412017 d 1.168180 e 3.988401 dtype: float64apply方法默认是应用在axis=0上面的,所以如果想要应用在axis=1上得显式指定。
>>> frame.apply(f,axis=1) Utah 1.490445 Ohio 2.736707 Texas 2.478823 Oregon 1.380158 dtype: float64除标量值外,传递给apply的函数还可以返回由多个值组成的Series:
>>> def f(x): ... return Series([x.max()-x.min()],index=['min','max']) ... >>> frame.apply(f) b d e min 1.412017 1.16818 3.988401 max 1.412017 1.16818 3.988401函数f可以用lambda表达式替换:
>>> f = lambda x:Series([x.max()-x.min()],index=['min','max']) >>> frame.apply(f) b d e min 1.412017 1.16818 3.988401 max 1.412017 1.16818 3.988401 排序和排名根据条件对数据进行排序也是一种重要的内置运算。要对行或者列索引进行排序(按字典排序),可使用sort_index方法,它将返回一个已排序的新对象:
>>> obj = Series(range(4),index=['d','a','b','c']) >>> obj d 0 a 1 b 2 c 3 dtype: int64 >>> obj.sort_index() a 1 b 2 c 3 d 0 dtype: int64面对DataFrame,则可以根据任意一个轴上的索引进行排序:
>>> frame = DataFrame(np.arange(8).reshape((2,4)),index=['three','one'],columns=['d','a','b','c']) >>> frame.sort_index() # axis=0 d a b c one 4 5 6 7 three 0 1 2 3 >>> frame.sort_index(axis=1) # axis=1 a b c d three 1 2 3 0 one 5 6 7 4数据默认是按升序排列的,但也可以降序排列,只需改一个参数:
>>> frame.sort_index(axis=1,ascending=False) d c b a three 0 3 2 1 one 4 7 6 5以上是对Series或者DataFrame的索引或者列进行排序,还有一种排序是针对里面的数据值来进行排序的,这里用到的就是sort_values方法(2.7.12以前版本使用的是order,虽然可以产生作用,但会弹出警告):
>>> obj.sort_values() 2 -3 3 2 0 4 1 7 dtype: int64在排序时,任何缺失值默认都会被放到Series的末尾:
>>> obj = Series([4,np.nan,7,np.nan,-3,2]) >>> obj.sort_values() 4 -3.0 5 2.0 0 4.0 2 7.0 1 NaN 3 NaN dtype: float64在DataFrame上,你可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给by选项即可达到该目的,使用的还是sort_values函数(2.7.12版本以前用的是sort_index,会产生效果,但会弹警告):
>>> frame = DataFrame({'b':[4,7,-3,2],'a':[0,1,0,1]}) >>> frame a b 0 0 4 1 1 7 2 0 -3 3 1 2 >>> frame.sort_values(by='b') a b 2 0 -3 3 1 2 0 0 4 1 1 7