機械学習ではカテゴリカル変数を数値に変換する必要があります。「ダミー変数」や「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 を使ったパイプラインを構築するのが推奨されます。