カラムの値でDataFrameをグループ分割 - pandas
こうしたい
元のデータ c1=hogeのみのデータ c1=piyoのみのデータ c1=hugaのみのデータ
c1 c2 c3 c1 c2 c3 c1 c2 c3 c1 c2 c3
0 hoge 0 1 0 hoge 0 1 2 piyo 4 5 4 huga 8 9
1 hoge 2 3 1 hoge 2 3 5 piyo 10 11 ,
2 piyo 4 5 > 3 hoge 6 7 ,
3 hoge 6 7
4 huga 8 9
5 piyo 10 11
DataFrame.groupby('カラム名') を使う。
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 |
import pandas as pddf = pd.DataFrame({ 'c1': ['hoge', 'hoge', 'piyo', 'hoge', 'huga', 'piyo'], 'c2': [0, 2, 4, 6, 8, 10], 'c3': [1, 3, 5, 7, 9, 11],})for c1, sdf in df.groupby('c1'): print(c1) print(sdf)# =># hoge# c1 c2 c3# 0 hoge 0 1# 1 hoge 2 3# 3 hoge 6 7# huga# c1 c2 c3# 4 huga 8 9# piyo# c1 c2 c3# 2 piyo 4 5# 5 piyo 10 11 |
行番号が飛び飛びになってるのを振り直したければ、reset_index()を使う。その際、通常は新規カラムindexを追加して旧番号を残し、新番号を振るという形になる。旧番号が不要ならdrop=Trueにする
1 2 3 4 5 6 7 8 9 10 11 |
...for c1, sdf in gp: sdf = sdf.reset_index() print(sdf)# =># index c1 c2 c3# 0 0 hoge 0 1# 1 1 hoge 2 3# 2 3 hoge 6 7# ... |
1 2 3 4 5 6 7 8 9 10 11 |
...for c1, sdf in gp: sdf = sdf.reset_index(drop=True) print(sdf)# =># c1 c2 c3# 0 hoge 0 1# 1 hoge 2 3# 2 hoge 6 7# ... |
複数のカラムでグループ分け
複数のカラムでグループ分けしたければ、groupby()にリストを渡す。
返ってくるデータはMultiIndexとなる。要は、forで回したときに、行のインデックスとして、グループ分けに使用したカラムのタプル (c1, c2) が使われたデータ構造となる。
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 |
import pandas as pddf = pd.DataFrame([['hoge', 0, 1], ['hoge', 2, 3], ['piyo', 4, 5], ['hoge', 6, 7], ['huga', 2, 1], ['piyo', 1, 1], ['hoge', 0, 2], ['hoge', 0, 5], ['hoge', 0, 5]], columns=['c1', 'c2', 'c3'])gp = df.groupby(['c1', 'c2'])for idx, sdf in gp: print(idx) print(sdf)# =># ('hoge', 0)# c1 c2 c3# 0 hoge 0 1# 6 hoge 0 2# 7 hoge 0 5# 8 hoge 0 5# ('hoge', 2)# c1 c2 c3# 1 hoge 2 3# ... |
グループ毎に集計
GroupByオブジェクトに対し、sum()やcount()などの集計関数を用いると、グループ毎に合計値やレコード数などを算出できる。
その際、結果の型は<pandas.core.frame.DataFrame>だが、print()すると、グループに用いたカラムのヘッダだけ1段下がったような表示になる。これは、そのカラムがデータフレームのindexとして指定されている状態であることを示す。
(意図的にDataFrameに対しindex列を指定するには、df.set_index('col_name')を用いる。その際、カラムの値は全てユニークでなければ無視される)
集計後、これを元に戻すには、reset_index()を用いる。
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 |
import pandas as pddf = pd.DataFrame([['hoge', 0, 1], ['hoge', 2, 3], ['piyo', 4, 5], ['hoge', 6, 7], ['huga', 2, 1], ['piyo', 1, 1], ['hoge', 0, 2], ['hoge', 0, 5], ['hoge', 0, 5]], columns=['c1', 'c2', 'c3'])gps = df.groupby('c1').sum()print(gps)# c2 c3# c1# hoge 8 23# huga 2 1# piyo 5 6gps = df.groupby(['c1', 'c2']).sum()print(gps)# c3# c1 c2 # hoge 0 13# 2 3# 6 7# huga 2 1# piyo 1 1# 4 5gps = gps.reset_index()print(gps)# c1 c2 c3# 0 hoge 0 13# 1 hoge 2 3# 2 hoge 6 7# 3 huga 2 1# 4 piyo 1 1# 5 piyo 4 5 |
同じ値が連続する区間毎に分割
c2が連続する区間ごとに分割
c1 c2 c1 c2 c1 c2 c1 c2
0 zero 0 0 zero 0 3 three 1 5 five 0
1 one 0 1 one 0 4 four 1 , 6 six 0
2 two 0 > 2 two 0 ,
3 three 1
4 four 1
5 five 0
6 six 0
単にgroupby('c2')すると、(0,1,2)と(5,6)が同じグループになってしまう。
値を1行ずらすshift()と元を比較することで、値の切り替わる行を1、同じ行を0とした新規列を作れる。その累積和に対してgroupby()するとよい。
c1 c2 切替 累積和 0 zero 0 NaN 0 1 one 0 0 0 2 two 0 0 0 3 three 1 1 1 4 four 1 0 1 5 five 0 1 2 6 six 0 0 2
1 2 3 |
df['切替'] = df['c2'] != df['c2'].shift()df['累積和'] = df['切替'].cumsum()grp = df.groupby('累積和') |

