特徴量エンジニアリング
「モデルの比較ができた。次は特徴量エンジニアリングだ。」
田中VPoEが力を込めて言う。
「Kaggleのトップ層が口を揃えて言うことがある。『モデルの選択よりも特徴量エンジニアリングの方が遥かに重要だ』と。業務知識をデータに変換する技術を身につけよう。」
特徴量エンジニアリングの原則
特徴量エンジニアリングの3つのソース:
1. ドメイン知識 → 業務の専門知識から特徴量を生成
2. 統計的分析 → EDAで発見したパターンを特徴量化
3. 自動生成 → 交互作用項、多項式特徴量の自動生成
ドメイン知識に基づく特徴量
サービス加入数
import pandas as pd
import numpy as np
df = pd.read_csv('WA_Fn-UseC_-Telco-Customer-Churn.csv')
df['TotalCharges'] = pd.to_numeric(df['TotalCharges'], errors='coerce').fillna(0)
# サービス加入数(ロックイン効果の指標)
service_cols = ['OnlineSecurity', 'OnlineBackup', 'DeviceProtection',
'TechSupport', 'StreamingTV', 'StreamingMovies']
df['num_services'] = df[service_cols].apply(
lambda row: (row == 'Yes').sum(), axis=1
)
# 離反率との関係を確認
print(df.groupby('num_services')['Churn'].apply(
lambda x: (x == 'Yes').mean()
))
月額料金とtenureの交互作用
# 月額料金あたりの利用月数(コスパ感の指標)
df['charge_per_tenure'] = np.where(
df['tenure'] > 0,
df['MonthlyCharges'] / df['tenure'],
df['MonthlyCharges']
)
# 総支払額と月額の比率(実質利用期間の指標)
df['total_monthly_ratio'] = np.where(
df['MonthlyCharges'] > 0,
df['TotalCharges'] / df['MonthlyCharges'],
0
)
契約の安定性スコア
# 契約安定性スコア(複数指標の組み合わせ)
def contract_stability_score(row):
score = 0
# 長期契約 +2
if row['Contract'] == 'Two year':
score += 2
elif row['Contract'] == 'One year':
score += 1
# 自動引き落とし +1
if row['PaymentMethod'] in ['Bank transfer (automatic)', 'Credit card (automatic)']:
score += 1
# ペーパーレスでない +1(離反率が低い傾向)
if row['PaperlessBilling'] == 'No':
score += 1
return score
df['stability_score'] = df.apply(contract_stability_score, axis=1)
tenureグループ
# tenureをビニング(顧客ライフサイクルステージ)
df['tenure_group'] = pd.cut(
df['tenure'],
bins=[-1, 6, 12, 24, 48, 72],
labels=['0-6m', '7-12m', '13-24m', '25-48m', '49-72m']
)
# 新規顧客フラグ
df['is_new_customer'] = (df['tenure'] <= 6).astype(int)
# 長期顧客フラグ
df['is_loyal_customer'] = (df['tenure'] >= 48).astype(int)
交互作用特徴量
# 高リスクの組み合わせを特徴量化
# EDAで発見した高リスクパターン
df['high_risk_combo'] = (
(df['Contract'] == 'Month-to-month') &
(df['InternetService'] == 'Fiber optic') &
(df['tenure'] <= 12)
).astype(int)
# Fiber optic × セキュリティなし
df['fiber_no_security'] = (
(df['InternetService'] == 'Fiber optic') &
(df['OnlineSecurity'] == 'No')
).astype(int)
# 単身 × 短期契約
df['single_monthly'] = (
(df['Partner'] == 'No') &
(df['Dependents'] == 'No') &
(df['Contract'] == 'Month-to-month')
).astype(int)
月額料金の相対指標
# 同じインターネットサービスタイプ内での料金順位
df['charge_rank_in_service'] = df.groupby('InternetService')['MonthlyCharges'].rank(pct=True)
# 平均との差分
avg_charge = df.groupby('InternetService')['MonthlyCharges'].transform('mean')
df['charge_diff_from_avg'] = df['MonthlyCharges'] - avg_charge
特徴量の評価
from sklearn.feature_selection import mutual_info_classif
# 数値化した新特徴量の情報利得を計算
new_features = ['num_services', 'charge_per_tenure', 'total_monthly_ratio',
'stability_score', 'is_new_customer', 'is_loyal_customer',
'high_risk_combo', 'fiber_no_security', 'single_monthly',
'charge_rank_in_service', 'charge_diff_from_avg']
y = (df['Churn'] == 'Yes').astype(int)
X_new = df[new_features].fillna(0)
mi_scores = mutual_info_classif(X_new, y, random_state=42)
mi_df = pd.DataFrame({
'feature': new_features,
'mutual_info': mi_scores
}).sort_values('mutual_info', ascending=False)
print("新特徴量の情報利得:")
print(mi_df.to_string(index=False))
特徴量エンジニアリングの効果測定
# ベースライン(元の特徴量のみ)vs 拡張特徴量
from xgboost import XGBClassifier
from sklearn.metrics import roc_auc_score
# 元の特徴量でのスコア
model_base = XGBClassifier(n_estimators=100, random_state=42, use_label_encoder=False, eval_metric='auc')
model_base.fit(X_train_original, y_train)
score_base = roc_auc_score(y_val, model_base.predict_proba(X_val_original)[:, 1])
# 拡張特徴量でのスコア
model_enhanced = XGBClassifier(n_estimators=100, random_state=42, use_label_encoder=False, eval_metric='auc')
model_enhanced.fit(X_train_enhanced, y_train)
score_enhanced = roc_auc_score(y_val, model_enhanced.predict_proba(X_val_enhanced)[:, 1])
print(f"ベースライン AUC-ROC: {score_base:.4f}")
print(f"拡張特徴量 AUC-ROC: {score_enhanced:.4f}")
print(f"改善幅: +{score_enhanced - score_base:.4f}")
まとめ
| 項目 | ポイント |
|---|---|
| ドメイン特徴量 | num_services, stability_score |
| 交互作用 | high_risk_combo, fiber_no_security |
| ビニング | tenure_group, is_new_customer |
| 相対指標 | charge_rank_in_service, charge_diff_from_avg |
| 評価方法 | 情報利得(Mutual Information)で有効性を確認 |
チェックリスト
- ドメイン知識から3つ以上の特徴量を生成できる
- 交互作用特徴量を作成できる
- 特徴量の有効性を情報利得で評価できる
- 特徴量追加前後の性能改善を測定できる
次のステップへ
特徴量エンジニアリングで性能が向上した。次はハイパーパラメータチューニングで、モデルの性能をさらに引き出そう。
推定読了時間: 30分