数据聚合
- 逐列以及多函数应用
- 返回不含行索引的聚合数据
聚合是指根据数组产生标量值的数据转换过程,如mean、count、min和sum等。在之前介绍groupby机制的时候我们知道对GroupBy对象可以使用count等方法进行聚合,得到每个分组的聚合结果。常见的GroupBy对象的聚合方法见下表:
方法 | 描述 |
count | 分组中的非NA数值 |
sum | 非NA值的和 |
mean | 非NA值的均值 |
median | 非NA值的算数中位数 |
std、var | 无偏(n-1为分母)标准差和方差 |
min、max | 非NA值的最小值和最大值 |
prod | 非NA值的乘积 |
frist,last | 非NA值的第一个和最后一个值 |
考虑以下这个DataFrame:
df = pd.DataFrame({'key1':list('aabba'),
'key2':['one','two','one','two','one'],
'data1':np.random.randn(5),
'data2':np.random.randn(5)})
grouped = df.groupby('key1')quantile可以计算DataFrame或者Series的分位数,尽管GroupBy对象没有此方法,但是我们仍可以对GroupBy对象使用此方法,内部GroupBy对每一个Series对象或者DataFrame对象使用该方法,例如我们可以计算data1中每个分组的分位数:
print(grouped['data1'].quantile(0.9))
# key1
# a 1.001195
# b 2.274486
# Name: data1, dtype: float64如果想自定义一个聚合函数,可以使用GroupBy对象的agg方法:
def peak_to_peak(arr):
"""
计算每组的极差
:param arr: Series对象
:return: 极差
"""
return arr.max()-arr.min()
print(grouped.agg(peak_to_peak))
# data1 data2
# key1
# a 1.605113 0.866069
# b 1.117966 1.030901逐列以及多函数应用
我们可以使用agg方法对分组后的结果同时使用多个方法进行聚合,先考虑下面这个DataFrame,数据来自于文章开头中的资源,我们为它加上tip_pct这一项,并使用groupby方法按day和smoker来进行分组:
tips = pd.read_csv('../pydata-book-2nd-edition/examples/tips.csv')
tips['tip_pct'] = tips['tip']/tips['total_bill']
print(tips.head())
# total_bill tip smoker day time size tip_pct
# 0 16.99 1.01 No Sun Dinner 2 0.059447
# 1 10.34 1.66 No Sun Dinner 3 0.160542
# 2 21.01 3.50 No Sun Dinner 3 0.166587
# 3 23.68 3.31 No Sun Dinner 2 0.139780
# 4 24.59 3.61 No Sun Dinner 4 0.146808
grouped = tips.groupby(['day','smoker'])
grouped_pct = grouped['tip_pct']之后如果给agg方法传入一个包含函数或者函数名的列表,则可以得到列名为函数名的聚合结果:
print(grouped_pct.agg(['std','mean',peak_to_peak]))
# std mean peak_to_peak
# day smoker
# Fri No 0.028123 0.151650 0.067349
# Yes 0.051293 0.174783 0.159925
# Sat No 0.039767 0.158048 0.235193
# Yes 0.061375 0.147906 0.290095
# Sun No 0.042347 0.160113 0.193226
# Yes 0.154134 0.187250 0.644685
# Thur No 0.038774 0.160298 0.193350
# Yes 0.039389 0.163863 0.151240如果你传入的是一个(名字,函数或函数名)的元组,则列名则会是你传入的名字:
print(grouped_pct.agg([('平均直','mean'),('极差',peak_to_peak)]))
# 平均直 极差
# day smoker
# Fri No 0.151650 0.067349
# Yes 0.174783 0.159925
# Sat No 0.158048 0.235193
# Yes 0.147906 0.290095
# Sun No 0.160113 0.193226
# Yes 0.187250 0.644685
# Thur No 0.160298 0.193350
# Yes 0.163863 0.151240我们可以对两个列同时进行相同的三种数据操作,结果如下:
grouped = tips.groupby(['day','smoker'])
result = grouped['tip_pct','total_bill'].agg(['count','mean',peak_to_peak])
print(result)
# tip_pct total_bill
# count mean peak_to_peak count mean peak_to_peak
# day smoker
# Fri No 4 0.151650 0.067349 4 18.420000 10.29
# Yes 15 0.174783 0.159925 15 16.813333 34.42
# Sat No 45 0.158048 0.235193 45 19.661778 41.08
# Yes 42 0.147906 0.290095 42 21.276667 47.74
# Sun No 57 0.160113 0.193226 57 20.506667 39.40
# Yes 19 0.187250 0.644685 19 24.120000 38.10
# Thur No 45 0.160298 0.193350 45 17.113111 33.68
# Yes 17 0.163863 0.151240 17 19.190588 32.77
print(result['tip_pct'])
# count mean peak_to_peak
# day smoker
# Fri No 4 0.151650 0.067349
# Yes 15 0.174783 0.159925
# Sat No 45 0.158048 0.235193
# Yes 42 0.147906 0.290095
# Sun No 57 0.160113 0.193226
# Yes 19 0.187250 0.644685
# Thur No 45 0.160298 0.193350
# Yes 17 0.163863 0.151240当然,我们可以以(名字,函数)的形式传入agg也是可以的,具体使用方法与之前的介绍相同,在此不再赘述。
如果想在不同的列上应用不同的函数,可以给agg方法传入字典,并且此时不再需要提前将需要进行聚合的列分隔出来:
grouped = tips.groupby(['day','smoker'])
print(grouped.agg({'tip_pct':['min','max',peak_to_peak],'total_bill':'std'}))
# tip_pct total_bill
# min max peak_to_peak std
# day smoker
# Fri No 0.120385 0.187735 0.067349 5.059282
# Yes 0.103555 0.263480 0.159925 9.086388
# Sat No 0.056797 0.291990 0.235193 8.939181
# Yes 0.035638 0.325733 0.290095 10.069138
# Sun No 0.059447 0.252672 0.193226 8.130189
# Yes 0.065660 0.710345 0.644685 10.442511
# Thur No 0.072961 0.266312 0.193350 7.721728
# Yes 0.090014 0.241255 0.151240 8.355149返回不含行索引的聚合数据
在默认情况下使用groupby函数进行分组的时候会将分组键作为行索引,当然我们可以在使用groupby方法时指定as_index = False来禁用此行为,而是使用默认的数字索引:
grouped = tips.groupby(['day','smoker'],as_index=False)
print(grouped.mean())
# day smoker total_bill tip size tip_pct
# 0 Fri No 18.420000 2.812500 2.250000 0.151650
# 1 Fri Yes 16.813333 2.714000 2.066667 0.174783
# 2 Sat No 19.661778 3.102889 2.555556 0.158048
# 3 Sat Yes 21.276667 2.875476 2.476190 0.147906
# 4 Sun No 20.506667 3.167895 2.929825 0.160113
# 5 Sun Yes 24.120000 3.516842 2.578947 0.187250
# 6 Thur No 17.113111 2.673778 2.488889 0.160298
# 7 Thur Yes 19.190588 3.030000 2.352941 0.163863
















