背景
あるテーブルデータのコンペに参加していて、特徴量が少なく、Target Encodingなるものを使って特徴を増やそうと思い、色々探しました。
qiitaには以下の記事があります。
によると、以下の方法でtarget encodingできるらしいとのこと
# 1
label_mean = df.groupby('category').label.mean()
df = df.assign(target_enc=df['category'].map(label_mean).copy())
# 2
df = df.assign(target_enc2=df.groupby('category')['label'].transform('mean').copy())
やってみると簡単にできました。
ただ、テーブルデータ初心者の私はあるところでつまづきます。そうテストデータです。
テストデータでも同様にgroupbyしてトレインデータと同じようにラベルの平均値を振る必要がありますが、
スマートに行う方法が思いつきません。
変換表を逐一つくるのも面倒です。
適したライブラリを発見する
(個人的に)使いやすいライブラリを見つけました。
Category Encoders
使ってみる
まず、Category Encodersをインストールします。
pip install category_encoders
使ってみましょう
from category_encoders.target_encoder import TargetEncoder
import pandas as pd
df = pd.DataFrame({ 'category': ['A','A','B','B','B','C','C','C','C','D'],
'label': [1,0,1,0,0,1,0,1,1,1]
})
TE = TargetEncoder()
df["target_enc"] = TE.fit_transform(df["category"],df["label"])
| | category | label | target_enc|
| 0 | A | 1 | 0.526894 |
| 1 | A | 0 | 0.526894 |
| 2 | B | 1 | 0.365121 |
| 3 | B | 0 | 0.365121 |
| 4 | B | 0 | 0.365121 |
| 5 | C | 1 | 0.742886 |
| 6 | C | 0 | 0.742886 |
| 7 | C | 1 | 0.742886 |
| 8 | C | 1 | 0.742886 |
| 9 | D | 1 | 0.600000 |
よくみると結果が少しおかしいですね。というのも、Aは1と0の平均なので0.5にならなければなりません。
これは、自動でsmoothingのデータの水増しが行われているためです。おそらくこのほうがLeakしないのかと思われます。
試しに、smoothingを0.1にしてみます(0にはできないらしいです。)
from category_encoders.target_encoder import TargetEncoder
import pandas as pd
df = pd.DataFrame({ 'category': ['A','A','B','B','B','C','C','C','C','D'],
'label': [1,0,1,0,0,1,0,1,1,1]
})
TE = TargetEncoder(smoothing=0.1)
df["target_enc"] = TE.fit_transform(df["category"],df["label"])
このように返ってきます
| | category | label | target_enc |
| 0 | A | 1 | 0.500005 |
| 1 | A | 0 | 0.500005 |
| 2 | B | 1 | 0.333333 |
| 3 | B | 0 | 0.333333 |
| 4 | B | 0 | 0.333333 |
| 5 | C | 1 | 0.750000 |
| 6 | C | 0 | 0.750000 |
| 7 | C | 1 | 0.750000 |
| 8 | C | 1 | 0.750000 |
| 9 | D | 1 | 0.600000 |
そして、テストデータに適用する場合は簡単です。transformするだけ。
df_test = pd.DataFrame({ 'category': ['A','B','C','C','D']
})
df_test["target_enc"] = TE.transform(df_test)
上記のデータと同じようにエンコーディングされていますね。
category target_enc
0 A 0.500005
1 B 0.333333
2 C 0.750000
3 C 0.750000
4 D 0.600000