这将是Pandas入门篇的最终篇了,人看麻了。
一、带有重复标签的轴索引
直到目前为止,所有范例都有着唯一的轴标签(索引值)。虽然许多pandas函数(如reindex)都要求标签唯一,但这并不是强制性的。来看看下面这个简单的带有重复索引值的Series:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import pandas as pdobj = pd.Series(range (5 ), index=["a" , "a" , "b" , "b" , "c" ]) print ("-----obj-----" )print (obj)print ("-----obj.index.is_unique-----" )print (obj.index.is_unique)-----obj----- a 0 a 1 b 2 b 3 c 4 dtype: int64 -----print (obj.index.is_unique)----- False
对于带有重复值的索引,数据选取的行为将会有些不同。如果某个索引对应多个值,则返回一个Series;而对应单个值的,则返回一个标量值:
1 2 3 4 5 6 7 8 9 10 11 ··· print ("-----obj['a']-----" )print (obj['a' ])-----obj['a' ]----- a 0 a 1 dtype: int64 -----obj['c' ]----- 4
这样会使代码变复杂,因为索引的输出类型会根据标签是否有重复发生变化。
对DataFrame的行进行索引时也是如此:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 df = pd.DataFrame(np.random.randn(4 ,3 ), index=["a" , "a" , "b" , "b" ]) print ("------df-----" )print (df)print ("-----df.loc['b']-----" )print (df.loc['b' ])------df----- 0 1 2 a -1.546672 -0.810346 -0.045471 a -1.340069 -0.827010 -1.070048 b 1.974275 0.189458 -0.988055 b 0.895172 -1.736643 1.619483 -----df.loc['b' ]----- 0 1 2 b 1.974275 0.189458 -0.988055 b 0.895172 -1.736643 1.619483
二、汇总和计算描述统计
2.1 简约型
pandas对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从Series中提取单个值(如sum或mean)或从DataFrame的行或列中提取一个Series。跟对应的NumPy数组方法相比,它们都是基于没有缺失数据的假设而构建的。看一个简单的DataFrame:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import pandas as pdimport numpy as npdf = pd.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' ]) print ("-----df-----" )print (df)-----df----- one two a 1.40 NaN b 7.10 -4.5 c NaN NaN d 0.75 -1.3
调用DataFrame的sum方法将会返回一个含有列的和的Series:
1 2 3 4 5 6 7 print ("-----df.sum()-----" )print (df.sum ())-----df.sum ()----- one 9.25 two -5.80 dtype: float64
传入axis='columns’或axis=1将会按行进行求和运算:
1 2 3 4 5 6 7 ··· -----df.sum (axis=1 )----- a 1.40 b 2.60 c 0.00 d -0.55 dtype: float64
注意,在这里和书上讲的不同这里直接将NaN排除了,整个切片都是NaN时值为0.00
通过skipna选项可以禁用该功能:
1 2 3 4 5 6 7 8 9 ··· print (df.mean(axis=1 , skipna=False ))a NaN b 1.300 c NaN d -0.275 dtype: float64
下表列出了一些简约方法的常用选项:
选项
说明
axis
轴
skipna
排除缺失值,默认为True
level
如果轴时层次化索引的(即MultiIndex),则根据level分组轴
有些方法(如idxmin和idxmax)返回的是间接统计(比如达到最小值或最大值的索引):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 print ("-----df.idmix()-----" )print (df.idxmin())print ("-----df.idmax()-----" )print (df.idxmax())-----df.idmix()----- one d two b dtype: object -----df.idmax()----- one b two d dtype: object
2.2 累计型
另一些方法则是累计型的:
1 2 3 4 5 6 7 8 9 10 11 ··· print ("-----df.cumsum()-----" )print (df.cumsum())-----df.cumsum()----- one two a 1.40 NaN b 8.50 -4.5 c NaN NaN d 9.25 -5.8
2.3 非累计非简约型
还有一种方法,它既不是约简型也不是累计型。describe就是一个例子,它用于一次性产生多个汇总统计:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ··· print ("-----df.describe()-----" )print (df.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
对于非数值型数据,describe会产生另外一种汇总统计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ··· obj = pd.Series(["a" , "a" , "b" , "c" ] * 4 ) print ("-----obj-----" )print (obj)print ("-----obj.describe()-----" )print (obj.describe())-----obj----- 0 a1 a2 b3 c4 a5 a6 b7 c8 a9 a10 b11 c12 a13 a14 b15 cdtype: object -----obj.describe()----- count 16 unique 3 top a freq 8 dtype: object
下图列出了所有与描述统计相关的方法
三、唯一值、值计数以及成员资格
还有一类方法可以从一维Series的值中抽取信息。看下面的例子:
1 2 import pandas as pdobj = pd.Series(['c' , 'a' , 'd' , 'a' , 'a' , 'b' , 'b' , 'c' , 'c' ])
第一个函数是unique,它可以得到Series中的唯一值数组:
1 2 3 4 5 6 7 8 ··· print ("-----obj.unique()-----" )uniques = obj.unique() print (uniques)-----obj.unique()----- ['c' 'a' 'd' 'b' ]
返回的唯一值是未排序的,如果需要的话,可以对结果再次进行排序(uniques.sort())。相似的,value_counts用于计算一个Series中各值出现的频率:
1 2 3 4 5 6 7 8 9 10 11 ··· print ("-----obj.value_counts()-----" )print (obj.value_counts())-----obj.value_counts()----- c 3 a 3 b 2 d 1 dtype: int64
isin用于判断矢量化集合的成员资格,可用于过滤Series中或DataFrame列中数据的子集:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 ··· print ("-----obj-----" )print (obj)print ("-----obj.isin(['b', 'c'])-----" )print (obj.isin(["b" , "c" ]))mask = obj.isin(["b" , "c" ]) print ("-----obj[mask]-----" )print (obj[mask])-----obj----- 0 c1 a2 d3 a4 a5 b6 b7 c8 cdtype: object -----obj.isin(['b' , 'c' ])----- 0 True 1 False 2 False 3 False 4 False 5 True 6 True 7 True 8 True dtype: bool -----obj[mask]----- 0 c5 b6 b7 c8 cdtype: object
与isin类似的是Index.get_indexer方法,它可以给你一个索引数组,从可能包含重复值的数组到另一个不同值的数组:
1 2 3 4 5 6 7 ··· to_match = pd.Series(["c" , "a" , "b" , "b" , "c" , "a" ]) unique_vals = pd.Series(["c" , "b" , "a" ]) print (pd.Index(unique_vals).get_indexer(to_match))[0 2 1 1 0 2 ]
下表给出了这几个方法的一些参考信息:
方法
说明
isin
计算一个表示"Series各值是否包含于传入的值序列中"的布尔型数组
match
计算一个数组中的各值到另一个不同值属猪的整数索引;对于数据对齐和连接类型的操作十分有用
unique
计算Series中的唯一值数组,按发现的顺序返回
value_counts
返回一个Series,其索引为唯一值,其值为频率,按计数值降序排列
有时,你可能希望得到DataFrame中多个相关列的一张柱状图。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ··· data = pd.DataFrame({Qu1': [1, 3, 4, 3, 4], ' Qu2': [2, 3, 1, 2, 3], ' Qu3': [1, 5, 2, 4, 4]}) print("-----data-----") print(data) # 将pandas.value_counts传给该DataFrame的apply函数,就会出现 print("柱状图") result = data.apply(pd.value_counts).fillna(0) print(result) # 结果 -----data----- Qu1 Qu2 Qu3 0 1 2 1 1 3 3 5 2 4 1 2 3 3 2 4 4 4 3 4 柱状图 Qu1 Qu2 Qu3 1 1.0 1.0 1.0 2 0.0 2.0 1.0 3 2.0 2.0 0.0 4 2.0 0.0 2.0 5 0.0 0.0 1.0
这里,结果中的行标签是所有列的唯一值。后面的频率值是每个列中这些值的相应计数。