Pandas的Groupby

Kopei article

前言

一般需要对数据做分割/处理/合并的时候会使用groupby, groupby的意思类似sql语句的分组. 对一个DataFrame做分割、处理、合并的过程一般如下图所示, 通过这样的流程能做到聚合数据的能力。
https://s3.ap-southeast-1.amazonaws.com/kopei-public/groupby-example.png

分割

官方叫split, 是把数据依照某种条件分组. 对一个DataFrame使用groupby就达到了split.

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
In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'A': ['foo','bar','foo','bar','foo','bar','foo','foo'], 'B':['one','one','two','three','two','two','one','three'],'C':[332,42,12,31,21,1,3,14]})

In [3]: df
Out[3]:
A B C
0 foo one 332
1 bar one 42
2 foo two 12
3 bar three 31
4 foo two 21
5 bar two 1
6 foo one 3
7 foo three 14

In [4]: group_a=df.groupby('A')

In [5]: group_a
Out[5]: <pandas.core.groupby.DataFrameGroupBy object at 0x7f78fb9cfc50>

In [52]: grouped.get_group('A')
Out[52]:
A B C D
1 bar one 0.254161 1.511763
3 bar three 0.215897 -0.990582
5 bar two -0.077118 1.211526

处理

apply对每个分割好的group运行某个(多个)函数. 在这一步我们可能会使用到如下方法:

  • aggregation
    的作用是统计组里的数据: 如平均值, 求和, 计数. 从下面的例子可以看出来, aggregation后得到一个以groupby参数作为groupname,
    并且以它为indexDataFrame; 如果是通过多个值groupby的那么结果是以MultiIndex为索引, 当然index是可以通过as_index来设置的(.reset_index()
    也可以得到相同效果). aggregation函数会排除NA值.
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
In [6]: group_a.agg(sum)   ## 注意, 这里如果传递[sum]将会对所有column做sum
Out[6]:
C
A
bar 74
foo 382
In [8]: group_a['C'].agg(sum) ## 注意, 这里传给agg, 如果是[sum], 返回的是Dataframe, 否则是Series
Out[8]:
A
bar 74
foo 382
Name: C, dtype: int64

In [9]: group_a_b=df.groupby(['A','B'])

In [10]: group_a_b.agg(sum)
Out[10]:
C
A B
bar one 42
three 31
two 1
foo one 335
three 14
two 33
In [15]: group_a_b=df.groupby(['A','B'], as_index=False).agg(sum)

In [16]: group_a_b
Out[16]:
A B C
0 bar one 42
1 bar three 31
2 bar two 1
3 foo one 335
4 foo three 14
5 foo two 33

所有的Aggregation函数如下表, 它们返回的对象一般会减少维度:
https://s3.ap-southeast-1.amazonaws.com/kopei-public/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202018-08-31%20%E4%B8%8B%E5%8D%882.59.31.png

agg()是可以一次运作多个函数的, 注意下面这个函数是对于grouped Series, 即切出了一个series操作的, 返回的是dataframe.

1
2
3
4
5
6
In [30]: group_a['C'].agg([sum, min])
Out[30]:
sum min
A
bar 74 1
foo 382 3

如果对一个groupby Dataframe应用多个函数, 那么每个column都会有各自的聚合函数列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In [63]: df.groupby('A').agg([sum, min,max])
Out[63]:
B C
sum min max sum min max
A
bar onethreetwo one two 74 1 42
foo onetwotwoonethree one two 382 3 332
###重命名列名
In [65]: df.groupby('A').agg([sum, min,max]).rename(columns={'B':'reName'})
Out[65]:
reName C
sum min max sum min max
A
bar onethreetwo one two 74 1 42
foo onetwotwoonethree one two 382 3 332

agg的函数也可以通过lambda把所有列改成标量值:

1
2
3
4
5
6
In [17]: df.groudby('A').agg(lambda x:1)
Out[17]:
B C
A
bar 1 1
foo 1 1

通过给agg()传递dict可以对Dataframe的不同column应用不同的聚合. 这样得出的column没有顺序的, 想要有顺序需要使用OrderedDict

1
2
3
4
5
6
In [51]: df.groupby('A').agg({'B': sum, 'C': min})
Out[51]:
C B
A
bar 1 onethreetwo
foo 3 onetwotwoonethree
  • transformation
    transform方法把一个groupby对象做转变, 返回一个和grouped对象一样index的对象(这点和agg不同, agg通常返回维度减少的数据). 这个transform实际传入的函数必须满足:
    • 返回和group chunk一样大小的对象, 或者返回的对象大小可以broadcastable到group chunk size(broadcasting是numpy的术语, 描述了numpy对待不同形状阵列时如何计算.)
    • 在group chunk上做一列一列操作. 实际使用的是chunk.apply
    • 不能直接(inplace)在group chunk上修改, group chunk需要认为是不可改变的, grouped.transform(lambda x: x.fillna(inplace=True))
      这样的直接修改可能带来意外结果.
    • 也可以直接对整个chunk做操作

这里有个例子,讲述了如何使用transform减少处理的逻辑http://pbpython.com/pandas_transform.html

  • filteration
    使用filter函数可以返回原来对象的一个子集. filter的参数是个应用到整个组的函数, 其返回为True/False.
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
In [115]: sf = pd.Series([1, 1, 2, 3, 3, 3])

In [116]: sf.groupby(sf).filter(lambda x: x.sum() > 2)
Out[116]:
3 3
4 3
5 3
dtype: int64

In [117]: dff = pd.DataFrame({'A': np.arange(8), 'B': list('aabbbbcc')})

In [118]: dff.groupby('B').filter(lambda x: len(x) > 2)
Out[118]:
A B
2 2 b
3 3 b
4 4 b
5 5 b

In [119]: dff.groupby('B').filter(lambda x: len(x) > 2, dropna=False)
Out[119]:
A B
0 NaN NaN
1 NaN NaN
2 2.0 b
3 3.0 b
4 4.0 b
5 5.0 b
6 NaN NaN
7 NaN NaN

In [120]: dff['C'] = np.arange(8)

In [121]: dff.groupby('B').filter(lambda x: len(x['C']) > 2)
Out[121]:
A B C
2 2 b 2
3 3 b 3
4 4 b 4
5 5 b 5

合并

combining是再把处理好的数据组合一起.

  • Post title:Pandas的Groupby
  • Post author:Kopei
  • Create time:2018-08-31 00:00:00
  • Post link:https://kopei.github.io/2018/08/30/python-2018-08-31-pandas/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
 Comments
On this page
Pandas的Groupby