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

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

言語 JA

Count / Frequency Encoding

01.4.3

Count / Frequency Encoding

最終更新 2024-06-01 読了時間 2 分
まとめ
Count Encoding(Frequency Encoding)は、「元号」のようなカテゴリの列を、そのカテゴリがデータに何回出てくるか(Count)、または全体の何割を占めるか(Frequency)という 1 本の数値列に置き換える手法です。One-Hot のようにカテゴリの数だけ列が増えることがなく、「平成の行は多い、令和の行は少ない」という人気度の情報を LightGBM や XGBoost などの木モデルに渡せます。このページでは category_encoders の CountEncoder(normalize=True) で総務省の人口データの「元号」列を 0〜1 の出現確率に変え、LGBMRegressor の 5 分割交差検証に投入するまでを示します。出現頻度と目的変数の関係が弱いときは効果が薄いので、Target Encoding と組み合わせる判断基準も押さえます。

直感 #

コンビニの商品 ID が 5,000 種類あるとき、One-Hot にすると 5,000 列の 0/1 ができますが、Count Encoding なら「その商品が何回売れたか」という 1 列で済みます。「売れ筋の商品ほど値が大きい」という情報だけが残り、どの商品かという個別性は捨てられます。Count Encoding(Frequency Encoding)は、各カテゴリの出現回数や出現確率を数値として付与する手法です。ワンホットより低次元で、カテゴリの人気度を暗に表現できるため、LightGBM や XGBoost などの木モデルでよく使われます。

特徴 #

利点は、次元数が 1 列で済んで学習・推論が高速なことと、「平成の行は 60%、令和の行は 5%」のようなカテゴリ間の頻度差をヒューリスティックに取り込めることです。欠点は、頻度が目的変数との関連を表すとは限らないことで、出現回数と人口総数に関係がないデータでは情報が足りず、Target Encoding などと組み合わせる必要があります。


実装レシピ #

次のコードは、総務省の人口データ sample.csv の「元号」列を出現確率に変えた 元号_freq 列を追加し、元の値と並べて先頭 5 行を表示します。

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

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

ce = CountEncoder(normalize=True)  # True にすると 0〜1 に正規化
df[f"{cat_col}_freq"] = ce.fit_transform(df[cat_col], df[target_col])
df[[cat_col, f"{cat_col}_freq"]].head()

主要オプション #

パラメータ意味推奨値
normalize出現回数をそのまま使うか、全体で割って確率にするか次元スケールを合わせたい場合は True
min_group_size少数カテゴリをまとめる閾値データ量が偏る場合に活用
handle_unknown未知カテゴリをどう扱うか"value" にして平均頻度を代入する等

典型的なユースケース #

最初のケースは、「町名」「商品ID」のように大量カテゴリだがターゲットとの相関は弱そうなときです。Count Encoding でベースラインを作り、特徴量重要度が高かった列だけ Target Encoding へ切り替えると、リークの手間を必要な列に絞れます。二つ目は、数値特徴量との交互作用を作りたいときで、Count Encoding した列と売上やアクセス数などを掛け合わせると「カテゴリ別トラフィック重み付き特徴量」が 1 列で作れます。三つ目はデータリークを避けたいときです。Target Encoding と違い目的変数を直接参照しないため、KFold で分けずに全データで fit してもリークリスクが低く、実装が単純になります。


モデル学習での扱い #

次のコードは、頻度に変えた「元号」と数値の「西暦」の 2 列で人口総数を予測する LGBMRegressor を 5 分割交差検証し、決定係数の平均を表示します。

1
2
3
4
5
6
7
8
9
from sklearn.model_selection import KFold, cross_val_score
from lightgbm import LGBMRegressor

X = df[[f"{cat_col}_freq", "西暦"]]
y = df[target_col]

est = LGBMRegressor(random_state=0)
scores = cross_val_score(est, X, y, cv=KFold(n_splits=5, shuffle=True, random_state=0))
print(scores.mean())

Count Encoding 列は 1 本なので、そのままモデルに渡すだけで済みます。パイプラインの一部に category_encoders を入れておくと、本番環境での再現性も担保しやすくなります。


品質チェックリスト #

最初に確認したいのはカテゴリの分布です。大半の行が同一カテゴリ(例: 90% が「平成」)なら、頻度列はほぼ定数になって効果が薄いです。二つ目は Count(回数)と Frequency(割合)のどちらがモデルに合うかで、normalize を切り替えて交差検証スコアを比べて決めます。三つ目は未知カテゴリや欠損(NaN)に対する挙動で、学習時にない元号が推論時に来たときに handle_unknown の設定どおりの値が入るかをテストします。最後に、元号_freq の特徴量重要度が高かった場合は、追加で Target Encoding や「カテゴリごとの目的変数の平均」との比較を試し、頻度が効いているのか、頻度が別の何かの代理になっているのかを見極めます。


参考 #

  • category_encoders.count.CountEncoder
  • 実プロジェクトでは Count Encoding + Target Encoding のハイブリッドを試す価値が高い(Count をベースに、上位カテゴリだけ Target Encoding するなど)。