Help us understand the problem. What is going on with this article?

Target Mean Encoding

Target Mean Encodingとは

カテゴリカル変数はそのままでは、機械学習モデルの入力にすることができません。
普通は、One Hot Encoding(ダミー変数化)をするかと思います。(自分はこれしか知りませんでした。)

カテゴリカル変数のEncoding手法の一つであるTarget Mean Encoding(Likelihood Encoding)は、目的変数の情報を利用し、カテゴリカル変数を数値に変換する方法で、Kaggle等の機械学習コンペではよく用いられているようです。
目的変数がBoolean表現の場合、カテゴリごとの確率を、数値であればカテゴリごとの平均を特徴量とします。

実行例

例として、以下のようなデータセットでTarget Mean Encoding(以下、Target Encoding)を試してみます。

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]
                  })
  category  label
0        A      1
1        A      0
2        B      1
3        B      0
4        B      0
5        C      1
6        C      0
7        C      1
8        C      1
9        D      1

Pandasのgroupbyを使った実行方法を試してみます。
方法は以下の2つです。

# 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())

得られる結果はこちらです。

  category  label  target_enc  target_enc2
0        A      1    0.500000     0.500000
1        A      0    0.500000     0.500000
2        B      1    0.333333     0.333333
3        B      0    0.333333     0.333333
4        B      0    0.333333     0.333333
5        C      1    0.750000     0.750000
6        C      0    0.750000     0.750000
7        C      1    0.750000     0.750000
8        C      1    0.750000     0.750000
9        D      1    1.000000     1.000000

Target Encodingできていることが確認できました。

Leakageについて

Leakageとは、モデルを学習する際に、本来知らないはずの情報を不当に使ってしまうことです。
Kaggleのドキュメントには、Leakageについての項目が設けられています。
ここでは以下の具体例が挙げられています。

  • 患者が前立腺癌かどうかを予測するためのデータに「前立腺の手術を受けたか」という変数を含めていた

Target Encodingでは、学習データで得られた各カテゴリの特徴量をテストデータ内の各カテゴリに適用します。これが、Leakageが引き起こしてしまいます。
本記事では、Leakageによる過学習を防ぐための手法について、2つ紹介します。

Leave One Out(LOO)

この手法は、値を計算するときに、その行データ以外で計算するというものです。

通常のTarget Encoding

category label target_enc
0 A 1 0.50
1 A 0 0.50
2 B 1 0.33
3 B 0 0.33
4 B 0 0.33
5 C 1 0.75
6 C 0 0.75
7 C 1 0.75
8 C 1 0.75
9 D 1 1.00

Target Encoding with LOO

category label target_enc
0 A 1 0.00
1 A 0 1.00
2 B 1 0.00
3 B 0 0.50
4 B 0 0.50
5 C 1 0.66
6 C 0 1.00
7 C 1 0.66
8 C 1 0.66
9 D 1 0.00

Cについて見てみましょう。
5行目のCのtarget_encは

(0+1+1)/3 = 2/3 = 0.66

となります。
また、6行目のCのtarget_encは

(1+1+1)/3 = 3/3 = 1.00

となります。

ただ、この手法だと余計にLeakageを起こしているように見えます。
(例えばBについて、labelの0, 1がtarget_encの0.5, 0に対応してしまっている)

Smoothing

この手法は、データ数が少ないカテゴリを持つカテゴリカル変数に対して効果的にTarget Encodingを用いるための手法です。
データ数が十分あるカテゴリについては通常のTarget Encodingに近い値を示し、データ数が少ないカテゴリについてはデータセット全体での値に近づくようにスムージングを行います。
詳しく知りたい方は、こちらのブログがわかりやすいです。

S_i = λ(n_i)\frac{n_iy}{n_i}+(1−λ(n_i))\frac{n_y}{n_tr}\\

λ(n_i) = \frac{1}{1+exp(-\frac{n_i−k}{f})}

k=0, f=1(λは標準シグモイド関数になる)でカテゴリA,Bについて計算してみると、以下のようになります。

λ(2) = \frac{1}{1+exp(-2)} = 0.880\\

S_A = 0.880*\frac{1}{2} + (1−0.880)*\frac{6}{10} = 0.512

λ(3) = \frac{1}{1+exp(-3)} = 0.953\\

S_B = 0.953*\frac{1}{3} + (1−0.953)*\frac{6}{10} = 0.346

変換時の注意点

以下でも実行できますが、どちらも警告が出ます。

# 1
label_mean = df.groupby('type').label.mean()
df['target_enc'] = df['type'].map(label_mean)

# 2
df['target_enc2'] = df.groupby('type')['label'].transform('mean')
SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: 
http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

ドキュメントの注意事項を参照しても、どう対応すればいいのかわからなかったのですが、
実行例で示したようにすることで警告は出なくなりました。

参考

カテゴリカル変数のEncoding手法について

Feature Enginnering

TargetEncodingのスムーシング

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした