pandas 分组统计 - groupby 详解

数据分组

分组统计 - groupby 功能

① 根据某些条件将数据拆分成组
② 对每个组独立应用函数
③ 将结果合并到一个数据结构中

Dataframe 在行(axis=0)或列(axis=1)上进行分组,将一个函数应用到各个分组并产生一个新值,然后函数执行结果被合并到最终的结果对象中。

df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)

注:因为输出结果冗长,请读者自行赋值粘贴到 jupyter(推荐)中运行。欢迎评论交流

分组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
df = pd.DataFrame({‘A’ : [‘foo’, ‘bar’, ‘foo’, ‘bar’,‘foo’, ‘bar’, ‘foo’, ‘foo’],
‘B’ : [‘one’, ‘one’, ‘two’, ‘three’, ‘two’, ‘two’, ‘one’, ‘three’],
‘C’ : np.random.randn(8),
‘D’ : np.random.randn(8)})
print(df)
print(‘——’)

print(df.groupby(‘A’), type(df.groupby(‘A’)))
print(‘——’)

直接分组得到一个 groupby 对象,是一个中间数据,没有进行计算

a = df.groupby(‘A’).mean()
b = df.groupby([‘A’,‘B’]).mean()
c = df.groupby([‘A’])[‘D’].mean() # 以 A 分组,算 D 的平均值
print(“—————–”)
print(a,type(a),‘\n’,a.columns)
print()
print(b,type(b),‘\n’,b.columns)
print()
print(c,type(c))

通过分组后的计算,得到一个新的 dataframe

默认 axis = 0,以行来分组

可单个或多个([])列分组
#按 A 列分组求出 A,B 列的个数

grouped = df.groupby([“A”])
n = grouped.agg({“A”: [“count”, pd.Series.unique], “B”: pd.Series.nunique})
print(n)
  

分组 - 可迭代对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
df = pd.DataFrame({‘X’ : [‘A’, ‘B’, ‘A’, ‘B’], ‘Y’ : [1, 4, 3, 2]})
print(df)
print(df.groupby(‘X’), type(df.groupby(‘X’)))
print(‘—–’)

print(list(df.groupby(‘X’)), ‘→ 可迭代对象,直接生成 list\n’)
print(list(df.groupby(‘X’))[0], ‘→ 以元祖形式显示 \n’)
for n,g in df.groupby(‘X’):
print(n)
print(g)
print(‘###’)
print(‘—–’)

n 是组名,g 是分组后的 Dataframe

print(df.groupby([‘X’]).get_group(‘A’),‘\n’)
print(df.groupby([‘X’]).get_group(‘B’),‘\n’)
print(‘—–’)

.get_group() 提取分组后的组

grouped = df.groupby([‘X’])
print(grouped.groups)
print(grouped.groups[‘A’]) # 也可写:df.groupby(‘X’).groups[‘A’]
print(‘—–’)

.groups:将分组后的 groups 转为 dict

可以字典索引方法来查看 groups 里的元素

sz = grouped.size()
print(sz,type(sz))
print(‘—–’)

.size():查看分组后的长度

df = pd.DataFrame({‘A’ : [‘foo’, ‘bar’, ‘foo’, ‘bar’,‘foo’, ‘bar’, ‘foo’, ‘foo’],
‘B’ : [‘one’, ‘one’, ‘two’, ‘three’, ‘two’, ‘two’, ‘one’, ‘three’],
‘C’ : np.random.randn(8),
‘D’ : np.random.randn(8)})
print(df)
print()
print(df.groupby([‘A’,‘B’]))
print()
grouped = df.groupby([‘A’,‘B’]).groups

print(grouped)
print()
print(grouped[(‘foo’, ‘three’)])

按照两个列进行分组

  

其他轴上的分组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import numpy as np

df = pd.DataFrame({‘data1’:np.random.rand(2),
‘data2’:np.random.rand(2),
‘key1’:[‘a’,‘b’],
‘key2’:[‘one’,‘two’]})
print(df)
print(df.dtypes)
print(“————-”)
print(df.groupby(df.dtypes, axis=1))
print(‘—–’)
print(list(df.groupby(df.dtypes, axis=1)))
print()
for n,p in df.groupby(df.dtypes, axis=1):
print(n)
print()
print(p)
print(‘##’)

按照值类型分列

  

通过字典或者 Series 分组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
df = pd.DataFrame(np.arange(16).reshape(4,4),
columns = [‘a’,‘b’,‘c’,‘d’])
print(df)
print(‘—–’)

mapping = {‘a’:‘one’,‘b’:‘one’,‘c’:‘two’,‘d’:‘two’,‘e’:‘three’}
by_column = df.groupby(mapping, axis = 1)
print(by_column.sum())
print(‘—–’)

mapping 中,a、b 列对应的为 one,c、d 列对应的为 two,以字典来分组

s = pd.Series(mapping)
print(s,‘\n’)
print(s.groupby(s).count())

s 中,index 中 a、b 对应的为 one,c、d 对应的为 two,以 Series 来分组

  

通过函数分组
1
2
3
4
5
6
df = pd.DataFrame(np.arange(16).reshape(4,4),
columns = [‘a’,‘b’,‘c’,‘d’],
index = [‘abc’,‘bcd’,‘aa’,‘b’])
print(df,‘\n’)
print(df.groupby(len).sum())

按照字母长度分组

  

分组计算函数方法
1
2
3
4
5
6
7
8
9
10
11
12
s = pd.Series([1, 2, 3, 10, 20, 30], index = [1, 2, 3, 1, 2, 3])
grouped = s.groupby(level=0) # 唯一索引用.groupby(level=0),将同一个 index 的分为一组
print(grouped)
print(grouped.first(),‘→ first:非 NaN 的第一个值 \n’)
print(grouped.last(),‘→ last:非 NaN 的最后一个值 \n’)
print(grouped.sum(),‘→ sum:非 NaN 的和 \n’)
print(grouped.mean(),‘→ mean:非 NaN 的平均值 \n’)
print(grouped.median(),‘→ median:非 NaN 的算术中位数 \n’)
print(grouped.count(),‘→ count:非 NaN 的值 \n’)
print(grouped.min(),‘→ min、max:非 NaN 的最小值、最大值 \n’)
print(grouped.std(),‘→ std,var:非 NaN 的标准差和方差 \n’)
print(grouped.prod(),‘→ prod:非 NaN 的积 \n’)
  

多函数计算:agg()
1
2
3
4
5
6
7
8
9
10
df = pd.DataFrame({‘a’:[1,1,2,2],
‘b’:np.random.rand(4),
‘c’:np.random.rand(4),
‘d’:np.random.rand(4),})
print(df)
print(df.groupby(‘a’).agg([‘mean’,np.sum]))
print(df.groupby(‘a’)[‘b’].agg({‘result1’:np.mean,
‘result2’:np.sum}))

函数写法可以用 str,或者 np. 方法

可以通过 list,dict 传入,当用 dict 时,key 名为 columns

  

下面是一个测试题,大家可以尝试一下
按要求创建 Dataframe df(如下图),并通过分组得到以下结果
① 以 A 分组,求出 C,D 的分组平均值
② 以 A,B 分组,求出 D,E 的分组求和
③ 以 A 分组,得到所有分组,以字典显示
④ 按照数值类型分组,求和
⑤ 将 C,D 作为一组分出来,并计算求和
⑥ 以 B 分组,求出每组的均值,求和,最大值,最小值

创建的 Dataframe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import pandas as pd
import numpy as np

df = pd.DataFrame({“A”:[“one”,“two”,“three”,“one”,“two”,“three”,“one”,“two”],
“B”:(list(“hhhh”) + list(“ffff”)),
“C”:range(10,26,2),
“D”:np.random.randn(8),
“E”:np.random.rand(8)
})
print(df)
print(“———- 以 A 分组,求出 CD 的分组平均值————-”)
print(df.groupby([“A”], axis = 0)[“C”,“D”])
df1 = df.groupby([“A”], axis = 0)[“C”,“D”].mean() # 先聚合
print(df1)
print(“———–以 AB 分组,求 DE 的分组和——–”)
df2 = df.groupby([“A”, “B”], axis = 0)[“D”,“E”].sum() # 先聚合
print(df2)
print(“———–以 A 分组,得到所有分组的字典——–”)
df2 = df.groupby([“A”], axis = 0)
print(df2.groups)
print(“按照数值类型分组,求和”)
df3 = df.groupby(df.dtypes, axis = 1).sum()
print(df3)
print(“———- 将 CD 作为一组分出来,并计算求和———–”)
mapping = {“C”:“one”, “D”:“one”}
print(df.groupby(mapping, axis = 1).sum())
print(“————以 B 分组,求每一组的均值、和、最大值、最小值—————————————————–”)
print(df.groupby([“B”]).agg([np.mean, np.sum, np.max, np.min]))