One-Hot Encoding

Prep

One-Hot Encoding

概要 #

One-Hot Encoding は、カテゴリカル変数を「0/1」の疎ベクトルに変換する最も基本的な手法です。線形モデル・決定木系モデルいずれでも扱いやすく、カテゴリ間の大小関係を導入せずに表現できる点が強みです。一方で、カテゴリ数が増えると次元爆発が起こりやすく、学習・推論コストに直結します。

いつ採用するか #

  • カテゴリ種類が 2〜10 程度で、解釈性を保ちたいとき
  • 線形モデル(ロジスティック回帰、GLM)に投入して係数を読み解きたいとき
  • 木系アルゴリズムに入れる前に、カテゴリ間の順序関係を入れたくないとき

注意すべきケース #

  • カテゴリ数が数百を超える場合は Count / Target Encoding を検討
  • 連携する推論基盤(例: FaaS, Web API)のレスポンス要件が厳しいとき
  • 多値カテゴリに対して drop='first' を設定すると、解釈性は保てるが欠損が増えやすい

実装フロー #

1. サンプルデータの読み込み #

import pandas as pd

df = pd.read_csv("../data/sample.csv")
categorical_cols = ["元号", "町名"]
numeric_cols = ["西暦", "人口総数"]
df[categorical_cols + numeric_cols].head()

2. ColumnTransformer で数値とカテゴリを同時処理 #

from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline

ohe = OneHotEncoder(handle_unknown="ignore", sparse_output=True)

preprocess = ColumnTransformer(
    transformers=[
        ("cat", ohe, categorical_cols),
        ("num", "passthrough", numeric_cols),
    ],
    remainder="drop",
)

model = Pipeline(
    steps=[
        ("preprocess", preprocess),
        ("estimator", Ridge())
    ]
)
model.fit(df[categorical_cols + numeric_cols], df["人口総数"])

ポイント:

  • handle_unknown="ignore" を指定しておくと、推論時に未学習カテゴリが来ても例外にならず 0 ベクトルで扱える
  • sparse_output=True で疎行列のまま後段へ渡せば、メモリ節約 & 線形モデルで高速に学習できる

3. 特徴量名の確認 #

feature_names = model.named_steps["preprocess"]\
    .named_transformers_["cat"].get_feature_names_out(categorical_cols)
feature_names[:10]

モデルから重要度や係数を読む際に、get_feature_names_out を使って列名を取得しておくと分析レポートが書きやすくなります。


よくある落とし穴と対策 #

課題対策
高次元化で学習時間が肥大化High-cardinality な列を別手法(Count Encoding 等)に切り替え、10件未満のカテゴリを Other に集約
ワンホット列が全て 0 になるサンプルが発生handle_unknown="ignore" + モデル入力にバイアス項(定数列)を追加しておく
カテゴリの追加・削除で推論が壊れる学習時に ColumnTransformer を保存し、必ず同じ順序・列構成で推論する。sklearnPipeline で一体管理する

データアナリスト向けチェックリスト #

  1. カテゴリ粒度を確認したか?
    例: 町名が 1,000 件ある場合は上位区分にまとめないと次元が増えすぎる。

  2. ベースラインの線形モデルで係数を確認したか?
    係数の符号が期待と異なる場合は、データのリークや前処理の問題を疑う。

  3. 推論環境での疎行列サポートを確認したか?
    一部のモデルサーバーでは疎行列が扱えないため、toarray() で密行列化するとメモリが数倍になる。


参考リンク #