はじめに
挙動が分かりづらいが、なんだかんだ便利な時があるpandasのgroupbyのコード例をいくつか記載しておきます(備忘兼ねて)
※19/10/27 修正しました
サンプルデータ作成
結果
# check
df
"""
x1 x2 gender young_old
0 3 5 female young
1 8 10 male old
2 2 7 male old
3 9 0 female old
4 11 6 female young
5 1 4 male young
"""
コード
import pandas as pd
import numpy as np
# 値
arr = np.arange(12)
# セグメント用
gender = ['male','female'] * 3
young_old = ['young','old'] * 3
# シャッフル
np.random.shuffle(arr)
np.random.shuffle(gender)
np.random.shuffle(young_old)
# 値のデータフレーム
df = pd.DataFrame(data=arr.reshape(6,2),
columns=['x1','x2']
)
# セグメントデータ追加
df['gender'] = gender
df['young_old'] = young_old
よくわかんないけど便利なgroupbyコード例
3種類記載
その3 複数カラム使って条件分岐(新バージョン)
※@konandoiruasaさんよりアドバイスコメント頂き修正しました
結果
# age_genderカラムを、genderとyoung_oldをもとに生成
tmp[['gender', 'young_old', 'age_gender']]
gender young_old age_gender
0 male old オールドマン
1 female young 女性全般
2 male young ヤングマン
3 male young ヤングマン
4 female old 女性全般
5 female old 女性全般
コード
def my_func_switch3(srs):
# 1行がSeriesになったものを受け取る
if srs['gender']=='male':
if srs['young_old']=='young':
return 'ヤングマン'
elif srs['young_old']=='old':
return 'オールドマン'
else:
return '女性全般'
tmp = df.copy() # なくてもいい。ここではdfを書き換えたくないのでやってる
tmp['age_gender'] = tmp.apply(my_func_switch3, axis=1)
その3 複数カラム使って条件分岐(旧バージョン)
※こちらは無駄の多い旧バージョン、コメント頂き上記新バージョンへ変更
結果
# 他カラムからage_genderを生成した(単純な文字列結合処理ではない)
# check
tmp[['gender','young_old','age_gender']]
"""
gender young_old age_gender
0 female young young_female
1 male old old_male
2 male old old_male
3 female old old_female
4 female young young_female
5 male young young_male
"""
コード
def my_func_switch(xdf):
# 1行になる時だけちゃんと動く これ外して動いても意図した計算にならないと思うのでやらない方がいい
if xdf.shape[0]>1:raise('xdf.shape[0]==1のみ有効')
# 条件分岐
if xdf['gender'].values[0]=='male':
if xdf['young_old'].values[0]=='young':
return 'young_male'
elif xdf['young_old'].values[0]=='old':
return 'old_male'
elif xdf['gender'].values[0]=='female':
if xdf['young_old'].values[0]=='young':
return 'young_female'
elif xdf['young_old'].values[0]=='old':
return 'old_female'
tmp = df.copy() # なくてもいい。ここではdfを書き換えたくないのでやってる
tmp['dummy'] = np.arange(6) # ユニークな値を持つカラムを作る
tmp['age_gender'] = (tmp
.groupby('dummy')
.apply(my_func_switch)
.values
)
その2 データフレームを受け取って複数カラム使う
結果
# flgカラムを生成(x1<x2の判定結果)
# check
tmp[['x1', 'x2', 'flg']]
"""
x1 x2 flg
0 3 5 True
1 8 10 False
2 2 7 False
3 9 0 True
4 11 6 True
5 1 4 True
"""
コード
tmp = df.copy() # なくてもいい。ここではdfを書き換えたくないのでやってる
tmp['flg'] = (tmp
.groupby('gender')
.apply(lambda xdf: xdf['x1'] < xdf['x2'])
.values
)
その1 x/x.max()みたいな
結果
# genderごとに最大値を算出し、最大値に対する割合のカラムを生成
# check
tmp[['x1','gender','genderごとのmaxに対する割合']]
"""
x1 gender genderごとのmaxに対する割合
0 3 female 0.272727
1 8 male 1.000000
2 2 male 0.250000
3 9 female 0.818182
4 11 female 1.000000
5 1 male 0.125000
"""
コード
a = (df
.groupby('gender')
['x1']
.apply(lambda x: x/ x.max())
)
# check
a
"""
0 0.272727
1 1.000000
2 0.250000
3 0.818182
4 1.000000
5 0.125000
Name: x1, dtype: float64
"""
tmp = df.copy()
tmp['genderごとのmaxに対する割合'] = a
シンプルなgroupbyコード例
こちらは比較的シンプルなもの(当社比)
下記の内容です
・シンプル?なgroupby_shift
・シンプルなgroupby_apply&lambda利用
・シンプルなgroupby_apply&自作関数利用(引数あり)
・シンプルなgroupby_apply&自作関数利用(引数なし)
・シンプルなgroupby_apply&関数利用
・シンプルなgroupby_agg
・シンプルなgroupby 複数カラムをキーに
・シンプルなgroupby
# シンプル?なgroupby_shift
tmp = df.copy()
tmp['shifted'] = (tmp
.groupby('gender')
['x1']
.shift(-1)
.values
)
# check
tmp[['x1','gender','shifted']]
"""
x1 gender shifted
0 3 female 9.0
1 8 male 2.0
2 2 male 1.0
3 9 female 11.0
4 11 female NaN
5 1 male NaN
"""
# シンプルなgroupby_apply&lambda利用
(df
.groupby('gender')
['x1']
.apply(lambda srs: srs.max())
.reset_index()
)
# check
"""
gender x1
0 female 11
1 male 8
"""
# シンプルなgroupby_apply&自作関数利用(引数あり)
def my_func_range(srs, ratio=1):
range_ = srs.max() - srs.min()
return range_ * ratio
(df
.groupby('gender')
['x1']
.apply(my_func_range, 0.5)
.reset_index()
)
# check
"""
gender x1
0 female 2.5
1 male 1.5
"""
# シンプルなgroupby_apply&自作関数利用(引数なし)
def my_func_range(srs):
range_ = srs.max() - srs.min()
return range_
(df
.groupby('gender')
['x1']
.apply(my_func_range)
.reset_index()
)
# check
"""
gender x1
0 female 5
1 male 3
"""
# シンプルなgroupby_apply&関数利用
(df
.groupby('gender')
['x1']
.apply(np.max)
.reset_index()
)
# check
"""
gender x1
0 female 11
1 male 8
"""
# おまけ) 計算前にどのように値が分けられるか確認
# check
df.groupby('gender').groups
"""
{'female': Int64Index([0, 3, 4], dtype='int64'),
'male': Int64Index([1, 2, 5], dtype='int64')}
"""
# シンプルなgroupby_agg
(df
.groupby('gender')
.agg({'x1':np.max, 'x2':np.max})
.reset_index()
)
# check
"""
gender x1 x2
0 female 11 6
1 male 8 10
"""
# シンプルなgroupby 複数カラムをキーに
(df
.groupby(['gender','young_old'])
['x1']
.max()
.reset_index()
)
# check
"""
gender young_old x1
0 female old 9
1 female young 11
2 male old 8
3 male young 1
"""
# シンプルなgroupby
(df
.groupby('gender')
['x1']
.max()
.reset_index()
)
# check
"""
gender x1
0 female 11
1 male 8
"""
参考ページ
groupbyの基本はこちらに良くまとまっています。素敵なページです。
https://qiita.com/propella/items/a9a32b878c77222630ae
終わり