Posted at

PandasでDataFrameGroupByに対する列追加の処理は?

More than 1 year has passed since last update.

GroupByした後に集約処理以外の普通のスキャン処理をやるのに標準の方法は無いようです。列を追加するにもDataFrameGroupByオブジェクトにそのままmulti indexで列結合する方法は面倒です。

以下のようなデータフレームに対して、集約以外のグループごとの処理を書いて、さらに列に追加する方法を整理しました。

df = pd.DataFrame({'group' : [1,1,2,3,3,3,3,2,2,4,4,4] , 'value' : [1,2,1,1,3,2,4,2,1,3,2,1]} )

group value
0 1 1
1 1 2
2 2 1
3 3 1
4 3 3
5 3 2
6 3 4
7 2 2
8 2 1
9 4 3
10 4 2
11 4 1

基本的にグループ化前のdfにグループ化→処理→フラット化した結果を代入するというのが素直な方法のようです。関数内で列を追加する方法もあるようですが。


DataFrameGroupByに対応した関数

以下のような場合は、特にそのまま関数を使えばよさそうです。

df['new'] = df.groupby('group')['value'].cumcount()

group value new
0 1 1 0
1 1 2 1
2 2 1 0
3 3 1 0
4 3 3 1
5 3 2 2
6 3 4 3
7 2 2 1
8 2 1 2
9 4 3 0
10 4 2 1
11 4 1 2

df['new'] = df.groupby('group')['value'].rank()

group value new
0 1 1 1.0
1 1 2 2.0
2 2 1 1.5
3 3 1 1.0
4 3 3 3.0
5 3 2 2.0
6 3 4 4.0
7 2 2 3.0
8 2 1 1.5
9 4 3 3.0
10 4 2 2.0
11 4 1 1.0

groupごとに行われることは暗黙のうちになされ、結果はフラット化されるようです。


DataFrameGroupByに対応しない関数をrow-wiseに処理したいとき

これは、特に特筆することはないですがapplyで可能です。

df['new'] = df.groupby('group')['value'].apply(lambda x:x+1)

group value new
0 1 1 2
1 1 2 3
2 2 1 2
3 3 1 2
4 3 3 4
5 3 2 3
6 3 4 5
7 2 2 3
8 2 1 2
9 4 3 4
10 4 2 3
11 4 1 2

これも結果はフラット化されます。ただし、あくまでもgroup化されたSeriesに対して行っていますが、row-wiseではそれは意識することはないでしょう。


DataFrameGroupByに対応しない関数をgroup-wiseに処理したいとき

例えば、group化されたSeriesごとに直前の値との差分をとるような以下の関数の結果を見ると、グループごとに処理されていることがわかります。

df['new'] = df.groupby('group')['value'].apply(lambda y : y - y.shift() )

group value new
0 1 1 NaN
1 1 2 1.0
2 2 1 NaN
3 3 1 NaN
4 3 3 2.0
5 3 2 -1.0
6 3 4 2.0
7 2 2 1.0
8 2 1 -1.0
9 4 3 NaN
10 4 2 -1.0
11 4 1 -1.0

同じく結果はフラット化されます。

もう少しシンプルな方法もあるのでしょうか?