dataframe分组与聚合

发布时间 2023-05-27 09:52:55作者: chenxiaoyuan
import pandas as pd
# 准备数据集
df = pd.read_excel('https://www.gairuo.com/file/data/dataset/team.xlsx')
df.head()
name team Q1 Q2 Q3 Q4
0 Liver E 89 21 24 64
1 Arry C 36 37 37 57
2 Ack A 57 60 18 84
3 Eorge C 93 96 71 78
4 Oah D 65 49 61 86

分组对象具体是什么

# 创建分组对象
grouped = df.groupby('team')

# 可将grouped看成一个DataFrame,指定‘team’为分组索引,可进行迭代
for i in grouped:
    print(i)
    break # 只输出一层
('A',        name team  Q1  Q2  Q3  Q4
2       Ack    A  57  60  18  84
7      Lfie    A   9  10  99  37
9     Oscar    A  77   9  26  67
16   Joshua    A  63   4  80  30
17    Henry    A  91  15  75  17
20    Lucas    A  60  41  77  62
22   Arthur    A  44  53  42  40
34  Reggie1    A  30  12  23   9
40     Toby    A  52  27  17  68
42    Dylan    A  86  87  65  20
51    Hugo0    A  28  25  14  71
67    Caleb    A  64  34  46  88
70   Nathan    A  87  77  62  13
71    Blake    A  78  23  93   9
75  Stanley    A  69  71  39  97
79    Tyler    A  75  16  44  63
88    Aaron    A  96  75  55   8)
# 获取A组,是一个DataFrame
grouped.get_group('A')
name team Q1 Q2 Q3 Q4
2 Ack A 57 60 18 84
7 Lfie A 9 10 99 37
9 Oscar A 77 9 26 67
16 Joshua A 63 4 80 30
17 Henry A 91 15 75 17
20 Lucas A 60 41 77 62
22 Arthur A 44 53 42 40
34 Reggie1 A 30 12 23 9
40 Toby A 52 27 17 68
42 Dylan A 86 87 65 20
51 Hugo0 A 28 25 14 71
67 Caleb A 64 34 46 88
70 Nathan A 87 77 62 13
71 Blake A 78 23 93 9
75 Stanley A 69 71 39 97
79 Tyler A 75 16 44 63
88 Aaron A 96 75 55 8
# 将grouped看成一个DataFrame,取Q1列进行求和(分组求和)
print(grouped['Q1'].sum())  # 取出来是一个Series
grouped[['Q1']].sum() # 取出来是一个DataFrame
team
A    1066
B     975
C    1056
D     860
E     963
Name: Q1, dtype: int64
Q1
team
A 1066
B 975
C 1056
D 860
E 963
# 只有数值字段参与求和运算
df.groupby('team').sum() 
Q1 Q2 Q3 Q4
team
A 1066 639 875 783
B 975 1218 1202 1136
C 1056 1194 1068 1127
D 860 1191 1241 1199
E 963 1013 881 1033

取消分组索引

# 默认以分组标签作为索引,也可取消索引
df.groupby('team', as_index=False).sum() 
team Q1 Q2 Q3 Q4
0 A 1066 639 875 783
1 B 975 1218 1202 1136
2 C 1056 1194 1068 1127
3 D 860 1191 1241 1199
4 E 963 1013 881 1033
df.groupby('team', as_index=False).team.count()
team
0 17
1 22
2 22
3 19
4 20

对不同列使用不同的计算方法

df.groupby('team', as_index=False).agg({
    'Q1':sum,
    'Q2':'count',
    'Q3':'mean',
    'Q4':max
})
team Q1 Q2 Q3 Q4
0 A 1066 17 51.470588 97
1 B 975 22 54.636364 99
2 C 1056 22 48.545455 98
3 D 860 19 65.315789 99
4 E 963 20 44.050000 98
# 对同一列使用不同的计算方法
df.groupby('team').agg({'Q1':[sum,'count','std',max]})
Q1
sum count std max
team
A 1066 17 24.155136 96
B 975 22 32.607896 97
C 1056 22 31.000768 98
D 860 19 25.886166 80
E 963 20 33.242767 97
# agg方法无法实现同一列的不同计算方法
df.groupby('team', as_index=False).agg({
    'Q1':sum,
    'Q1':'count',
    'Q1':'std',
    'Q1':max
})
team Q1
0 A 96
1 B 97
2 C 98
3 D 80
4 E 97
# 分组对象使用apply()调用一个函数(此处调用lambda函数,并传入一个Series映射),传入apply()的是DataFrame
df.groupby('team', as_index=False).apply(lambda x: pd.Series({
    'Q1_sum': x['Q1'].sum(),
    'Q1_count': x['Q1'].count(),
    'Q1_std': x['Q1'].std(),
    'Q1_max': x['Q1'].max()
})) 
team Q1_sum Q1_count Q1_std Q1_max
0 A 1066.0 17.0 24.155136 96.0
1 B 975.0 22.0 32.607896 97.0
2 C 1056.0 22.0 31.000768 98.0
3 D 860.0 19.0 25.886166 80.0
4 E 963.0 20.0 33.242767 97.0

以表达式、函数进行分组

# 索引值是否为偶数,分成两组
df.groupby(lambda x: x%2==0).sum() # 以默认的索引进行分组
df.groupby(df.index%2==0).sum() # 也可指定分组索引
Q1 Q2 Q3 Q4
False 2322 2449 2823 2699
True 2598 2806 2444 2579
# 列名包含Q的分为一组
df.groupby(lambda x: 'Q' in x, axis=1).sum() #字符串求和等于拼接
False True
0 LiverE 198
1 ArryC 167
2 AckA 219
3 EorgeC 338
4 OahD 261
... ... ...
95 GabrielC 268
96 Austin7C 125
97 Lincoln4C 212
98 EliE 234
99 BenE 179

100 rows × 2 columns

# 按姓名首字母为元音、辅音分组
def get_letter_type(letter):
    if letter[0].lower() in 'aeiou':
        return '元音'
    else:
        return '辅音'
    
# 使用上述函数进行分组
df.set_index('name').groupby(get_letter_type).sum()
Q1 Q2 Q3 Q4
元音 1462 1440 1410 1574
辅音 3458 3815 3857 3704
# 指定多个分组索引
df.groupby(['team', df.name.apply(get_letter_type)]).sum()
Q1 Q2 Q3 Q4
team name
A 元音 274 197 141 199
辅音 792 442 734 584
B 元音 309 291 269 218
辅音 666 927 933 918
C 元音 473 488 453 464
辅音 583 706 615 663
D 元音 273 333 409 486
辅音 587 858 832 713
E 元音 133 131 138 207
辅音 830 882 743 826

将分组中的一列输出为列表

# 创建示例数据
tmp = pd.DataFrame({'team':['A','A','A','B','B','B'],'name':['Eric','Eric','Tony','Tony','Tom','Tom',]})
tmp
team name
0 A Eric
1 A Eric
2 A Tony
3 B Tony
4 B Tom
5 B Tom
tmp.groupby('team').apply(lambda x: x['name'].to_list())
team
A    [Eric, Eric, Tony]
B      [Tony, Tom, Tom]
dtype: object
# 去重后输出列表:unique
pd.DataFrame(tmp.groupby('team')['name'].unique()).rename(columns={'name':'agg_name'})
agg_name
team
A [Eric, Tony]
B [Tony, Tom]
# 去重后输出列表长度:nunique
pd.DataFrame(tmp.groupby('team')['name'].nunique()).rename(columns={'name':'num'})
num
team
A 2
B 2
# 使用apply() 合并输出上述2个结果
tmp.groupby('team', as_index=False).apply(lambda x: pd.Series({
    'agg_name': x['name'].unique(),
    'num': x['name'].nunique()
}))
team agg_name num
0 A [Eric, Tony] 2
1 B [Tony, Tom] 2

窗口函数

df['Q1_mean'] = df.groupby('team')['Q1'].transform('mean')
df.sort_values(by='team', ascending=False)
name team Q1 Q2 Q3 Q4 Q1_mean Q1_size
0 Liver E 89 21 24 64 48.150000 20
19 Max E 97 75 41 3 48.150000 20
26 Teddy E 71 91 21 48 48.150000 20
29 Riley E 35 26 59 83 48.150000 20
31 Joseph E 67 87 87 93 48.150000 20
... ... ... ... ... ... ... ... ...
34 Reggie1 A 30 12 23 9 62.705882 17
70 Nathan A 87 77 62 13 62.705882 17
79 Tyler A 75 16 44 63 62.705882 17
71 Blake A 78 23 93 9 62.705882 17
51 Hugo0 A 28 25 14 71 62.705882 17

100 rows × 8 columns

df['Q1_size'] = df.groupby('team')['Q1'].transform('count')
df.sort_values(by='team', ascending=False)
name team Q1 Q2 Q3 Q4 Q1_mean Q1_size
0 Liver E 89 21 24 64 48.150000 20
19 Max E 97 75 41 3 48.150000 20
26 Teddy E 71 91 21 48 48.150000 20
29 Riley E 35 26 59 83 48.150000 20
31 Joseph E 67 87 87 93 48.150000 20
... ... ... ... ... ... ... ... ...
34 Reggie1 A 30 12 23 9 62.705882 17
70 Nathan A 87 77 62 13 62.705882 17
79 Tyler A 75 16 44 63 62.705882 17
71 Blake A 78 23 93 9 62.705882 17
51 Hugo0 A 28 25 14 71 62.705882 17

100 rows × 8 columns