聚合是指所有根据数组产生标量值的数据转换过程。就像mean count min sum等,
函数 | 描述 |
---|---|
count | 分组中的非NA 值数量 |
sum | 非NA值的累计和 |
mean | 非NA 值的均值 |
median | 非NA 值的算术中位数 |
std,var | 无偏的(n-1 分母)标准差和方差 |
min max | 非NA 值的最大值最小值 |
prod | 非NA 值 的乘积 |
first,last | 非NA 值 的第一个和最后一个值。 |
你可以自定义聚合,并在调用已经在分组对象上定义好的方法。例如,quantile 可用计算series 或 dataframe 列的样本分位数
分位数(Quantile),亦称分位点,是指将一个随机变量的概率分布范围分为几个等份的数值点,常用的有中位数(即二分位数)、四分位数、百分位数等。
尽管quantile并不是显式的为GroupBy 对象的函数,但是series的方法,因此也可以用于聚合。
df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
'key2' : ['one', 'two', 'one', 'two', 'one'],
'data1' : np.random.randn(5),
'data2' : np.random.randn(5)})
df
key1 key2 data1 data2
0 a one -0.603123 1.810936
1 a two 0.462399 0.172707
2 b one 0.998915 -1.275746
3 b two 2.649937 -0.188244
4 a one -1.637420 0.921537
grouped=df.groupby('key1')
grouped['data1'].quantile(0.9)
key1
a 0.249294
b 2.484835
Name: data1, dtype: float64
def peak_to_peak(arr): # 用自己的聚合函数,要把函数传递给aggregate or agg 方法。
return arr.max()-arr.min()
grouped.agg(peak_to_peak)
data1 data2
key1
a 2.099819 1.638229
b 1.651022 1.087502
grouped.describe() # 一些方法比如这个也是有效的,尽管不是聚合函数
data1 data2
count mean std min 25% 50% 75% max count mean std min 25% 50% 75% max
key1
a 3.0 -0.592715 1.049948 -1.637420 -1.120271 -0.603123 -0.070362 0.462399 3.0 0.968393 0.820119 0.172707 0.547122 0.921537 1.366236 1.810936
b 2.0 1.824426 1.167449 0.998915 1.411671 1.824426 2.237182 2.649937 2.0 -0.731995 0.768980 -1.275746 -1.003870 -0.731995 -0.460120 -0.188244
tips=pd.read_csv('tips.csv',sep='\t')
tips['tip_pct']=tips['tip']/tips['total_bill'] # 增加一个小费比例
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'] # 将函数名以字符串的形式传入
grouped_pct.agg('mean')
day smoker
Fri No 0.151650
Yes 0.174783
Sat No 0.158048
Yes 0.147906
Sun No 0.160113
Yes 0.187250
Thur No 0.160298
Yes 0.163863
Name: tip_pct, dtype: float64
grouped_pct.agg(['mean','std',peak_to_peak]) # 传递的是函数或函数名的列表,获得列名是这些函数名的dataframe
mean std peak_to_peak
day smoker
Fri No 0.151650 0.028123 0.067349
Yes 0.174783 0.051293 0.159925
Sat No 0.158048 0.039767 0.235193
Yes 0.147906 0.061375 0.290095
Sun No 0.160113 0.042347 0.193226
Yes 0.187250 0.154134 0.644685
Thur No 0.160298 0.038774 0.193350
Yes 0.163863 0.039389 0.151240
grouped_pct.agg([('foo','mean'),('bar',np.std)]) # (name.function) 第一个元素作为dataframe的列名
foo bar
day smoker
Fri No 0.151650 0.028123
Yes 0.174783 0.051293
Sat No 0.158048 0.039767
Yes 0.147906 0.061375
Sun No 0.160113 0.042347
Yes 0.187250 0.154134
Thur No 0.160298 0.038774
Yes 0.163863 0.039389
functions=['count','mean','max'] # 应用到所有列上的函数列表,
result=grouped['tip_pct','total_bill'].agg(functions)
result
tip_pct total_bill
count mean max count mean max
day smoker
Fri No 4 0.151650 0.187735 4 18.420000 22.75
Yes 15 0.174783 0.263480 15 16.813333 40.17
Sat No 45 0.158048 0.291990 45 19.661778 48.33
Yes 42 0.147906 0.325733 42 21.276667 50.81
Sun No 57 0.160113 0.252672 57 20.506667 48.17
Yes 19 0.187250 0.710345 19 24.120000 45.35
Thur No 45 0.160298 0.266312 45 17.113111 41.19
Yes 17 0.163863 0.241255 17 19.190588 43.11
result['tip_pct'] # 产生的dataframe 有分层列,这与聚合每一列在通过concat将结果拼接在一起是相同的
count mean max
day smoker
Fri No 4 0.151650 0.187735
Yes 15 0.174783 0.263480
Sat No 45 0.158048 0.291990
Yes 42 0.147906 0.325733
Sun No 57 0.160113 0.252672
Yes 19 0.187250 0.710345
Thur No 45 0.160298 0.266312
Yes 17 0.163863 0.241255
ftuples=[('Durchschnitt','mean'),('Abweichung',np.var)] # 就是传递有自定义名称的元组列表。
grouped['tip_pct','total_bill'].agg(ftuples)
tip_pct total_bill
Durchschnitt Abweichung Durchschnitt Abweichung
day smoker
Fri No 0.151650 0.000791 18.420000 25.596333
Yes 0.174783 0.002631 16.813333 82.562438
Sat No 0.158048 0.001581 19.661778 79.908965
Yes 0.147906 0.003767 21.276667 101.387535
Sun No 0.160113 0.001793 20.506667 66.099980
Yes 0.187250 0.023757 24.120000 109.046044
Thur No 0.160298 0.001503 17.113111 59.625081
Yes 0.163863 0.001551 19.190588 69.808518
grouped.agg({'tip_pct':['min','max','mean','std'], # 将不同的函数应用到一个或多个列上的字典就像
'size':'sum'}) # ,传递有列名与函数对应关系
tip_pct size
min max mean std sum
day smoker
Fri No 0.120385 0.187735 0.151650 0.028123 9
Yes 0.103555 0.263480 0.174783 0.051293 31
Sat No 0.056797 0.291990 0.158048 0.039767 115
Yes 0.035638 0.325733 0.147906 0.061375 104
Sun No 0.059447 0.252672 0.160113 0.042347 167
Yes 0.065660 0.710345 0.187250 0.154134 49
Thur No 0.072961 0.266312 0.160298 0.038774 112
Yes 0.090014 0.241255 0.163863 0.039389 40
前面的例子中,聚合数据返回时都是带有索引的,有时索引是分层的,由唯一的分组件联合形成。因为不是所有的情况都要索引,通过传递 ax_index = False 来禁用分组键作为索引的行为。
tips.groupby(['day','smoker'],as_index=False).mean() # == tips.groupby(['day','smoker']).mean().reset_index()
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
数据透视表是电子表格程序和其他数据分析软件中常见的数据汇总工具。更加一个或多个键聚合一张表的数据,将数据在矩形格式中排列,其中一些分组件是沿着行的,另一些沿着列。
在pandas中透视表透过groupby 工具以及使用分层索引的重塑操作实现。dataframe 有一个pivot_table 方法,并且还有一个顶层的pandas.pivot_table 函数,为groupby提供了一个方便的接口,还可以添加部分总计,也叫边距。。。啥啥啥啥啥
tips.pivot_table(index=['day','smoker']) # 计算一张在行方向上按day and smoker排列的分组平均值
size tip tip_pct total_bill # tips.groupby(['day','smoker']).mean() 跟这个一样欸
day smoker
Fri No 2.250000 2.812500 0.151650 18.420000
Yes 2.066667 2.714000 0.174783 16.813333
Sat No 2.555556 3.102889 0.158048 19.661778
Yes 2.476190 2.875476 0.147906 21.276667
Sun No 2.929825 3.167895 0.160113 20.506667
Yes 2.578947 3.516842 0.187250 24.120000
Thur No 2.488889 2.673778 0.160298 17.113111
Yes 2.352941 3.030000 0.163863 19.190588
tips.pivot_table(['tip_pct','size'],index=['time','day'],columns='smoker',margins=True)
# z在tip_pct,size 列聚合,根据time分组
size t ip_pct # 将 smoker放到表的列,将day 放到表的行。
smoker No Yes All No Yes All # 添加margins=True, 来扩充这个表来包含部分统计
time day
Dinner Fri 2.000000 2.222222 2.166667 0.139622 0.165347 0.158916 # 这里All的值是均值,就是不考虑分组了
Sat 2.555556 2.476190 2.517241 0.158048 0.147906 0.153152
Sun 2.929825 2.578947 2.842105 0.160113 0.187250 0.166897
Thur 2.000000 NaN 2.000000 0.159744 NaN 0.159744
Lunch Fri 3.000000 1.833333 2.000000 0.187735 0.188937 0.188765
Thur 2.500000 2.352941 2.459016 0.160311 0.163863 0.161301
All 2.668874 2.408602 2.569672 0.159328 0.163196 0.160803
tips.pivot_table('tip_pct',index=['time','smoker'],columns='day',aggfunc=len,margins=True,fill_value=0)
day Fri Sat Sun Thur All # 使用不同聚合函数时,将函数传递给aggfunc就行,传递len获得一张分组大小的交叉表
time smoker
Dinner No 3 45 57 1 106.0
Yes 9 42 19 0 70.0
Lunch No 1 0 0 44 45.0
Yes 6 0 0 17 23.0
All 19 87 76 62 244.0
pivot_table参数 | 描述 |
---|---|
values | 需要聚合的列,默认聚合所有数值型列 |
index | 在结果透视表的行上进行分组的列名或其他分组键 |
columns | 在结果透视表的列上进行分组的列名或其他分组键。 |
aggfunc | 聚合函数或函数列表,默认时mean 可以是groupby的任意有效函数 |
fill_value | 替换缺失值 |
dropna | 如果为True,不含所有条目都为NA的列 |
margins | 添加ALL,默认False |
这个是数据透视表的一个特殊情况,计算的是分组中的频率,
from io import StringIO
data = """\
Sample Nationality Handedness
1 USA Right-handed
2 Japan Left-handed
3 USA Right-handed
4 Japan Right-handed
5 Japan Left-handed
6 Japan Right-handed
7 USA Right-handed
8 USA Left-handed
9 Japan Right-handed
10 USA Right-handed"""
data = pd.read_table(StringIO(data), sep='\s+')
data
Sample Nationality Handedness
0 1 USA Right-handed
1 2 Japan Left-handed
2 3 USA Right-handed
3 4 Japan Right-handed
4 5 Japan Left-handed
5 6 Japan Right-handed
6 7 USA Right-handed
7 8 USA Left-handed
8 9 Japan Right-handed
9 10 USA Right-handed
pd.crosstab(data.Nationality, data.Handedness, margins=True) # 虽然可以使用pivot_table,但crosstab更加方便
Handedness Left-handed Right-handed All
Nationality
Japan 2 3 5
USA 1 4 5
All 3 7 10
# corsstab 的前两个参数可以是数值,series或数组的列表
pd.crosstab([tips.time, tips.day], tips.smoker, margins=True) # 额,,又是这个
smoker No Yes All
time day
Dinner Fri 3 9 12
Sat 45 42 87
Sun 57 19 76
Thur 1 0 1
Lunch Fri 1 6 7
Thur 44 17 61
All 151 93 244