分組聚合是數(shù)據(jù)處理中常見(jiàn)的場(chǎng)景硝桩,在pandas中用groupby方法實(shí)現(xiàn)分組操作,用agg方法實(shí)現(xiàn)聚合操作索烹。
環(huán)境
- python3.9
- win10 64bit
- pandas==1.2.1
groupby
方法是pandas中的分組方法届案,對(duì)數(shù)據(jù)框采用groupby
方法后,返回的是DataFrameGroupBy
對(duì)象啦逆,一般分組操作后會(huì)進(jìn)行聚合操作伞矩。
分組
import pandas as pd
import numpy as np
pd.set_option('display.notebook_repr_html',False)
# 數(shù)據(jù)準(zhǔn)備
df = pd.DataFrame({'A': [1, 1, 2, 2],'B': [1, 2, 3, 4],'C':[6,8,1,9]})
df
A B C
0 1 1 6
1 1 2 8
2 2 3 1
3 2 4 9
對(duì)數(shù)據(jù)框按A
列進(jìn)行分組,產(chǎn)生分組數(shù)據(jù)框夏志。分組數(shù)據(jù)框是可迭代對(duì)象乃坤,可以進(jìn)行循環(huán)遍歷,可以看出在循環(huán)中,每個(gè)元素的類型是元組侥袜,
元組的第一個(gè)元素是分組值蝌诡,第二個(gè)元素是對(duì)應(yīng)的分組數(shù)據(jù)框。
# 分組
g_df=df.groupby('A')
# 分組數(shù)據(jù)框類
type(g_df)
pandas.core.groupby.generic.DataFrameGroupBy
# 循環(huán)分組數(shù)據(jù)
for i in g_df:
print(i,type(i),end='\n\n')
(1, A B C
0 1 1 6
1 1 2 8) <class 'tuple'>
(2, A B C
2 2 3 1
3 2 4 9) <class 'tuple'>
可以對(duì)分組后的數(shù)據(jù)框直接使用聚合方法agg
枫吧,對(duì)分組數(shù)據(jù)框的每一列計(jì)算統(tǒng)計(jì)函數(shù)值浦旱。
# 分組求和
df.groupby('A').agg('sum')
B C
A
1 3 14
2 7 10
序列分組
可以根據(jù)數(shù)據(jù)框外的序列數(shù)據(jù)對(duì)數(shù)據(jù)框進(jìn)行分組,需要注意序列長(zhǎng)度需要與數(shù)據(jù)框行數(shù)相同九杂。
# 定義分組列表
label=['a','a','b','b']
# 分組求和
df.groupby(label).agg('sum')
A B C
a 2 3 14
b 4 7 10
多列分組
可以根據(jù)數(shù)據(jù)框的多列對(duì)數(shù)據(jù)框進(jìn)行分組颁湖。
# 數(shù)據(jù)準(zhǔn)備
df = pd.DataFrame({'A': [1, 1, 2, 2],'B': [3, 4, 3, 3],'C':[6,8,1,9]})
df
A B C
0 1 3 6
1 1 4 8
2 2 3 1
3 2 3 9
根據(jù)A
,B
列進(jìn)行分組,然后求和例隆。
# 根據(jù)多列分組求和
df.groupby(['A','B']).agg('sum')
C
A B
1 3 6
4 8
2 3 10
索引分組
可以根據(jù)索引對(duì)數(shù)據(jù)框進(jìn)行分組甥捺,需要設(shè)置level
參數(shù)。
# 數(shù)據(jù)準(zhǔn)備
df = pd.DataFrame({'A': [1, 1, 2, 2],'B': [3, 4, 3, 3],'C':[6,8,1,9]},index=['a','a','b','b'])
df
A B C
a 1 3 6
a 1 4 8
b 2 3 1
b 2 3 9
數(shù)據(jù)框只有一層索引镀层,設(shè)置參數(shù)level=0
镰禾。
# 根據(jù)索引分組求和
df.groupby(level=0).agg('sum')
A B C
a 2 7 14
b 4 6 10
當(dāng)數(shù)據(jù)框索引有多層時(shí),也可以根據(jù)需求設(shè)置level
參數(shù)唱逢,完成分組聚合吴侦。
# 數(shù)據(jù)準(zhǔn)備
mi=pd.MultiIndex.from_arrays([[1,1,2,2],[3,4,3,3]],names=['id1','id2'])
df=pd.DataFrame(dict(value=[4,7,2,9]),index=mi)
df
value
id1 id2
1 3 4
4 7
2 3 2
3 9
設(shè)置level
參數(shù),如需要根據(jù)第一層索引坞古,即id1
進(jìn)行分組备韧,可以設(shè)置level=0
或level='id1'
完成分組聚合。
# 根據(jù)第一層索引分組求和
df.groupby(level=0).agg('sum')
value
id1
1 11
2 11
# 根據(jù)第一層索引分組求和
df.groupby(level='id1').agg('sum')
value
id1
1 11
2 11
聚合
分組后一般會(huì)進(jìn)行聚合操作痪枫,用agg
方法進(jìn)行聚合织堂。
# 數(shù)據(jù)準(zhǔn)備
df = pd.DataFrame({'A': [1, 1, 2, 2],'B': [3, 4, 3, 3],'C':[6,8,1,9],'D':[2,5,4,8]})
df
A B C D
0 1 3 6 2
1 1 4 8 5
2 2 3 1 4
3 2 3 9 8
單函數(shù)對(duì)多列
對(duì)分組后數(shù)據(jù)框使用單個(gè)函數(shù)進(jìn)行聚合,單個(gè)聚合函數(shù)會(huì)對(duì)每列進(jìn)行計(jì)算奶陈,然后合并返回易阳。聚合函數(shù)以字符串的形式傳入。
# 對(duì)所有列分組求和
df.groupby('A').agg('sum')
B C D
A
1 7 14 7
2 6 10 12
可以對(duì)分組后的數(shù)據(jù)指定列進(jìn)行分組聚合吃粒。需要注意子列需要用[]包裹闽烙。
# 對(duì)指定列分組求和
df.groupby('A')[['B','C']].agg('sum')
B C
A
1 7 14
2 6 10
聚合函數(shù)也可以傳入自定義的匿名函數(shù)。
# 匿名函數(shù)分組求和
df.groupby('A').agg(lambda x:sum(x))
B C D
A
1 7 14 7
2 6 10 12
多函數(shù)對(duì)多列
聚合函數(shù)可以是多個(gè)函數(shù)声搁。聚合時(shí)黑竞,多個(gè)聚合函數(shù)會(huì)對(duì)每列進(jìn)行計(jì)算,然后合并返回疏旨。聚合函數(shù)以列表的形式傳入很魂。
# 全部列多函數(shù)聚合
df.groupby('A').agg(['sum','mean'])
B C D
sum mean sum mean sum mean
A
1 7 3.5 14 7 7 3.5
2 6 3.0 10 5 12 6.0
聚合返回后的數(shù)據(jù)列名有兩層索引,第一層是聚合的列名檐涝,第二層是使用的聚合函數(shù)名遏匆。如果需要對(duì)返回的聚合函數(shù)名重命名法挨,
需要在傳參時(shí),傳入元組幅聘,第一個(gè)元素為聚合函數(shù)名凡纳,第二個(gè)元素為聚合函數(shù)。
# 聚合函數(shù)重命名
df.groupby('A').agg([('SUM','sum'),('MEAN','mean')])
B C D
SUM MEAN SUM MEAN SUM MEAN
A
1 7 3.5 14 7 7 3.5
2 6 3.0 10 5 12 6.0
同樣帝蒿,也可以傳入匿名函數(shù)荐糜。
# 匿名函數(shù)并重命名
df.groupby('A').agg([('SUM','sum'),('MAX',lambda x:max(x))])
B C D
SUM MAX SUM MAX SUM MAX
A
1 7 4 14 8 7 5
2 6 3 10 9 12 8
如果需要對(duì)不同的列進(jìn)行不同的聚合計(jì)算,則需要傳入字典的形式葛超。
# 不同列不同聚合函數(shù)
df.groupby('A').agg({'B':['sum','mean'],'C':'mean'})
B C
sum mean mean
A
1 7 3.5 7
2 6 3.0 5
可以重命名聚合后的列名暴氏,注意只能對(duì)一列傳入一個(gè)聚合函數(shù)時(shí)有效。
# 聚合后重命名列名
df.groupby('A').agg(B_sum=('B','sum'),C_mean=('C','mean'))
B_sum C_mean
A
1 7 7
2 6 5