教師あり学習アプローチ
「異常検知は汎用的だが、ラベル付きデータがあるなら教師あり学習の方が精度は出る。」
田中VPoEが続ける。
「XGBoostとLightGBMを不均衡データ対応で使いこなせるようになってくれ。Focal Lossも試してみよう。」
XGBoost for 不均衡データ
基本設定
import xgboost as xgb
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.metrics import average_precision_score, classification_report
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 不均衡比率の計算
neg = (y_train == 0).sum()
pos = (y_train == 1).sum()
scale = neg / pos
xgb_model = xgb.XGBClassifier(
scale_pos_weight=scale,
max_depth=6,
learning_rate=0.05,
n_estimators=300,
min_child_weight=5,
subsample=0.8,
colsample_bytree=0.8,
reg_alpha=0.1,
reg_lambda=1.0,
eval_metric='aucpr',
use_label_encoder=False,
random_state=42,
n_jobs=-1
)
xgb_model.fit(
X_train, y_train,
eval_set=[(X_test, y_test)],
verbose=50
)
y_prob_xgb = xgb_model.predict_proba(X_test)[:, 1]
print(f"XGBoost PR-AUC: {average_precision_score(y_test, y_prob_xgb):.4f}")
XGBoostのチューニングポイント
不正検知向けXGBoostチューニング:
1. scale_pos_weight: 不均衡比率(neg/pos)を設定
2. max_depth: 3〜8(深すぎると過学習)
3. min_child_weight: 5〜20(少数クラスの葉ノードを安定化)
4. subsample: 0.6〜0.9(行のサブサンプリング)
5. colsample_bytree: 0.6〜0.9(列のサブサンプリング)
6. eval_metric: 'aucpr' を使用('auc' ではなく)
7. early_stopping_rounds: 過学習防止
LightGBM for 不均衡データ
import lightgbm as lgb
lgb_model = lgb.LGBMClassifier(
is_unbalance=True,
max_depth=6,
learning_rate=0.05,
n_estimators=300,
num_leaves=31,
min_child_samples=20,
subsample=0.8,
colsample_bytree=0.8,
reg_alpha=0.1,
reg_lambda=1.0,
metric='average_precision',
random_state=42,
n_jobs=-1
)
lgb_model.fit(
X_train, y_train,
eval_set=[(X_test, y_test)],
callbacks=[
lgb.log_evaluation(50),
lgb.early_stopping(30)
]
)
y_prob_lgb = lgb_model.predict_proba(X_test)[:, 1]
print(f"LightGBM PR-AUC: {average_precision_score(y_test, y_prob_lgb):.4f}")
LightGBM特有の設定
LightGBM固有のパラメータ:
is_unbalance=True: 自動でクラス重み調整
num_leaves: 葉の数(デフォルト31)
min_child_samples: 葉ノードの最小サンプル数(20〜50推奨)
is_unbalance vs scale_pos_weight:
is_unbalance=True: 内部でweight = total / (2 * count_class)
scale_pos_weight: 手動で重みを指定
→ ビジネスコストに合わせるなら scale_pos_weight を使用
Focal Loss の適用
XGBoostでのFocal Loss実装
import numpy as np
def focal_loss_objective(y_pred, dtrain, alpha=0.25, gamma=2.0):
"""Focal Loss のカスタム目的関数"""
y_true = dtrain.get_label()
sigmoid = 1.0 / (1.0 + np.exp(-y_pred))
# Focal weight
p_t = y_true * sigmoid + (1 - y_true) * (1 - sigmoid)
alpha_t = y_true * alpha + (1 - y_true) * (1 - alpha)
focal_weight = alpha_t * (1 - p_t) ** gamma
# Gradient
grad = focal_weight * (sigmoid - y_true)
# Hessian(近似)
hess = focal_weight * sigmoid * (1 - sigmoid)
hess = np.maximum(hess, 1e-7)
return grad, hess
def focal_loss_eval(y_pred, dtrain, alpha=0.25, gamma=2.0):
"""Focal Loss の評価関数"""
y_true = dtrain.get_label()
sigmoid = 1.0 / (1.0 + np.exp(-y_pred))
p_t = y_true * sigmoid + (1 - y_true) * (1 - sigmoid)
alpha_t = y_true * alpha + (1 - y_true) * (1 - alpha)
loss = -alpha_t * (1 - p_t) ** gamma * np.log(np.maximum(p_t, 1e-7))
return 'focal_loss', loss.mean()
# 使用
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)
params = {
'max_depth': 6,
'learning_rate': 0.05,
'subsample': 0.8,
'colsample_bytree': 0.8,
}
model_focal = xgb.train(
params,
dtrain,
num_boost_round=300,
obj=lambda y_pred, dtrain: focal_loss_objective(y_pred, dtrain, alpha=0.75, gamma=2.0),
custom_metric=lambda y_pred, dtrain: focal_loss_eval(y_pred, dtrain, alpha=0.75, gamma=2.0),
evals=[(dtest, 'test')],
verbose_eval=50
)
交差検証による安定した評価
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import average_precision_score
import numpy as np
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
pr_aucs = []
for fold, (train_idx, val_idx) in enumerate(skf.split(X, y)):
X_fold_train, X_fold_val = X.iloc[train_idx], X.iloc[val_idx]
y_fold_train, y_fold_val = y.iloc[train_idx], y.iloc[val_idx]
model = lgb.LGBMClassifier(
is_unbalance=True,
max_depth=6,
learning_rate=0.05,
n_estimators=300,
random_state=42
)
model.fit(
X_fold_train, y_fold_train,
eval_set=[(X_fold_val, y_fold_val)],
callbacks=[lgb.early_stopping(30), lgb.log_evaluation(0)]
)
y_prob = model.predict_proba(X_fold_val)[:, 1]
pr_auc = average_precision_score(y_fold_val, y_prob)
pr_aucs.append(pr_auc)
print(f"Fold {fold+1}: PR-AUC = {pr_auc:.4f}")
print(f"\n平均 PR-AUC: {np.mean(pr_aucs):.4f} (+/- {np.std(pr_aucs):.4f})")
モデルの比較
| モデル | 特徴 | 不均衡対策 | 推論速度 |
|---|---|---|---|
| XGBoost | 正則化が強い | scale_pos_weight | 中 |
| LightGBM | 学習が高速 | is_unbalance | 高速 |
| XGBoost+Focal | 難しいサンプルに集中 | Focal Loss | 中 |
| アンサンブル | 複数モデルの統合 | 各モデルの対策 | 低速 |
まとめ
| 項目 | ポイント |
|---|---|
| XGBoost | scale_pos_weight + eval_metric=‘aucpr’ |
| LightGBM | is_unbalance=True、学習が高速 |
| Focal Loss | 難しいサンプルに集中、alpha/gammaの調整が必要 |
| 交差検証 | StratifiedKFold で不均衡を維持した安定評価 |
チェックリスト
- XGBoostとLightGBMの不均衡対策パラメータを設定できる
- eval_metricにaucprを使う理由を説明できる
- Focal Lossの実装方法を理解した
- 層化交差検証で安定した評価ができる
次のステップへ
教師あり学習モデルを構築できたところで、次はAutoencoder による異常検知アプローチを学ぼう。
推定読了時間: 30分