import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from numpy import nan as NA
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
df1=DataFrame(
{
'key1':list('aabba'),
'key2':'one,two,one,two,one'.split(','),
'data1':np.random.randint(0,10,5),
'data2':np.random.randint(0,10,5)
}
)
df1
key1 key2 data1 data2
0 a one 7 2
1 a two 4 5
2 b one 3 7
3 b two 9 8
4 a one 1 2
s1=df1['data1']
Series.groupby
按照某个series 进行分组,返回一个分组后的对象
s1.groupby(df1['key1'])
<pandas.core.groupby.generic.SeriesGroupBy object at 0x0000017FF3763F28>
# 可以用list()转换,查看结构,可以知道分组对象的每个值都是分组依据和分组结果
list(s1.groupby(df1.key1))
[('a',
0 7
1 4
4 1
Name: data1, dtype: int32),
('b',
2 3
3 9
Name: data1, dtype: int32)]
我们的分组对象是可以直接使用聚合(统计)函数
s1.groupby(df1.key1).sum()
key1
a 12
b 12
Name: data1, dtype: int32
s1.groupby(df1.key1).mean()
key1
a 4
b 6
Name: data1, dtype: int32
s1.groupby(df1.key1).count()
key1
a 3
b 2
Name: data1, dtype: int64
DataFrame.groupby
df1
key1 key2 data1 data2
0 a one 7 2
1 a two 4 5
2 b one 3 7
3 b two 9 8
4 a one 1 2
# 用匹配的值
df1.groupby(df1.key2)
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000017FF379FEB8>
list(df1.groupby(df1.key2))
[('one',
key1 key2 data1 data2
0 a one 7 2
2 b one 3 7
4 a one 1 2),
('two',
key1 key2 data1 data2
1 a two 4 5
3 b two 9 8)]
# 如果分组依据来自本身的某列,直接用列名称
df1.groupby('key2')
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000017FF37B5668>
# 可以用其他独立的Series进行分组
df1.groupby(Series(['c','c','d','d','d']))
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000017FF37B5EF0>
list(df1.groupby(Series(['c','c','d','d','d'])))
[('c',
key1 key2 data1 data2
0 a one 7 2
1 a two 4 5),
('d',
key1 key2 data1 data2
2 b one 3 7
3 b two 9 8
4 a one 1 2)]
# 可以直接使用聚合函数
df1.groupby(Series(['c','c','d','d','d'])).sum()
data1 data2
c 11 7
d 13 17
df1.groupby(Series(['c','c','d','d','d'])).max()
key1 key2 data1 data2
c a two 7 5
d b two 9 8
使用多个依据进行分组
DataFrame.groupby([Series1,Series2,…])
如果Series(mapper)来源本身,可以直接使用列名称
DataFrame.groupby([columnName1,columnName2,…])
df1.groupby([df1.key1,df1.key2])
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000017FF37C3A58>
list(df1.groupby([df1.key1,df1.key2]))
[(('a', 'one'),
key1 key2 data1 data2
0 a one 7 2
4 a one 1 2),
(('a', 'two'),
key1 key2 data1 data2
1 a two 4 5),
(('b', 'one'),
key1 key2 data1 data2
2 b one 3 7),
(('b', 'two'),
key1 key2 data1 data2
3 b two 9 8)]
list(df1.groupby(['key1','key2']))
[(('a', 'one'),
key1 key2 data1 data2
0 a one 7 2
4 a one 1 2),
(('a', 'two'),
key1 key2 data1 data2
1 a two 4 5),
(('b', 'one'),
key1 key2 data1 data2
2 b one 3 7),
(('b', 'two'),
key1 key2 data1 data2
3 b two 9 8)]
df1.groupby(['key1','key2']).sum()
data1 data2
key1 key2
a one 8 4
two 4 5
b one 3 7
two 9 8
# 假设有很多列,只需要一两列进行分组与计算
df2=DataFrame(
np.random.randint(0,10,(10,10)),
columns=list('ABCDEFGHIJ')
)
df2.insert(0,'key2','one,two,one,two,one'.split(',')*2)
df2.insert(0,'key1',list('aabbc')*2)
df2
key1 key2 A B C D E F G H I J
0 a one 4 4 7 9 6 5 0 8 2 5
1 a two 8 5 1 9 6 1 5 5 4 5
2 b one 7 7 5 9 9 9 7 5 8 6
3 b two 9 9 2 0 9 0 9 2 3 6
4 c one 2 9 8 3 1 6 1 5 6 5
5 a one 8 6 4 7 5 7 7 8 8 4
6 a two 4 3 8 7 3 4 8 2 2 6
7 b one 3 0 0 0 9 7 8 3 0 3
8 b two 9 7 4 3 5 2 1 7 1 4
9 c one 6 8 1 6 1 6 9 6 1 5
如果需要分组计算的列不是很多
1.整体分组计算,然后取需要的列得到结果
2.先取需要的列,在进行分组计算
df2.groupby(['key1','key2']).sum()
A B C D E F G H I J
key1 key2
a one 12 10 11 16 11 12 7 16 10 9
two 12 8 9 16 9 5 13 7 6 11
b one 10 7 5 9 18 16 15 8 8 9
two 18 16 6 3 14 2 10 9 4 10
c one 8 17 9 9 2 12 10 11 7 10
# 方法1
df2.groupby(['key1','key2']).sum()[['A','B']]
A B
key1 key2
a one 12 10
two 12 8
b one 10 7
two 18 16
c one 8 17
# 方法2
df2[['A','B']].groupby([df2.key1,df2.key2]).sum()
A B
key1 key2
a one 12 10
two 12 8
b one 10 7
two 18 16
c one 8 17
# 如果取得时候包含相关列,就可以直接使用列名称
df2[['key1','key2','A','B']].groupby(['key1','key2']).sum()
A B
key1 key2
a one 12 10
two 12 8
b one 10 7
two 18 16
c one 8 17
gg=list(df2[['key1','key2','A','B']].groupby(['key1','key2']))
for each in gg:
if each[0]==('b','two'):
num1=gg.index(each)
num1
3
gg[num1]
(('b', 'two'),
key1 key2 A B
3 b two 9 9
8 b two 9 7)
我们分组对象,还可以转为列表后转为字典
dict(gg)
{('a',
'one'): key1 key2 A B
0 a one 4 4
5 a one 8 6,
('a',
'two'): key1 key2 A B
1 a two 8 5
6 a two 4 3,
('b',
'one'): key1 key2 A B
2 b one 7 7
7 b one 3 0,
('b',
'two'): key1 key2 A B
3 b two 9 9
8 b two 9 7,
('c',
'one'): key1 key2 A B
4 c one 2 9
9 c one 6 8}
dict(gg).get(('b','two'))
key1 key2 A B
3 b two 9 9
8 b two 9 7
# 查看df1的列类型
df1.dtypes
key1 object
key2 object
data1 int32
data2 int32
dtype: object
# 使用列类型进行分组
df1.groupby(df1.dtypes,axis=1)
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000017FF380B208>
list(df1.groupby(df1.dtypes,axis=1))
[(dtype('int32'),
data1 data2
0 7 2
1 4 5
2 3 7
3 9 8
4 1 2),
(dtype('O'),
key1 key2
0 a one
1 a two
2 b one
3 b two
4 a one)]
xxx.astype(yy) xxx对象的值转为yy类型
df1.data2.astype(float)
0 2.0
1 5.0
2 7.0
3 8.0
4 2.0
Name: data2, dtype: float64
df1['data3']=df1.data2.astype(float)
df1
key1 key2 data1 data2 data3
0 a one 7 2 2.0
1 a two 4 5 5.0
2 b one 3 7 7.0
3 b two 9 8 8.0
4 a one 1 2 2.0
list(df1.groupby(df1.dtypes,axis=1))
[(dtype('int32'),
data1 data2
0 7 2
1 4 5
2 3 7
3 9 8
4 1 2),
(dtype('float64'),
data3
0 2.0
1 5.0
2 7.0
3 8.0
4 2.0),
(dtype('O'),
key1 key2
0 a one
1 a two
2 b one
3 b two
4 a one)]
df1.insert(len(df1.columns),'data4',list('aabbc'))
df1
key1 key2 data1 data2 data3 data4
0 a one 7 2 2.0 a
1 a two 4 5 5.0 a
2 b one 3 7 7.0 b
3 b two 9 8 8.0 b
4 a one 1 2 2.0 c
可以按照一列或多列进行分组
# 如 key1 就是一列 的值 其实是按行分
# 如 key1,key2 就是两列 其实是按行分
# 按列分组, 如:按照类型分 dtype,axis=1
# 读取 成绩.csv 前十个人的信息,姓名作为行索引,学科作为列索引
data=pd.read_csv('成绩.csv',index_col='Unnamed: 0')
# 预览前5条 xxx.head()
data.head(8)
语文 数学 英语 化学 物理 生物 政治 历史 地理
赵大 97 90 68 86 73 94 70 70 72
孙兄 91 99 86 89 68 96 70 82 60
钱术 95 87 87 67 99 88 85 65 95
吴羊 92 98 94 64 96 82 65 85 69
王女 91 84 84 88 92 75 82 97 91
王卜 94 89 90 99 95 99 67 82 82
王可 94 90 76 68 93 82 93 99 83
钱巾 97 85 92 81 71 85 90 60 65
我们可以使用字典分组
如:用字典给每列取一个别名,如果语数外为主科,其他为副科
创建2个字典再组合成二维列表,再转为字典
方法1
dict1=dict.fromkeys(data.columns[:3],'主科')
dict2=dict.fromkeys(data.columns[3:],'副科')
list_1=[]
for each in dict1:
list_1.append([each,dict1[each]])
for each in dict2:
list_1.append([each,dict2[each]])
list_1
[['语文', '主科'],
['数学', '主科'],
['英语', '主科'],
['化学', '副科'],
['物理', '副科'],
['生物', '副科'],
['政治', '副科'],
['历史', '副科'],
['地理', '副科']]
dict(list_1)
{'语文': '主科',
'数学': '主科',
'英语': '主科',
'化学': '副科',
'物理': '副科',
'生物': '副科',
'政治': '副科',
'历史': '副科',
'地理': '副科'}
方法2:直接循环
list_2=[]
for index,value in enumerate(data.columns):
if index<3:
list_2.append([value,'主科'])
else:
list_2.append([value,'副科'])
list_2
[['语文', '主科'],
['数学', '主科'],
['英语', '主科'],
['化学', '副科'],
['物理', '副科'],
['生物', '副科'],
['政治', '副科'],
['历史', '副科'],
['地理', '副科']]
a=['a','b','c']
for i in range(len(a)):
print(i,a[i])
0 a
1 b
2 c
for index,value in enumerate(a):
print(index,value)
0 a
1 b
2 c
方法3
dict1
{'语文': '主科', '数学': '主科', '英语': '主科'}
dict2
{'化学': '副科', '物理': '副科', '生物': '副科', '政治': '副科', '历史': '副科', '地理': '副科'}
# 将两个字典变成字符串,第一个字典不要后面的},第二个字典不要前面的{,
# 中间用字符串‘,’连接,最后将整体用eval转成整数变成了一个字典
mapping=eval(str(dict1)[:-1]+','+str(dict2)[1:])
# 分组使用主副科分组
data.groupby(mapping,axis=1)
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000017FFC0B72E8>
data.groupby(mapping,axis=1).sum()
主科 副科
赵大 255 465
孙兄 276 465
钱术 269 499
吴羊 284 461
王女 259 525
王卜 273 524
王可 260 518
钱巾 274 452
李丁 270 481
吴丫 243 478
吴丑 266 511
钱火 266 465
王石 248 487
李人 246 511
郑正 256 435
王乃 249 475
李寸 247 478
郑之 289 437
钱口 274 417
孙寸 247 508
吴儿 254 507
李木 245 512
赵主 258 455
钱巨 287 516
郑电 257 516
赵工 245 524
李方 259 473
李门 243 463
李几 248 469
赵夫 256 504
吴井 267 474
郑天 273 521
孙计 254 439
郑尺 276 515
孙友 268 493
郑中 265 439
赵页 258 455
郑户 247 493
王了 242 511
赵爪 272 503
吴又 269 427
钱化 248 522
吴不 252 518
吴伏 241 470
王贝 260 472
李气 268 413
李田 265 452
李下 244 442
李匕 268 521
李心 283 457
# 每个分类有几个
data.groupby(mapping,axis=1).size()
主科 3
副科 6
dtype: int64
#使用Series 作为分组对象
map_series=Series(mapping)
map_series
语文 主科
数学 主科
英语 主科
化学 副科
物理 副科
生物 副科
政治 副科
历史 副科
地理 副科
dtype: object
data.groupby(map_series,axis=1).sum()
主科 副科
赵大 255 465
孙兄 276 465
钱术 269 499
吴羊 284 461
王女 259 525
王卜 273 524
王可 260 518
钱巾 274 452
李丁 270 481
吴丫 243 478
吴丑 266 511
钱火 266 465
王石 248 487
李人 246 511
郑正 256 435
王乃 249 475
李寸 247 478
郑之 289 437
钱口 274 417
孙寸 247 508
吴儿 254 507
李木 245 512
赵主 258 455
钱巨 287 516
郑电 257 516
赵工 245 524
李方 259 473
李门 243 463
李几 248 469
赵夫 256 504
吴井 267 474
郑天 273 521
孙计 254 439
郑尺 276 515
孙友 268 493
郑中 265 439
赵页 258 455
郑户 247 493
王了 242 511
赵爪 272 503
吴又 269 427
钱化 248 522
吴不 252 518
吴伏 241 470
王贝 260 472
李气 268 413
李田 265 452
李下 244 442
李匕 268 521
李心 283 457
# 直接创建Series使用列索引 变行索引,被转换的value就是分组依据
map_series2=Series(['主科']*3+['副科']*6,index=data.columns)
# 分组对象可以直接describe
data.groupby(map_series2,axis=1).describe()
count mean std min 25% 50% 75% max
主科 语文 50.0 94.26 2.947223 90.0 91.00 94.0 96.75 99.0
数学 50.0 88.98 6.192458 80.0 83.25 89.0 95.00 99.0
英语 50.0 77.22 11.775606 60.0 68.00 75.0 86.75 98.0
副科 化学 50.0 80.52 11.664074 60.0 71.00 80.5 89.75 99.0
物理 50.0 80.36 10.912939 62.0 71.00 79.0 89.75 99.0
生物 50.0 83.24 11.626079 60.0 72.00 85.0 92.75 99.0
政治 50.0 78.08 11.593172 60.0 69.00 79.0 88.00 98.0
历史 50.0 81.56 12.266031 60.0 71.75 82.0 93.75 99.0
地理 50.0 77.60 11.261276 60.0 68.25 76.0 87.00 99.0
其他聚合函数
# 假设有很多列,只需要一两列进行分组与计算。
df3 = DataFrame(
np.random.randint(0,10,(10,3)),
columns=list('ABC')
)
df3.insert(0,'key2','one,two,one,two,one'.split(',')*2)
df3.insert(0,'key1',list('aabbc')*2)
df3.groupby(['key1','key2']).sum()
A B C
key1 key2
a one 17 11 15
two 16 8 1
b one 17 3 10
two 9 6 8
c one 11 7 9
df3.groupby(['key1','key2']).max()
A B C
key1 key2
a one 9 7 9
two 9 7 1
b one 9 3 6
two 5 5 8
c one 9 5 6
df3.groupby(['key1','key2']).describe()
A B C
count mean std min 25% 50% 75% max count mean ... 75% max count mean std min 25% 50% 75% max
key1 key2
a one 2.0 8.5 0.707107 8.0 8.25 8.5 8.75 9.0 2.0 5.5 ... 6.25 7.0 2.0 7.5 2.121320 6.0 6.75 7.5 8.25 9.0
two 2.0 8.0 1.414214 7.0 7.50 8.0 8.50 9.0 2.0 4.0 ... 5.50 7.0 2.0 0.5 0.707107 0.0 0.25 0.5 0.75 1.0
b one 2.0 8.5 0.707107 8.0 8.25 8.5 8.75 9.0 2.0 1.5 ... 2.25 3.0 2.0 5.0 1.414214 4.0 4.50 5.0 5.50 6.0
two 2.0 4.5 0.707107 4.0 4.25 4.5 4.75 5.0 2.0 3.0 ... 4.00 5.0 2.0 4.0 5.656854 0.0 2.00 4.0 6.00 8.0
c one 2.0 5.5 4.949747 2.0 3.75 5.5 7.25 9.0 2.0 3.5 ... 4.25 5.0 2.0 4.5 2.121320 3.0 3.75 4.5 5.25 6.0
5 rows × 24 columns
df4 = DataFrame({
'key1':list('aabbabaa')*2,
'key2':'one/two/one/three/two/two/one/one'.split('/')*2,
'data1': np.random.randint(1,100,16),
'data2': np.random.randint(1,100,16)
})
df4
key1 key2 data1 data2
0 a one 32 37
1 a two 3 90
2 b one 75 38
3 b three 83 47
4 a two 16 94
5 b two 30 52
6 a one 7 51
7 a one 98 99
8 a one 63 58
9 a two 36 81
10 b one 63 54
11 b three 54 72
12 a two 26 79
13 b two 65 83
14 a one 50 60
15 a one 5 94
df4.groupby(['key1','key2']).size()
key1 key2
a one 6
two 4
b one 2
three 2
two 2
dtype: int64
自定义函数应用到 对象上
xxx.agg([funcName,fun1,fun2,fun3,…]) 可以是一个或多个函数
如果是Python中的常用函数,直接传 字符串形式的函数名进去 如 ‘sum’ ,‘mean’
如果是自定义的函数或者nump的函数,用函数名称 my_ptp , np.ptp
# 定义一个极差函数
def my_ptp(x):
return x.max()-x.min()
# 应用到分组对象
df4.groupby(['key1','key2']).agg(my_ptp)
data1 data2
key1 key2
a one 93 62
two 33 15
b one 12 16
three 29 25
two 35 31
# 也可以直接使用np.ptp极差函数
df4.groupby(['key1','key2']).agg(np.ptp)
data1 data2
key1 key2
a one 93 62
two 33 15
b one 12 16
three 29 25
two 35 31
df4.groupby(['key1','key2']).agg(['mean','std','count',my_ptp])
data1 data2
mean std count my_ptp mean std count my_ptp
key1 key2
a one 42.50 35.590729 6 93 66.5 24.647515 6 62
two 20.25 14.103782 4 33 86.0 7.164728 4 15
b one 69.00 8.485281 2 12 46.0 11.313708 2 16
three 68.50 20.506097 2 29 59.5 17.677670 2 25
two 47.50 24.748737 2 35 67.5 21.920310 2 31
# 可以给这些聚合函数取别名 .agg(['显示名':'函数名'])
df4.groupby(['key1','key2']).agg([('平均值','mean'),('标准值','std'),('计数','count'),('极差',np.ptp)])
data1 data2
平均值 标准值 计数 极差 平均值 标准值 计数 极差
key1 key2
a one 42.50 35.590729 6 93 66.5 24.647515 6 62
two 20.25 14.103782 4 33 86.0 7.164728 4 15
b one 69.00 8.485281 2 12 46.0 11.313708 2 16
three 68.50 20.506097 2 29 59.5 17.677670 2 25
two 47.50 24.748737 2 35 67.5 21.920310 2 31
还可以不同列数 ,使用不同的聚合函数
dict_map={
'data1':['max','min','sum'],
'data2':[('极差ptp',np.ptp),('方差var','var'),('标准差std','std')]
}
df4.groupby(['key1','key2']).agg(dict_map)
data1 data2
max min sum 极差ptp 方差var 标准差std
key1 key2
a one 98 5 255 62 607.500000 24.647515
two 36 3 81 15 51.333333 7.164728
b one 75 63 138 16 128.000000 11.313708
three 83 54 137 25 312.500000 17.677670
two 65 30 95 31 480.500000 21.920310
as_index=True.默认让分组依据作为行索引
df4.groupby(['key1','key2'],as_index=False).agg(dict_map)
key1 key2 data1 data2
max min sum 极差ptp 方差var 标准差std
0 a one 98 5 255 62 607.500000 24.647515
1 a two 36 3 81 15 51.333333 7.164728
2 b one 75 63 138 16 128.000000 11.313708
3 b three 83 54 137 25 312.500000 17.677670
4 b two 65 30 95 31 480.500000 21.920310