K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

Target / Mean Encoding

01.4.2

Target / Mean Encoding

最終更新 2024-06-01 読了時間 2 分
まとめ
Target Encoding(Mean Encoding)は、「元号」のようなカテゴリの列を、そのカテゴリに属する行の目的変数の平均(たとえば「平成の行の人口総数の平均」)に置き換える手法です。「町名」が 1,000 種類あっても 1 列で済み、しかも目的変数との結び付きを直接反映できるため、テーブルデータの Kaggle などで定番になっています。その一方で、ある行の値を計算する平均にその行自身の正解が含まれるとリーク(過大評価)が起きるため、KFold(n_splits=5) で分けて自分の所属しない fold のデータだけで平均を計算する Out-of-Fold(OOF)の実装が必須です。このページでは category_encoders の TargetEncoder(smoothing=1.0) を KFold のループで回す書き方と、出現回数の少ないカテゴリを全体平均に寄せる平滑化、微小ノイズの注入という 3 つのリーク対策を扱います。

概要 #

店舗ごとの売上を予測するとき、「その店の過去の平均売上」は非常に強い特徴量ですが、今日の売上を含めて平均を取ったら答えを写すことになります。Target Encoding はこの「カテゴリごとの目的変数の平均」を特徴量にする手法です。強力であるぶん、平均の計算に自分自身を入れないための KFold の工夫が結果を左右します。高次元なカテゴリを 1 列に落とし込みながら目的変数との結び付きを直接反映できる一方で、リーク(過大評価)との戦い が最大のテーマになります。


Pipeline 例(KFold + TargetEncoder) #

次のコードは、5 分割の交差検証の形で「元号」列を Target Encoding した 元号_te 列を作り、最後に推論用の encoder を全データで学習し直します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import numpy as np
from category_encoders.target_encoder import TargetEncoder
from sklearn.model_selection import KFold

df = pd.read_csv("../data/sample.csv")
cat_col = "元号"
target_col = "人口総数"

te = TargetEncoder(smoothing=1.0)  # 事前分布との平滑化
df[f"{cat_col}_te"] = 0.0

kf = KFold(n_splits=5, shuffle=True, random_state=0)
for train_idx, valid_idx in kf.split(df):
    te.fit(df.loc[train_idx, cat_col], df.loc[train_idx, target_col])
    df.loc[valid_idx, f"{cat_col}_te"] = te.transform(df.loc[valid_idx, cat_col])

# 最終的に全データで再学習し、推論時はこの encoder を使う
te.fit(df[cat_col], df[target_col])

実装のポイント #

一つ目は Out-of-Fold で生成することです。学習に使った行で同じ統計値を使うとリークするため、KFold で分割し、検証側の行を「見ていないデータ」として推測する形にします。二つ目は平滑化(smoothing)を入れることで、出現回数が少ないカテゴリは全体平均に寄せます。smoothing=1.0 などを指定すると count / (count + smoothing) を重みとして混ぜてくれます。三つ目はノイズを加えることで、np.random.normal(0, 0.01) のような微小なノイズを 元号_te に足すと、木モデル+小規模データで「この値ならこのカテゴリ」と暗記する過学習を軽減できます。


リーク対策の比較 #

手段目的実装 Tip
KFold Out-of-Fold 生成訓練行でのリーク防止n_splits=5 以上で安定化
時系列順の蓄積平均未来情報を使わないOrdered Target Statistics との比較を推奨
事前分布との平滑化頻度の少ないカテゴリでの極端値を抑えるsmoothing を count に応じて増減
ノイズ注入過学習の抑制np.random.normal(scale=0.01) などを加算

モデル投入時の検証ポイント #

最初に見るのはバリデーションスキームとの整合性で、Hold-Out / KFold / 時系列など、本番運用と同じスキームで Out-of-Fold を作成したかを確認します。時系列で予測するのに shuffle=True の KFold で OOF を作ると、未来の行の平均が過去の行に混ざります。二つ目は重要度のモニタリングで、元号_te の重要度(Gain / SHAP)が他の列より極端に高い場合はリークの可能性があり、交差検証スコアと Public/Private LB の差分を定期チェックします。三つ目はカテゴリごとの値域の確認で、df.groupby(cat_col)[f"{cat_col}_te"].agg(["count", "mean", "std"]) を出し、count が 1 桁のカテゴリで mean が全体平均から大きく外れていないかを見ます。


チェックリスト #

最初に確認したいのは、学習データと検証データが完全に分離された状態でエンコードしているかです。二つ目は、平滑化・ノイズを入れたバージョンと入れていないバージョンを交差検証で比較したかで、スコア差が小さければ smoothing=1.0 の既定で十分です。三つ目は推論時に使う TargetEncoder を保存し、再現性を担保したかで、OOF 用ではなく全データで fit した方を保存します。最後に、需要予測・行動予測など時系列依存が強い場合は Ordered Target Statistics も検討したかを見ます。


参考文献 #