機械学習ではカテゴリカル変数を数値に変換する必要があります。「ダミー変数」や「One-Hot エンコーディング」と呼ばれるこの処理を、pandas の get_dummies と scikit-learn の OneHotEncoder で実装する方法を解説します。
ダミー変数とは
カテゴリ変数の各カテゴリに対して、該当すれば 1、しなければ 0 の列を作成します。
import pandas as pd df = pd.DataFrame({ 'color': ['赤', '青', '緑', '赤', '青'] }) # ダミー変数化 dummies = pd.get_dummies(df['color']) print(dummies) # 青 緑 赤 # 0 0 0 1 # 1 1 0 0 # 2 0 1 0 # 3 0 0 1 # 4 1 0 0
get_dummies の基本
get_dummies は pandas の関数で、シンプルな変換に適しています。
import pandas as pd df = pd.DataFrame({ 'name': ['田中', '佐藤', '鈴木'], 'city': ['東京', '大阪', '東京'], 'age': [25, 30, 35] }) # 単一列をダミー変数化 pd.get_dummies(df['city']) # DataFrame 全体に適用(object 型の列を自動検出) pd.get_dummies(df) # name age city_大阪 city_東京 # 0 田中 25 0 1 # 1 佐藤 30 1 0 # 2 鈴木 35 0 1
prefix オプション
複数の列をダミー変数化する場合、prefix で接頭辞をつけると識別しやすくなります。
df = pd.DataFrame({ 'color': ['赤', '青', '赤'], 'size': ['S', 'M', 'L'] }) dummies = pd.get_dummies(df, prefix=['color', 'size']) print(dummies.columns.tolist()) # ['color_赤', 'color_青', 'size_L', 'size_M', 'size_S']
drop_first で多重共線性を回避
回帰分析では、ダミー変数の全てを使うと多重共線性の問題が起きます。drop_first=True で 1 つ目のカテゴリを落とせます。
df = pd.DataFrame({ 'color': ['赤', '青', '緑', '赤'] }) # 全カテゴリ print(pd.get_dummies(df['color'])) # 青 緑 赤 # 0 0 0 1 # 1 1 0 0 # 2 0 1 0 # 3 0 0 1 # 最初のカテゴリを落とす print(pd.get_dummies(df['color'], drop_first=True)) # 緑 赤 # 0 0 1 # 1 0 0 # 2 1 0 # 3 0 1
「青」の列がなくなりました。緑=0、赤=0 なら青と判断できます。
全カテゴリを保持。解釈しやすいが、回帰分析で問題になる可能性。
多重共線性を回避。回帰分析では推奨。
scikit-learn の OneHotEncoder
機械学習パイプラインでは OneHotEncoder がよく使われます。学習データとテストデータで一貫した変換が保証されるためです。
from sklearn.preprocessing import OneHotEncoder import pandas as pd import numpy as np df = pd.DataFrame({ 'color': ['赤', '青', '緑', '赤'] }) # OneHotEncoder を作成 encoder = OneHotEncoder(sparse_output=False) # 学習と変換 encoded = encoder.fit_transform(df[['color']]) print(encoded) # [[0. 0. 1.] # [1. 0. 0.] # [0. 1. 0.] # [0. 0. 1.]] # カテゴリの確認 print(encoder.categories_) # [array(['緑', '赤', '青'], dtype=object)]
未知のカテゴリへの対処
get_dummies の問題点は、学習データにないカテゴリがテストデータに現れたときです。
import pandas as pd # 学習データ train = pd.DataFrame({'color': ['赤', '青', '緑']}) train_dummies = pd.get_dummies(train['color']) # テストデータに新しいカテゴリ「黄」がある test = pd.DataFrame({'color': ['赤', '黄']}) test_dummies = pd.get_dummies(test['color']) print(train_dummies.columns.tolist()) # ['緑', '赤', '青'] print(test_dummies.columns.tolist()) # ['赤', '黄'] # 列が一致しない!
OneHotEncoder なら handle_unknown オプションで対処できます。
from sklearn.preprocessing import OneHotEncoder encoder = OneHotEncoder(sparse_output=False, handle_unknown='ignore') # 学習データで fit train = [['赤'], ['青'], ['緑']] encoder.fit(train) # 未知のカテゴリを含むデータを変換 test = [['赤'], ['黄']] encoded = encoder.transform(test) print(encoded) # [[0. 0. 1.] # 赤 # [0. 0. 0.]] # 黄(全て0になる)
| handle_unknown | 動作 |
|---|---|
| error | エラーを発生(デフォルト) |
| ignore | 全て 0 のベクトルにする |
| infrequent_if_exist | 稀なカテゴリとして扱う |
DataFrame との統合
OneHotEncoder の結果を DataFrame に戻す方法です。
from sklearn.preprocessing import OneHotEncoder import pandas as pd df = pd.DataFrame({ 'color': ['赤', '青', '緑'], 'size': ['S', 'M', 'L'], 'price': [100, 200, 300] }) # カテゴリ列のみエンコード encoder = OneHotEncoder(sparse_output=False) cat_columns = ['color', 'size'] encoded = encoder.fit_transform(df[cat_columns]) feature_names = encoder.get_feature_names_out(cat_columns) # DataFrame に変換して結合 encoded_df = pd.DataFrame(encoded, columns=feature_names) result = pd.concat([df.drop(columns=cat_columns), encoded_df], axis=1) print(result)
ColumnTransformer でパイプライン化
実務では ColumnTransformer を使って、カテゴリ列と数値列を別々に処理するのが一般的です。
from sklearn.compose import ColumnTransformer from sklearn.preprocessing import OneHotEncoder, StandardScaler from sklearn.pipeline import Pipeline from sklearn.linear_model import LogisticRegression import pandas as pd df = pd.DataFrame({ 'color': ['赤', '青', '緑', '赤'], 'size': ['S', 'M', 'L', 'S'], 'price': [100, 200, 300, 150], 'target': [0, 1, 1, 0] }) # 前処理パイプライン preprocessor = ColumnTransformer( transformers=[ ('cat', OneHotEncoder(handle_unknown='ignore'), ['color', 'size']), ('num', StandardScaler(), ['price']) ] ) # モデルと結合 pipeline = Pipeline([ ('preprocessor', preprocessor), ('classifier', LogisticRegression()) ]) # 学習 X = df.drop(columns=['target']) y = df['target'] pipeline.fit(X, y) # 予測(新しいデータも同じ前処理が適用される) new_data = pd.DataFrame({ 'color': ['青'], 'size': ['M'], 'price': [250] }) pipeline.predict(new_data)
探索的分析や簡単な変換に便利。学習/テストの一貫性は手動で管理が必要。
機械学習パイプラインに組み込みやすい。未知カテゴリの処理も可能。
get_dummies は手軽で直感的ですが、本番の機械学習システムでは OneHotEncoder を使ったパイプラインを構築するのが推奨されます。