モデルドリフトは「データドリフト」「コンセプトドリフト」「予測ドリフト」の3種類に分類され、それぞれ検知手法と対処法が異なります。特徴量の分布変化はPSIやKSテストで早期に捉え、教師ラベルが必要なコンセプトドリフトは遅延評価で後追い確認するのが基本戦略です。検知しっぱなしで放置するのは、火災報知器の電池を抜いておくようなものです。再学習トリガーとロールバック判断までを自動化してこそ、ML運用が初めて本番環境で生き延びます。

モデルドリフトとは

モデルドリフトとは、本番運用中の機械学習モデルの予測精度が、時間経過とともに劣化していく現象です。学習時には正しく機能していたモデルが、数週間から数ヶ月のうちに「なぜか外れるようになる」のは、多くの場合ドリフトが原因と考えて差し支えありません。ドリフトは大きく3種類に分類されます。

第一に「データドリフト(共変量シフト)」は、入力特徴量の分布そのものが変化する現象です。たとえばECサイトで、コロナ禍以降に顧客の購買年齢層が大きくシフトした場合がこれに該当します。第二に「コンセプトドリフト」は、入力と出力の関係性そのものが変化する現象で、同じ特徴量から導かれる答えが時代とともに変わっていくケースを指します。第三に「予測ドリフト」は、モデルの出力分布が変化する現象で、データドリフトとコンセプトドリフトの両方の結果として現れます。

【ドリフトの種類と発生メカニズム】

データドリフト(Covariate Shift)
  [学習時 P(X)] --変化--> [本番時 P(X)]
    P(Y|X) は不変
    例: 顧客年齢層の変化、季節変動

コンセプトドリフト(Concept Drift)
  [学習時 P(Y|X)] --変化--> [本番時 P(Y|X)]
    P(X) は不変でもOK
    例: 市場ルール変更、消費者嗜好の変化

予測ドリフト(Prediction Drift)
  [学習時 P(Y_hat)] --変化--> [本番時 P(Y_hat)]
    データ or コンセプトドリフトの結果
    早期シグナルとして利用可能

ドリフトを放置すると何が起きるかは想像に難くありません。レコメンドは的外れになり、与信モデルは不良債権を増やし、需要予測は在庫過剰か欠品を招きます。MLOpsの中核機能として、ドリフト監視は地味ながら最も費用対効果が高い投資のひとつです。MLOpsの全体像MLパイプライン設計も併せてご確認ください。

ドリフト検知の統計手法

ドリフト検知には複数の統計手法があり、特徴量のタイプや計算コストの許容度によって使い分けます。代表的な4手法を整理します。

PSI(Population Stability Index)は、クレジットリスク分野で古くから使われる指標で、2つの分布の差をビンごとに対数比で集約します。解釈が容易で、0.1未満は安定、0.1〜0.25は要注意、0.25超はシフト発生というしきい値が慣習として定着しています。KSテスト(Kolmogorov-Smirnov検定)は連続値に適した手法で、2つの累積分布関数の最大距離を統計量とします。軽量ですが、多次元データには直接使えません。KLダイバージェンスは情報理論由来の指標で、非対称性があるため「学習分布から見た本番分布のずれ」を評価するのに使います。Wasserstein距離は「ある分布を別の分布に変形するための最小コスト」を測る指標で、分布の形状差を正確に捉えられる反面、計算コストは高めです。

手法特徴量タイプ感度計算コスト適した場面
PSI連続・カテゴリ両対応クレジット・スコアリングの定常監視
KSテスト連続のみ個別特徴量の異常検知
KLダイバージェンス離散分布カテゴリ特徴量・予測確率の監視
Wasserstein距離連続非常に高重要特徴量の厳密監視

実装の観点では、Evidently AIのようなOSSライブラリを使うのが現実的です。特徴量ごとの分布比較レポートと統計量算出をワンストップで行えます。

import pandas as pd
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset

# 学習時データと本番データを読み込み
reference_df = pd.read_csv("train_features.csv")
current_df = pd.read_csv("production_features.csv")

# ドリフトレポート生成
report = Report(metrics=[DataDriftPreset()])
report.run(reference_data=reference_df, current_data=current_df)

# JSON で結果取得
result = report.as_dict()
drift_detected = result["metrics"][0]["result"]["dataset_drift"]
num_drifted = result["metrics"][0]["result"]["number_of_drifted_columns"]

print(f"Drift detected: {drift_detected}")
print(f"Drifted features: {num_drifted}")

# HTML レポート出力
report.save_html("drift_report.html")

より詳細な統計量ベースの監視については特徴量ストアの設計と連動させるのが効果的です。

監視ダッシュボードの設計

ドリフト監視は「数値をダッシュボードに並べればよい」という単純な話ではありません。何をどの頻度で観測し、どのしきい値でアラートを上げるかという設計判断が品質を左右します。監視すべきメトリクスは大きく3層に分類できます。入力層では各特徴量の分布統計、モデル層では予測確率の分布、出力層では実測ラベルとのギャップ(精度、AUC、F1など)を見ます。

メトリクス意味しきい値の目安アラートレベル
PSI(重要特徴量)特徴量分布の安定性0.25超Critical
PSI(補助特徴量)特徴量分布の安定性0.1超Warning
予測確率平均モデル出力の偏り過去30日平均±2σWarning
予測クラス分布分類出力の偏りクラス比±20%Critical
実測精度(遅延)真のモデル精度ベースライン-5%Critical
欠損率データパイプライン健全性5%超Warning

Criticalアラートはオンコールエンジニア宛に即時通知し、Warningは日次サマリーに集約するのが運用負荷とのバランスが取れた設計です。全てのメトリクスでアラートを出すと、オオカミ少年状態に陥り、本当に重要な変化を見逃すことになります。モデルレジストリと連携させて、どのモデルバージョンで発生したかを即座に追跡できるようにしておくと、根本原因分析が格段に楽になります。

ドリフト検知後の対応フロー

アラートが鳴ったあとの対応フローを事前に設計しておかないと、監視は単なる不安製造機になります。対応は「一時停止」「ロールバック」「再学習」「許容」の4択で、判断基準を明確化しておくのが鉄則です。予測ドリフトだけならまず再学習を検討し、根本原因が明らかな一時的要因(キャンペーン実施、季節要因)なら許容という判断もあり得ます。

自動化の第一歩は、ドリフト検知から再学習ジョブ起動までをコードで繋ぐことです。下記のスクリプトは、PSIしきい値超過を検知したらAirflowのDAGをトリガーし、Slack通知を送る最小構成の例です。

import requests
from datetime import datetime

def check_and_trigger_retrain(psi_score: float, threshold: float = 0.25):
    if psi_score < threshold:
        print(f"PSI {psi_score:.3f} within limit, no action")
        return

    # Airflow DAG をトリガー
    airflow_url = "http://airflow:8080/api/v1/dags/retrain_pipeline/dagRuns"
    payload = {"conf": {"reason": f"PSI={psi_score:.3f}", "ts": datetime.utcnow().isoformat()}}
    requests.post(airflow_url, json=payload, auth=("admin", "admin"))

    # Slack 通知
    slack_url = "https://hooks.slack.com/services/XXX"
    msg = f":warning: Drift detected (PSI={psi_score:.3f}). Retrain triggered."
    requests.post(slack_url, json={"text": msg})

check_and_trigger_retrain(psi_score=0.31)

ロールバックの判断基準は「新モデルより旧モデルの方が直近の実測精度が高い場合」で明快です。A/Bテストの枠組みで段階的に新モデルを配信し、問題があれば即座に切り戻せる構成にしておくのが安全です。根本原因分析(RCA)は、どの特徴量がいつからドリフトし始めたかを時系列で可視化するだけで、データパイプラインの障害・上流システムの変更・実世界の変化のどれが原因かの当たりが付けられます。

LLMにおけるドリフト

LLMを業務で使っている場合、ドリフトの概念は少し様相が変わります。OpenAIやAnthropicのAPIを利用していると、同じモデル名でも裏側で微妙にアップデートが入り、プロンプトに対する応答が変化することがあります。これは「モデル側のドリフト」と呼ぶべき現象で、自社では制御できません。定期的に評価セットを流してスコアを記録し、想定外の変化を早期に捉える仕組みが必須です。

またRAGシステムでは、インデックス対象の文書が更新されたり、ユーザーの質問の傾向が変化したりすることで、検索精度の劣化が発生します。こちらは「データドリフトのRAG版」と捉えるのが適切で、retrieval品質とgeneration品質を別々にモニタリングする必要があります。クエリの埋め込みベクトル分布の変化、検索上位ドキュメントの変化、ユーザーフィードバック率の変化を追うと、静かに進むRAG劣化を検知できます。予測分析の基礎の考え方は生成AIにも応用可能です。

まとめ

モデルドリフトは、本番運用のMLシステムにとって避けられない宿命です。PSIやKSテストで入力分布を監視し、予測確率と実測精度を多層的に追いかけ、アラート発生時の対応フローを自動化しておく。これが最低限のMLOps運用ラインです。「作って終わり」のモデルは、半年後にはまず間違いなく壊れているとお考えください。ドリフト監視への継続投資こそが、本番MLシステムの寿命を決める最大要因です。

よくある質問

Q. モデルドリフトとは?

A. 本番運用中のモデルが時間とともに精度を低下させる現象です。入力データの分布変化(データドリフト)や、目的変数との関係性の変化(コンセプトドリフト)が原因で発生します。発見が遅れるほど業務への影響が大きくなるため、継続的な監視が不可欠です。

Q. データドリフトとコンセプトドリフトの違いは?

A. データドリフトは入力特徴量の分布変化、コンセプトドリフトは入力と出力の関係性の変化です。データドリフトは統計的手法で早期検知できますが、コンセプトドリフトは教師ラベルが必要なため、検知までに時間がかかる性質があります。

Q. ドリフト検知の頻度はどのくらいが適切ですか?

A. 推論頻度と業務の重要度によります。リアルタイム推論サービスなら日次監視、バッチ推論なら推論サイクルごとの監視が目安です。重要業務では時間単位の監視も検討します。