数据聚合与分组运算
分组与聚合的原理
- 分组:使用特定的条件将原数据划分为多个组
- 聚合:对每个分组中的数据执行某些操作(如聚合、转换等),最后将计算的结果进行整合
- 分组和聚合的步骤分为三步:
-
- 拆分:将数据集按照一些标准拆分成若干个组,拆分操作是在指定轴上进行的,既可以对横轴方向上的数据进行分组,也可以对纵轴上的数据进行分组
-
- 应用:将某个函数或方法应用到每个分组
-
- 合并:将产生的新值整合到结果对象中
通过gropby()方法将数据拆分成组
- df1.groupby(
by=None,
axis=0,
level=None,
as_index=True,
sort=True,
group_keys=True,
squeeze=False,
observed=False,
**kwargs,
)
- by=None:用于确定分组的依据
- axis:表示分组的轴的方向,可以为0或1,默认为0
- level:如果某个轴是一个MultiIndex对象,则会按照特定级别或多个级别分组
- as_index:表示聚合后的数据是否以组标签作为索引的DataFrame对象输出,接受布尔值,默认为True
- sort:表示是否对分组标签进行排序,接受布尔值,默认为True
- by参数接收的数据,也就是常见的分组方式有以下四种:
- 列表或数组,其长度必须与待分组的轴一样
- DataFrame对象中某列的名称
- 字典或者series对象,给出待分组轴上的值与分组名称之间的对应关系
- 函数,用于处理轴索引或索引中的各个标签
通过列名进行分组
- 在pandas对象中,如果他的某一列数据满足不同的划分标准,则可以将该列当作分组键来拆分数据集。
df1 = pd.DataFrame({'KEY':['C','B','C','A','B','B','A','C','A'],
'DATA':[2,4,6,8,10,1,14,16,18]})
df1
KEY DATA
0 C 2
1 B 4
2 C 6
3 A 8
4 B 10
5 B 1
6 A 14
7 C 16
8 A 18
gp = df1.groupby(by='KEY') #通过KEY进行分组
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x00000296D65FEB08>
for i in gp: # 通过groupby分组后的数据是DataFrameGroupBy类型,需要遍历
print(i)
('A', KEY DATA
3 A 8
6 A 14
8 A 18)
('B', KEY DATA
1 B 4
4 B 10
5 B 1)
('C', KEY DATA
0 C 2
2 C 6
7 C 16)
通过Series对象进行分组
- 当被拆分的对象没有相同列名时可以进行拆分可以创建一个series对象充当列名进行拆分
df = pd.DataFrame({'key1':['A','A','B','B','A'], #创建DF对象
'key2':['one','two','one','two','one'],
'data1':[2,3,4,6,8],
'data2':[3,5,6,3,7]})
df
key1 key2 data1 data2
0 A one 2 3
1 A two 3 5
2 B one 4 6
3 B two 6 3
4 A one 8 7
se = pd.Series(['a','b','c','a','b']) #创建Series对象
se
0 a
1 b
2 c
3 a
4 b
dtype: object
droup_obj = df.groupby(by=se) #通过by传入Series对象
for i in droup_obj:
print(i)
('a', key1 key2 data1 data2
0 A one 2 3
3 B two 6 3)
('b', key1 key2 data1 data2
1 A two 3 5
4 A one 8 7)
('c', key1 key2 data1 data2
2 B one 4 6)
通过字典进行分组
- 字典中的键名为自定义分组的列名,值为自定义分组名
num_df = pd.DataFrame({'a':[1,2,3,4,5],
'b':[6,7,8,9,10],
'c':[11,12,13,14,15],
'd':[5,4,3,2,1],
'e':[10,9,8,7,6]})
num_df
mapping = {'a':'第一组','b':'第二组','c':'第一组','d':'第三组','e':'第二组'}
mapping
{'a': '第一组', 'b': '第二组', 'c': '第一组', 'd': '第三组', 'e': '第二组'}
df_gr = num_df.groupby(by=mapping,axis=1)
for i in df_gr:
print(i)
('第一组', a c
0 1 11
1 2 12
2 3 13
3 4 14
4 5 15)
('第三组', d
0 5
1 4
2 3
3 2
4 1)
('第二组', b e
0 6 10
1 7 9
2 8 8
3 9 7
4 10 6)
通过函数进行分组
- 函数返回的结果为自定义分组的组名,列索引为原数据的列索引
df = pd.DataFrame({'a':[1,2,3,4,5],
'b':[6,7,8,9,10],
'c':[5,4,3,2,1]},
index=['sun','jack','alice','helen','job'])
df
a b c
sun 1 6 5
jack 2 7 4
alice 3 8 3
helen 4 9 2
job 5 10 1
df_g = df.groupby(len)
i
for i in df_g:
print(i)
(3, a b c
sun 1 6 5
job 5 10 1)
(4, a b c
jack 2 7 4)
(5, a b c
alice 3 8 3
helen 4 9 2)
数据聚合
使用内置统计方法聚合数据
- 使用内置方法应用到每个分组中,并进算出平均数,最后将每个分组的计算结果合并到一起
import numpy as np
df = pd.DataFrame({'key1':['A','A','B','B','A'],
'key2':['ONE','TWO','ONE','TWO','ONE'],
'data1':[2,3,4,6,8],
'data2':[3,5,np.nan,3,7]})
df
key1 key2 data1 data2
0 A ONE 2 3.0
1 A TWO 3 5.0
2 B ONE 4 NaN
3 B TWO 6 3.0
4 A ONE 8 7.0
i
for i in df.groupby('key1'):
print(i)
('A', key1 key2 data1 data2
0 A ONE 2 3.0
1 A TWO 3 5.0
4 A ONE 8 7.0)
('B', key1 key2 data1 data2
2 B ONE 4 NaN
3 B TWO 6 3.0)
df.groupby('key1').mean()
data1 data2
key1
A 4.333333 5.0
B 5.000000 3.0
面向列的聚合方法
- 当内置方法无法满足聚合要求时,这时可以自定义一个函数,将他传给agg()方法,实现对Series或DataFrame对象进行聚合运算。
- df.agg(func, axis=0, *args, **kwargs)
- func:表示用于汇总数据的函数,可以为单个函数或者函数列表
- axis:表示函数作用于轴的方向,0或index表示将函数应用到每一列,1或columns表示将函数应用到每一行,该参数默认为值为0
- 对每一列数据应用同一个函数
data_frame = pd.DataFrame(np.arange(36).reshape((6,6)),columns=list('abcdef'))
print(data_frame)
a b c d e f
0 0 1 2 3 4 5
1 6 7 8 9 10 11
2 12 13 14 15 16 17
3 18 19 20 21 22 23
4 24 25 26 27 28 29
5 30 31 32 33 34 35
data_frame['key'] = pd.Series(list('aaabbb'),name='key')
data_frame
a b c d e f key
0 0 1 2 3 4 5 a
1 6 7 8 9 10 11 a
2 12 13 14 15 16 17 a
3 18 19 20 21 22 23 b
4 24 25 26 27 28 29 b
5 30 31 32 33 34 35 b
_gr =
data_frame_gr = data_frame.groupby(by = 'key')
dict(x for x in data_frame_gr)['a']
dict(x for x in data_frame_gr)['a']
a b c d e f key
0 0 1 2 3 4 5 a
1 6 7 8 9 10 11 a
2 12 13 14 15 16 17 a
dict(x for x in data_frame_gr)['b']
a b c d e f key
3 18 19 20 21 22 23 b
4 24 25 26 27 28 29 b
5 30 31 32 33 34 35 b
data_frame_gr.agg(sum)
a b c d e f
key
a 18 21 24 27 30 33
b 72 75 78 81 84 87
- 对某列数据应用到不同的函数
def range_data_group(arr):
return arr.max()-arr.min()
data_frame_gr.agg([('极差',range_data_group),('和',sum)])
a b c d e f
极差 和 极差 和 极差 和 极差 和 极差 和 极差 和
key
a 12 18 12 21 12 24 12 27 12 30 12 33
b 12 72 12 75 12 78 12 81 12 84 12 87
- 对不同列应用不同函数
data_frame_gr.agg({'a':'sum','b':'mean','c':range_data_group})
a b c
key
a 18 7 12
b 72 25 12
分组级运算
数据转换
- 之前使用agg()方法进行聚合运算时,返回的数据集的形状与被分组数据集的形状是不同的,如果希望保持与原数据集形状相同,那么可以使用transfrom()方法实现,transfrom()方法的语法格式如下:
- transform(func,*args,**kwargs)
- func:表示操作pandas对象的函数,transform方法返回的结果有两种,一种是可以广播的标量值,另一种是与分组大小相同的结果数值。通过本方法操作分组时,会把函数应用到各个分组中,并且将结果返回到适当时位置上
df = pd.DataFrame({'a':[0,1,6,10,3],
'b':[1,2,7,11,4],
'c':[2,3,8,12,4],
'd':[3,4,9,13,5],
'e':[4,5,10,14,3],
'key':['A','A','B','B','B']})
df
a b c d e key
0 0 1 2 3 4 A
1 1 2 3 4 5 A
2 6 7 8 9 10 B
3 10 11 12 13 14 B
4 3 4 4 5 3 B
data_group = df.groupby('key').transform('mean')#分组求平均数
data_group
a b c d e
0 0.500000 1.500000 2.5 3.5 4.5
1 0.500000 1.500000 2.5 3.5 4.5
2 6.333333 7.333333 8.0 9.0 9.0
3 6.333333 7.333333 8.0 9.0 9.0
4 6.333333 7.333333 8.0 9.0 9.0
df = pd.DataFrame({'A':[2,3,3,4,2],
'B':[4,2,3,6,6],
'C':[9,7,0,7,8],
'D':[3,4,8,6,10]})
df
A B C D
0 2 4 9 3
1 3 2 7 4
2 3 3 0 8
3 4 6 7 6
4 2 6 8 10
key = ['one','one','two','two','two'] #传入key,使用key分组
df.groupby(key).transform('mean')
A B C D
0 2.5 3 8 3.5
1 2.5 3 8 3.5
2 3.0 5 5 8.0
3 3.0 5 5 8.0
4 3.0 5 5 8.0
##数据应用
*当有些分组操作,既不适合agg(),也不适合transform()方法,便可以使用apply()方法进行分组操做,它可以作用在每一行,每一列元素上,还可以在许多标准用例中替代聚合和转换
- apply(func,broadcast=None,raw=False,reduce=None,resul_type=None,args=(),**kwds)
- func:表示应用于某一行或某一列的函数
- axis:表示函数操作的轴向,'0’或’index’表示作用在列上,'1’或’columns’表示将函数应用于行上,默认为0
- broadcast:表示是否将数据进行广播,若设置为False或None,则会返回一个Series对象,其长度跟索引的长度或列数一样,若设置为True,则表示结果将被广播到原始对象中,原始的索引和列将被会保留
df = pd.DataFrame({'data1':[80,23,25,63,94,92,99,92,82,99],
'data2':[41,87,58,68,72,89,60,42,53,65],
'data3':[30,78,23,66,16,59,20,23,24,40],
'key':['b','a','a','b','b','a','b','a','a','a']})
df
data1 data2 data3 key
0 80 41 30 b
1 23 87 78 a
2 25 58 23 a
3 63 68 66 b
4 94 72 16 b
5 92 89 59 a
6 99 60 20 b
7 92 42 23 a
8 82 53 24 a
9 99 65 40 a
df_gr = df.groupby(by='key') #通过key分组
dict([x for x in df_gr])['b'] #将分组后的数据显现出来
data1 data2 data3 key
0 80 41 30 b
3 63 68 66 b
4 94 72 16 b
6 99 60 20 b
def add_10(arr): #创建元素加10的函数
return arr.iloc[:,:3]+10
df_gr.apply(add_10) #通过apply函数对所有元素进行+10处理
data1 data2 data3
0 90 51 40
1 33 97 88
2 35 68 33
3 73 78 76
4 104 82 26
5 102 99 69
6 109 70 30
7 102 52 33
8 92 63 34
9 109 75 50