利用python进行数据分析之pandas库的应用(二)
本节介绍Series和DataFrame中的数据的基本手段
重新索引
pandas对象的一个重要方法就是reindex,作用是创建一个适应新索引的新对象
>>> from pandas import Series,DataFrame >>> 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
#reindex对索引值进行重排,如果当前索引值不存在,就引入缺失值 >>> obj2=obj.reindex(['a','b','c','d','e']) >>> obj2 a -5.3 b 7.2 c 3.6 d 4.5 e NaN dtype: float64
#可以指定fill_value=0来进行缺失值的替换 >>> obj.reindex(['a','b','c','d','e'],fill_value=0) a -5.3 b 7.2 c 3.6 d 4.5 e 0.0 dtype: float64
对于时间序列这样的有序数据,重新索引时可能需要做一些插值处理,method选项即可达到此目的:
method参数介绍 | |
参数 | 说明 |
ffill或pad | 前向填充 |
bfill或backfill | 后向填充 |
>>> obj3=Series(['blue','red','yellow'],index=[0,2,4]) >>> obj3.reindex(range(6),method='ffill') 0 blue 1 blue 2 red 3 red 4 yellow 5 yellow dtype: object
对于DataFrame数据类型,reindex可以修改行与列索引,但如果仅传入一个序列,则优先重新索引行:
>>> DataFrame(np.arange(9).reshape((3,3)),index=['a','c','d'],columns=['ohio','texas','california']) ohio texas california a 0 1 2 c 3 4 5 d 6 7 8 >>> frame=DataFrame(np.arange(9).reshape((3,3)),index=['a','c','d'],columns=['ohio','texas','california']) >>> frame2=frame.reindex(['a','b','c','d']) >>> frame2 ohio texas california a 0 1 2 b NaN NaN NaN c 3 4 5 d 6 7 8
#使用columns关键字可以对列重新索引 >>> frame.reindex(columns=['texas','utah','california']) texas utah california a 1 NaN 2 c 4 NaN 5 d 7 NaN 8
#可利用ix的标签索引功能,重新索引任务可以变得简洁
frame.ix[['a','b','c','d'],['texas','utah','california']]
texas utah california
a 1 NaN 2
b NaN NaN NaN
c 4 NaN 5
d 7 NaN 8
丢弃指定轴上的项
丢弃轴上的项很简单,使用drop方法返回的是一个在指定轴上删除指定值的新对象
>>> obj=Series(np.arange(5),index=['a','b','c','d','e']) >>> new_obj=obj.drop('c') >>> new_obj a 0 b 1 d 3 e 4 dtype: int32
#对于DataFrame,可以删除任意轴上的索引值 >>> frame=DataFrame(np.arange(9).reshape((3,3)),index=['a','c','d'],columns=['ohio','texas','california']) >>> frame.drop(['ohio'],axis=1) texas california a 1 2 c 4 5 d 7 8
索引,选取和过滤
Series利用标签的切片运算与普通的python切片运算不同,其末端是包含的,
DataFrame进行索引就是获取一个或多个列
>>> frame.drop(['ohio'],axis=1) texas california a 1 2 c 4 5 d 7 8 >>> frame ohio texas california a 0 1 2 c 3 4 5 d 6 7 8 >>> frame['ohio'] a 0 c 3 d 6 Name: ohio, dtype: int32
#也可通过切片和布尔型来选取
>>> frame[:2] ohio texas california a 0 1 2 c 3 4 5 >>> frame[frame['ohio']>=3] ohio texas california c 3 4 5 d 6 7 8
为了在DateFrame上进行标签索引,我们引入ix:
>>> frame ohio texas california a 0 1 2 c 3 4 5 d 6 7 8 >>> frame.ix['a',['ohio','texas']] #注意行标签在前,列标签在后 ohio 0 texas 1 Name: a, dtype: int32
算术运算和数据对齐
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+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 >>> df1+df2 b c d e colorado NaN NaN NaN NaN ohio 3 NaN 6 NaN oregon NaN NaN NaN NaN texas 9 NaN 12 NaN utah NaN NaN NaN NaN
#只返回行列均匹配的数值
在对不同的索引对象进行算术运算时,当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值
>>> 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 >>> df1.add(df2,fill_value=0) b c d e colorado 6 7 8 NaN ohio 3 1 6 5 oregon 9 NaN 10 11 texas 9 4 12 8 utah 0 NaN 1 2
DataFrame和Series之间的算术运算也是有明确规定的,会进行一种广播运算,默认情况下DataFrame和Series之间的运算会将Series的索引匹配到DataFrame的列索引,然后沿着行一直向下传播,
>>> frame=DataFrame(np.arange(12).reshape((4,3)),columns=list('bde'),index=['utah','ohio','texas','oregon']) >>> series=frame.ix[0] >>> frame b d e utah 0 1 2 ohio 3 4 5 texas 6 7 8 oregon 9 10 11 >>> series b 0 d 1 e 2 Name: utah, dtype: int32 >>> frame-series b d e utah 0 0 0 ohio 3 3 3 texas 6 6 6 oregon 9 9 9
如果希望匹配行索引并且在列上进行广播,则必须使用算是运算方法:
>>> frame['d'] utah 1 ohio 4 texas 7 oregon 10 Name: d, dtype: int32 >>> frame.sub(frame['d'],axis=0) b d e utah -1 0 1 ohio -1 0 1 texas -1 0 1 oregon -1 0 1
函数应用和映射
numpy的函数也可以操作pandas对象:
>>> frame=DataFrame(np.random.randn(4,3),columns=list('bde'),index=['utah','ohio','texas','oregon']) >>> frame b d e utah -1.258749 0.147998 0.250556 ohio 0.801182 -0.295881 1.377340 texas -0.281857 -0.009323 -0.520724 oregon 1.859103 0.098237 -0.475264 >>> np.abs(frame) b d e utah 1.258749 0.147998 0.250556 ohio 0.801182 0.295881 1.377340 texas 0.281857 0.009323 0.520724 oregon 1.859103 0.098237 0.475264
另一种常用的操作是,将函数应用到由各行各列所形成的一维数组上,利用apply方法可实现此功能:
>>> f=lambda x: x.max()-x.min() >>> frame.apply(f) #在行上进行操作 b 3.117851 d 0.443879 e 1.898065 dtype: float64 >>> frame.apply(f,axis=1)#在列上进行函数操作 utah 1.509304 ohio 1.673221 texas 0.511402 oregon 2.334367 dtype: float64 >>>
元素级的python函数也是适用的:
>>> format1=lambda x:'%.2f' %x >>> frame.applymap(format1) #用applymap,是因为Series有一个用于元素级函数的map方法 b d e utah -1.26 0.15 0.25 ohio 0.80 -0.30 1.38 texas -0.28 -0.01 -0.52 oregon 1.86 0.10 -0.48
排序和排名
根据条件对数据集排序也是一种重要的内置运算,对行列索引进行排序可使用sort_index方法,它将返回一个已排序的新对象
>>> obj=Series(range(4),index=['a','b','c','d']) >>> obj.sort_index() a 0 b 1 c 2 d 3 dtype: int64
对于DataFrame,可以根据任意一个轴上的索引进行排序:
>>> frame=DataFrame(np.arange(8).reshape((2,4)),index=['three','one'],columns=['d','a','b','c']) >>> frame d a b c three 0 1 2 3 one 4 5 6 7 >>> frame.sort_index() d a b c one 4 5 6 7 three 0 1 2 3 >>> frame.sort_index(axis=1) #指定轴进行排序 a b c d three 1 2 3 0 one 5 6 7 4
Series若要进行按值排序,则可使用order方法,ascending参数可指定升降序
>>> obj a 0 b 1 c 2 d 3 dtype: int64 >>> obj.order(ascending=False) d 3 c 2 b 1 a 0 dtype: int64 #排序时任何缺失值都会被排到Series的末尾
DataFrame的按值排序可以根据一个或多个列中的值进行排序,将一个或多个列名传递给by参数即可
>>> frame=DataFrame({'a':[4,7,-3,2],'b':[0,1,0,1]}) >>> frame a b 0 4 0 1 7 1 2 -3 0 3 2 1 >>> frame.sort_index(by='b') a b 0 4 0 2 -3 0 1 7 1 3 2 1 >>> frame.sort_index(by=['a','b']) #多列排序传入列名的列表即可 a b 2 -3 0 3 2 1 0 4 0 1 7 1
排名跟排序关系密切,且会增加一个排名值(排名从1开始),给对应值排名,输出索引和名次,
>>> obj=Series([7,-5,7,4,2,0,4]) >>> obj 0 7 1 -5 2 7 3 4 4 2 5 0 6 4 dtype: int64 >>> obj.rank() 0 6.5 1 1.0 2 6.5 3 4.5 4 3.0 5 2.0 6 4.5 dtype: float64
rank函数也可以根据值在数据中出现的位置顺序进行排名,相同值顺序在前排名高,也可以进行降序排名:
>>> obj.rank(method='first') 0 6 1 1 2 7 3 4 4 3 5 2 6 5 dtype: float64 >>> obj.rank(ascending=False,method='max') 0 2 1 7 2 2 3 4 4 5 5 6 6 4 dtype: float64
带有重复值的轴索引
pandas中轴索引非必须为唯一,对于带有重复值的索引,数据选取的行为将不同,如果某个索引对应多个值,则返回一个Series,而对应单个值,则返回一个标量值,对于Series与DataFrame类型数据皆为如此。(DataFrame单索引返回Series,重复索引返回DataFrame类型)
>>> obj=Series(range(5),index=['a','a','b','b','c']) >>> obj.index.is_unique False >>> obj['a'] a 0 a 1 dtype: int64 >>> obj['c'] 4
汇总和计算统计描述
idxmin,idxmax返回的是间接统计,cumsum返回累计统计
>>> df=DataFrame([[1.4,np.nan],[7.1,-4.5],[np.nan,np.nan],[0.75,-1.3]],index=['a','b','c','d'],columns=['one','two']) >>> df one two a 1.40 NaN b 7.10 -4.5 c NaN NaN d 0.75 -1.3 >>> df.idxmax() one b two d dtype: object >>> df.cumsum() one two a 1.40 NaN b 8.50 -4.5 c NaN NaN d 9.25 -5.8
describe方法一次性产生多个汇总统计,对于非数值型数据,describe方法会产生另外一种汇总统计:
>>> df.describe() one two count 3.000000 2.000000 mean 3.083333 -2.900000 std 3.493685 2.262742 min 0.750000 -4.500000 25% 1.075000 -3.700000 50% 1.400000 -2.900000 75% 4.250000 -2.100000 max 7.100000 -1.300000 >>> obj=Series(['a','a','b','c']*4) >>> obj.describe() count 16 unique 3 top a freq 8 dtype: object
描述和汇总统计方法介绍 | |
参数 | 说明 |
count | 非NA值的数量 |
describe | 针对Series或各DataFrame列计算汇总统计 |
min,max | 计算最大值和最小值 |
argmin,argmax | 计算能够获取到最大最小值的索引位置(整数) |
idxmin,idxmax | 计算能够获取到最大最小值的索引值 |
sum | 值的求和 |
mean | 均值 |
mad | 根据平均值计算绝对离差 |
var | 方差 |
std | 标准差 |
diff | 计算一阶差分 |
cumsum | 样本值的累积和 |
唯一值,值计数以及成员资格
一类方法可以从一维Series中抽取信息:
>>> obj=Series(['c','a','d','a','a','b','b','c']) >>> uniques=obj.unique() >>> uniques array(['c', 'a', 'd', 'b'], dtype=object) #unique方法得到Series中唯一值数组 >>> obj.value_counts() a 3 b 2 c 2 d 1 dtype: int64 #value_counts用于计算Series中各值出现的频率 >>> mask=obj.isin(['b','c']) >>> mask 0 True 1 False 2 False 3 False 4 False 5 True 6 True 7 True dtype: bool >>> obj[mask] 0 c 5 b 6 b 7 c dtype: object #isin用于判断矢量化的成员资格,可用于选取Series列中的数据子集
处理缺失数据
pandas使用浮点值NaN表示浮点数和非浮点数组中的缺失数据,它只是一个便于被检测出来的标记,pandas对象上所有的描述统计都排除了缺失数据
>>> from pandas import Series,DataFrame >>> import numpy as np >>> string_data=Series(['aardvark','artichoke',np.nan,'avocado']) >>> string_data 0 aardvark 1 artichoke 2 NaN 3 avocado dtype: object >>> sring_data.isnull() >>> string_data.isnull() 0 False 1 False 2 True 3 False dtype: bool #python内置的None属性会被当作NA处理 >>> string_data[0]=None >>> string_data.isnull() 0 True 1 False 2 True 3 False dtype: bool
滤除缺失数据的方法有很多,手工是一种,但dropna是比较实用的一种方法,dropna返回一个仅含非空数据和索引值的Series。
>>> data=Series([1,np.nan,3.5,np.nan,7]) >>> data 0 1.0 1 NaN 2 3.5 3 NaN 4 7.0 dtype: float64 >>> data.dropna() 0 1.0 2 3.5 4 7.0 dtype: float64 #也可以通过布尔型索引达到这个目的 >>> data[data.notnull()] 0 1.0 2 3.5 4 7.0 dtype: float64
对于DataFrame对象,dropnan默认丢弃任何含有缺失值的行:
>>> data=DataFrame([[1,6.5,3],[1,np.nan,np.nan],[np.nan,np.nan,np.nan],[np.nan,6.5,3]]) >>> data 0 1 2 0 1 6.5 3 1 1 NaN NaN 2 NaN NaN NaN 3 NaN 6.5 3 >>> cleaned=data.dropna() >>> cleaned 0 1 2 0 1 6.5 3 #传入how='all',则只丢弃全为na的那些行 >>> data.dropna(how='all') 0 1 2 0 1 6.5 3 1 1 NaN NaN 3 NaN 6.5 3 #如要丢弃列,则传入axis=1即可
当你不想丢弃过滤缺失数据时,可以通过其他方法填补缺失数据,大多数情况下fillna是最主要的函数,通过一个常数调用就会将缺失值替换为想要的常数值
>>> df.ix[:4,1]=np.nan >>> df 0 1 2 0 0.644651 NaN -0.858760 1 -0.093238 NaN -0.179058 2 1.547357 NaN -0.160275 3 -0.159654 NaN -0.898084 4 -0.987568 NaN -0.128100 5 -0.950301 -0.882556 0.155634 6 1.090057 -0.312113 -1.098901 >>> df.fillna(0) 0 1 2 0 0.644651 0.000000 -0.858760 1 -0.093238 0.000000 -0.179058 2 1.547357 0.000000 -0.160275 3 -0.159654 0.000000 -0.898084 4 -0.987568 0.000000 -0.128100 5 -0.950301 -0.882556 0.155634 6 1.090057 -0.312113 -1.098901 #通过字典调用fillna,可实现不同列填充不同的值 >>> df.fillna({1:0.5,3:-1}) 0 1 2 0 0.644651 0.500000 -0.858760 1 -0.093238 0.500000 -0.179058 2 1.547357 0.500000 -0.160275 3 -0.159654 0.500000 -0.898084 4 -0.987568 0.500000 -0.128100 5 -0.950301 -0.882556 0.155634 6 1.090057 -0.312113 -1.098901
层次化索引
层次化索引是pandas的一项重要功能,它使你能在一个轴上拥有多个索引级别,可以低纬度的形式处理高维度数据:
>>> data=Series(np.random.randn(10),index=[['a','a','a','b','b','b','c','c','d','d'],[1,2,3,1,2,3,1,2,2,3]]) >>> data a 1 0.671419 2 -0.645337 3 -0.681691 b 1 -1.096300 2 -1.017407 3 -0.299791 c 1 1.268928 2 1.051565 d 2 0.821926 3 -0.628511 dtype: float64 >>> data['b'] 1 -1.096300 2 -1.017407 3 -0.299791 dtype: float64 #数据甚至可以在内层选取 >>> data[:,2] a -0.645337 b -1.017407 c 1.051565 d 0.821926 dtype: float64
层次化索引在数据重塑和基于分组的操作中,扮有重要角色,对于DataFrame,每条轴都可以有分层索引,可以轻松选取列分组
#Series可以通过unstack安排到一个DataFrame中去 >>> data.unstack() 1 2 3 a 0.671419 -0.645337 -0.681691 b -1.096300 -1.017407 -0.299791 c 1.268928 1.051565 NaN d NaN 0.821926 -0.628511 >>> data.unstack().stack() a 1 0.671419 2 -0.645337 3 -0.681691 b 1 -1.096300 2 -1.017407 3 -0.299791 c 1 1.268928 2 1.051565 d 2 0.821926 3 -0.628511 dtype: float64
重排分级顺序与根据级别进行汇总统计
有时需要重新调整某条轴上各级别的顺序或者根据指定级别上的值进行重新排序,swaplevel可以接受两个级别编号或名称,并返回一个互换了级别的新对象。值汇总统计时,使用level参数可以指定在某条轴上求和的级别。
>>> frame=DataFrame(np.arange(12).reshape((4,3)),index=[['a','a','b','b'],[1,2,1,2]],columns=[['ohio','ohio','colorado'],['green','red','green']]) >>> frame ohio colorado green red green a 1 0 1 2 2 3 4 5 b 1 6 7 8 2 9 10 11 >>> frame.index.names=['key1','key2'] >>> frame.columns.names=['state','color'] >>> frame.swaplevel('key1','key2') state ohio colorado color green red green key2 key1 1 a 0 1 2 2 a 3 4 5 1 b 6 7 8 2 b 9 10 11
#在key2上进行归纳求和 >>> frame.sum(level='key2') state ohio colorado color green red green key2 1 6 8 10 2 12 14 16 >>> frame.sum(level='color',axis=1) color green red key1 key2 a 1 2 1 2 8 4 b 1 14 7 2 20 10
使用DataFrame的列
DataFrame的set_index函数会将其一个或多个列转换为行索引,并创建一个新的DataFrame:
>>> frame=DataFrame({'a':range(7),'b':range(7,0,-1),'c':['one','one','one','two','two','two','two'],'d':[0,1,2,0,1,2,3]}) >>> frame2=frame.set_index(['c','d']) >>> frame2 a b c d one 0 0 7 1 1 6 2 2 5 two 0 3 4 1 4 3 2 5 2 3 6 1