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 |
使用自定义计算函数
def fun(ls):
#组内差值10以内返回1,否则返回0
for i in range(len(ls)-1):
for j in range(i,len(ls)):
if abs(ls[i]-ls[j])>10:
continue
else:
return 1 #return为函数的结束标志
return 0
df.groupby('team', as_index=False).apply(lambda x: pd.Series({
'delta': fun(x['Q4'].tolist())
}))
# 计算各组Q1及格和不及格人员的熵值
def entropy(df):
s=df['Q1'].sum()
r1=df[df['Q1']>=60]['Q1'].sum()
r2=df[df['Q1']<60]['Q1'].sum()
return -(r1/s)*math.log((r1/s),2)-(r2/s)*math.log((r2/s),2)
df.groupby('team', as_index=False).apply(lambda x: pd.Series({
'entropy': entropy(x) # x为pandas.DataFrame对象
}))
以表达式、函数进行分组
# 索引值是否为偶数,分成两组
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'})
# 使用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
# 窗口函数 row_number()功能
def row_number(df, par_list, order_list, asc_list):
df['rn'] = 1
df.sort_values(by=par_list+order_list,
ascending=[True]*len(par_list)+asc_list,
inplace=True)
df['rn'] = df.groupby(par_list)['rn'].cumsum()
# 示例
row_number(df=df, par_list=['team'], order_list=['Q1','Q2'], asc_list=[True,False])