pandasのgroupbyで特徴量を作りたい
カラムの属性ごとの統計量を特徴に追加したいときに,collectionsやgroupbyでdictみたいなの作ってマージしなくても良い場合が結構あります.
単に統計量出すだけであれば簡単なものの,特徴量としてレコードに追加したい局面にpandas.DataFrame.groupbyの使い方に苦戦したのでメモとして残します.
何が言いたいかというとgroupby.transformは便利.
サンプルデータ
import pandas as pd
df = pd.DataFrame({
"site":["A","A","A","B","B","C"],
"dat":[15,30,30,30,10,50]
})
| site | dat | |
|---|---|---|
| 0 | A | 15 |
| 1 | A | 30 |
| 2 | A | 30 |
| 3 | B | 30 |
| 4 | B | 10 |
| 5 | C | 50 |
属性ごとの平均,最大,最小など基本統計量
transformの引数をnp.maxやnp.minに変えれば直接特徴量が生成できる.
median, varなども同様.
siteごとの平均値を算出するコードを下に示す.
import numpy as np
df["site_mean"] = df.groupby("site").transform(np.mean)
| site | dat | site_mean | |
|---|---|---|---|
| 0 | A | 15 | 25 |
| 1 | A | 30 | 25 |
| 2 | A | 30 | 25 |
| 3 | B | 30 | 20 |
| 4 | B | 10 | 20 |
| 5 | C | 50 | 50 |
Count Encoding
あるカラムの(カテゴリ)特徴の出現回数を新たな特徴にする手法がカウントエンコーディングと呼ばれている.groupbyと組み合わせることで,ある属性の中での希少性のようなものを特徴にできる.
collections.Counter使えばできますが,これも同じくtransformで終わらせます.
siteとdatのペアの出現回数に変換するコードを示す.
(site Aにおける30の出現回数は2回)
df["count_site_dat"] = df.groupby(["site","dat"]).transform(np.size)
| site | dat | site_mean | count_size_dat | |
|---|---|---|---|---|
| 0 | A | 15 | 25 | 1 |
| 1 | A | 30 | 25 | 2 |
| 2 | A | 30 | 25 | 2 |
| 3 | B | 30 | 20 | 1 |
| 4 | B | 10 | 20 | 1 |
| 5 | C | 50 | 50 | 1 |
順位
ある特徴を持っているデータの中で,ある特徴が何番目に大きいデータかを算出する.
df["site_rank"] = df.groupby("site")["dat"].rank(method="dense")
| site | dat | site_mean | count_size_dat | site_rank | |
|---|---|---|---|---|---|
| 0 | A | 15 | 25 | 1 | 1 |
| 1 | A | 30 | 25 | 2 | 2 |
| 2 | A | 30 | 25 | 2 | 2 |
| 3 | B | 30 | 20 | 1 | 2 |
| 4 | B | 10 | 20 | 1 | 1 |
| 5 | C | 50 | 50 | 1 | 1 |
rankの引数を変えると,主に同じ値(同じ順位)の表現方法が変わる.
詳細はpandas.DataFrame, Seriesを順位付けするrankのmethodを参照.