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

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

言語 JA

Ordered Target Statistics(CatBoost Encoding)

01.4.4

Ordered Target Statistics(CatBoost Encoding)

最終更新 2024-06-01 読了時間 2 分
まとめ
Ordered Target Statistics は、CatBoost が採用する「順序付きターゲットエンコーディング」で、Target Encoding と同じくカテゴリを目的変数の平均に置き換えますが、各行の値を計算するときにその行より前に並んだ行だけを使います。1 行目の「平成」は事前平均、2 行目の「平成」は 1 行目の値、100 行目の「平成」はそれまでの 99 行の平均というように、自分自身の正解と未来の行の正解が混ざらないため、Target Encoding で問題になるリークが構造的に起きません。このページでは category_encoders の CatBoostEncoder(cols=["元号"], random_state=0) で総務省の人口データを数値化し、sort_values("西暦") で時系列順に並べてから渡す応用と、smoothing・a のハイパーパラメータ、ヒストグラムで分布を確かめる方法を扱います。

コンセプト #

テストの点数を予想するとき、「この生徒のクラスの平均点」を特徴量にすると便利ですが、その平均に本人の点数が含まれていたら答えを写しているのと同じです。Ordered Target Statistics は、出席番号順に並べて「自分より前の番号の人の平均」だけを使います。サンプルをランダム順または時間順に並べ、各サンプルをエンコードするときには それ以前に出現したデータのみ を使ってターゲット平均を計算します。これにより、Target Encoding の強み(ターゲットとの強い相関を捉える)を保ちながら、未来の情報を使ってしまうリークを防げます。


実装ステップ #

次のコードは、「元号」列を Ordered Target Statistics で数値化した 元号_ots 列を追加し、元の値と並べて先頭 5 行を表示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import pandas as pd
from category_encoders.cat_boost import CatBoostEncoder

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

encoder = CatBoostEncoder(cols=[cat_col], random_state=0)
df[f"{cat_col}_ots"] = encoder.fit_transform(df[cat_col], df[target_col])
df[[cat_col, f"{cat_col}_ots"]].head()

category_encoders.cat_boost.CatBoostEncoder が最も手軽です。内部でデータ順序をランダムに並べ替え、逐次平均を計算してくれます。

時系列データでの応用 #

次のコードは、「西暦」の昇順に並べ替えてから同じ encoder に渡し、各行が過去の年のデータだけで計算されるようにします。

1
2
3
df = df.sort_values("西暦")
encoder = CatBoostEncoder(cols=[cat_col], random_state=0)
df[f"{cat_col}_ots"] = encoder.fit_transform(df[cat_col], df[target_col])

ハイパーパラメータ #

パラメータ説明推奨設定
random_stateランダム順序の再現性モデル全体と同じ seed を指定
smoothing事前平均との平滑化強度1.0 〜 5.0 をデータ量に応じて調整
a (sigma)ノイズの大きさ0.0(ノイズなし)〜 0.05 程度

CatBoost では内部で ordered boosting を採用しており、同様の考え方でリークを抑えています。smoothing を大きくすると、出現回数の少ない元号の値が全体平均に強く引き寄せられ、極端な値が出にくくなります。


可視化で挙動をチェック #

次のコードは、元号ごとに 元号_ots のヒストグラムを重ねて描き、同じ元号の中で値がどれくらい散らばっているかを確認します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import matplotlib.pyplot as plt
import japanize_matplotlib

plt.figure(figsize=(8, 4))
for era in df[cat_col].unique():
    subset = df.query(f"{cat_col} == @era")[f"{cat_col}_ots"]
    plt.hist(subset, alpha=0.5, label=era, bins=20)

plt.title("Ordered Target Statistics の分布")
plt.legend()

カテゴリごとの分布を重ねると、時間経過に伴ってどのようにターゲット平均が更新されているか視覚的に確認できます。


運用 Tips #

学習・推論の再現性のために、学習時に使用した encoder を pickle / joblib で保存し、推論環境にデプロイします。推論時は transform だけを呼ぶので、学習データ全体で計算した平均がそのまま使われます。ランダム順序の影響を抑えたいときは、random_state を変えて複数回学習しスコアを平均することで分散を抑えられます。CatBoost 本体を使っている場合は cat_features に列名を指定するだけで内部で同等の処理が行われるため、外部で CatBoostEncoder を使う必要はありません。


チェックリスト #

最初に確認したいのは入力データの並び順で、時間順にしたいのかランダム順でよいのかを sort_values の有無で明示的に制御したかを見ます。二つ目は Target Encoding と比較して過学習が緩和されているかで、同じ KFold の交差検証で両者のスコア差を確認します。最後に、学習済み encoder を保存し、推論パイプラインに組み込んだかを確かめます。


参考 #