一、介紹
日常數據分析中,難免需要將數據根據某個(或者多個)字段進行分組,求聚合值的操作,例如:求班級男女身高的平均值。可以通過 groupby
實現該需求。
初步認識:df.groupby('name').agg({'price':'sum'}).reset_index()
使用語法:
Series.groupby(by=None,
axis=0,
level=None,
as_index=True,
sort=True,
group_keys=True,
dropna=True)
二、groupby實操
1.構造測試數據集
import pandas as pd
import numpy as np
name = ['老王','呂布','孫悟空']
df = pd.DataFrame({
'name':[name[x] for x in np.random.randint(0, len(name), 9)],
'salary':np.random.randint(100,1000,9),
'score':np.random.randint(6,11,9)
})
df
'''
name salary score
0 孫悟空 719 6
1 呂布 907 6
2 呂布 936 9
3 老王 974 7
4 呂布 940 7
5 孫悟空 857 6
6 老王 230 7
7 呂布 464 6
8 老王 557 9
'''
2.DataFrameGroupBy對象
- 查看分組對象
# 數據框分組對象
groupbying = df.groupby('name')
groupbying # <pandas.core.groupby.DataFrameGroupBy object at 0x00000000116A12E8>
# 查看類型
type(groupbying) # pandas.core.groupby.DataFrameGroupBy
# 查看值
list(groupbying) # 大列表 包含元組對象
list(groupbying)[0]
lvbu = list(groupbying)[0] # 元組
list(lvbu)[0]
list(lvbu)[1]
- 遍歷分組對象
for name, group in groupbying:
print(name)
print(group)
- 選擇分組
get_group()
groupbying.get_group('孫悟空')
'''
name salary score
0 孫悟空 719 6
5 孫悟空 857 6
'''
- 同一個列名使用不同聚合函數
agg
df.groupby('name')['score'].agg(['sum','max','min','mean','size']).reset_index()
'''
name sum max min mean size
0 呂布 28 9 6 7.000000 4
1 孫悟空 12 6 6 6.000000 2
2 老王 23 9 7 7.666667 3
'''
- 不作為索引
df.groupby('name', as_index=False)['score'].sum()
df.groupby('name')['score'].sum()
三、常見聚合函數
Pandas
常用的聚合函數:
函數 | 含義 |
---|---|
min/max | 最小值、最大值 |
sum | 和 |
mean | 均值 |
median | 中位數 |
std | 標准差 |
var | 方差 |
count | 計數 |
numpy
庫方法同樣支持,例如:
- unique 不同元素
- nunique 不同元素個數(count是所有個數,不去重)
四、agg聚合操作
聚合操作是通過 agg
來完成的,可以指定一個或者多個列分別使用不同的聚合函數來聚合。
- 對單列聚合
df.groupby('name').agg({'salary':'sum'}).reset_index()
df.groupby('name')['salary'].sum().reset_index()
- 對多列聚合
score = df.groupby('name').agg({'salary':'sum',
'score':'mean'}).reset_index()
score.columns = ['name', 'salary_sum', 'score_mean']
score
'''
name salary_sum score_mean
0 呂布 3247 7.000000
1 孫悟空 1576 6.000000
2 老王 1761 7.666667
'''
df.groupby('name').agg({'salary':'sum', 'score':'mean'}).reset_index().rename(columns={'salary':'salary_sum', 'score':'score_mean'})
- 針對多列並重命名
# version 0.25 以后才支持這種寫法
df.groupby('name').agg(
total_score=pd.NamedAgg(column='score', aggfunc='sum'),
min_salary=pd.NamedAgg(column='salary', aggfunc='min')
)
- 統計非重復個數
df.groupby('name').agg({'score':['unique','nunique']}).reset_index()
'''
name score
unique nunique
0 呂布 [6, 9, 7] 3
1 孫悟空 [6] 1
2 老王 [7, 9] 2
'''
# 多重索引
五、transform函數
transform
實現添加一列。
df['salary_mean'] = df.groupby('name')['salary'].transform('mean')
'''
name salary score score_mean salary_mean
0 孫悟空 719 6 6.000000 788.00
1 呂布 907 6 7.000000 811.75
2 呂布 936 9 7.000000 811.75
3 老王 974 7 7.666667 587.00
4 呂布 940 7 7.000000 811.75
5 孫悟空 857 6 6.000000 788.00
6 老王 230 7 7.666667 587.00
7 呂布 464 6 7.000000 811.75
8 老王 557 9 7.666667 587.00
'''
如果不使用 transform
實現操作。
avg_salary = df.groupby('name')['salary'].mean().to_dict()
df['salary_mean2'] = df['name'].map(avg_salary)
transform
是在原數據的基礎上新增一列,agg
是根據分組字段和聚合函數生成新的數據框transform
的數據是填充到分組對象的每列上,而agg
生成一個新的聚合結果
六、apply函數
分組之后的 apply
應用函數,是以分組后的子數據框作為參數傳入指定函數的,與數據框中傳入的是 Series
稍有不同。
def get_max_salary(x):
df = x.sort_values(by='salary', ascending=True)
return df.iloc[-1, :]
df.groupby('name', as_index=False).apply(get_max_salary)
apply
的運行效率比agg
和transform
更慢。
參考鏈接:圖解Pandas的groupby機制