混合ガウスモデル(GMM)による異常検知 — 多峰の正常を密度でとらえる

マハラノビス距離による異常検知の最後で、重大な限界に触れました。マハラノビス距離は正常を「1つの楕円(単峰のガウス分布)」とみなすため、正常が複数の塊(多峰)に分かれていると破綻するのです。たとえば工場の機械が「低速運転」と「高速運転」という2つの正常モードを持つとき、その中間の状態は本来異常なのに、単一ガウスは「2つの塊の真ん中=最も平均に近い=最も正常」と誤判定してしまいます。

この問題を解決するのが 混合ガウスモデル(Gaussian Mixture Model, GMM)による異常検知です。アイデアは自然です——正常が複数の塊から成るなら、複数のガウス分布を重ね合わせて正常をモデル化すればよい。そして、その混合分布のもとで確率密度が低い(ありえない)点を異常とします。これは「正常領域を距離で測る」マハラノビスから、「正常の確率密度を推定する」密度ベースの異常検知への一歩です。

本記事では、単一ガウスの限界の確認から始め、GMMの定義・EMアルゴリズム・負の対数尤度による異常スコア・BICでの成分数選択までを、Pythonの実測とともに解説します。混合ガウスモデルの理論EMアルゴリズムを先に読むと、推定の中身まで理解できます。

GMM異常検知の概念

図のように、正常データが2つの塊に分かれているとき、それぞれにガウス分布を当て、両方から外れた点(赤)を異常とします。この「複数の正常モード」を扱えるのがGMMの強みです。

単一ガウスはなぜ破綻するのか

まず、単一ガウス(マハラノビス距離)が多峰の正常で何を間違えるのかを、はっきり見ます。

単一ガウスの限界

図は、左右に分かれた2つの正常クラスタに、単一ガウスのマハラノビス距離の等高線を重ねたものです。単一ガウスは全データの平均(=2クラスタのちょうど中間、原点付近)を中心とし、その周りに等高線を描きます。すると、誰もいない中央の谷(0,0)が「最も正常」と判定されてしまう。本来そこは「どちらのモードにも属さない異常な状態」なのに、です。これは平均という1点だけで正常を代表させる手法の構造的な欠陥で、距離の測り方を工夫しても解決しません。正常の「形」そのものを、もっと柔軟に表現する必要があります。

GMM — ガウスの重ね合わせ

そこでGMMは、正常分布を $K$ 個のガウス分布の混合(重み付き和)で表現します。

GMMの式

$$ \begin{equation} p(\bm{x}) = \sum_{k=1}^{K} \pi_k\, \mathcal{N}(\bm{x} \mid \bm{\mu}_k, \Sigma_k) \end{equation} $$

ここで $\pi_k$ は各成分の混合比($\sum_k \pi_k = 1$)、$\bm{\mu}_k, \Sigma_k$ は $k$ 番目のガウスの平均と共分散です。複数の山を重ねることで、単峰のガウスでは表せない多峰の分布を柔軟に表現できます。$K=1$ なら単なる単一ガウス(マハラノビス)に戻るので、GMMはマハラノビスを多峰へ一般化したもの、と理解できます。

GMMが学んだ密度

図は、2成分のGMMが学習した確率密度です。2つの山がきれいに表現され、その間の谷(中央)は密度が低くなっています。この「密度の地形」こそがGMMの正常モデルであり、低地(低密度)に落ちた点が異常と判定されます。

EMアルゴリズムで学習する

GMMのパラメータ(各ガウスの $\pi_k, \bm{\mu}_k, \Sigma_k$)は、EMアルゴリズムで推定します。

EMアルゴリズム

EMは2ステップの反復です。Eステップで「各データ点が、どの成分にどれくらいの確率で属するか(負担率)」を計算し、Mステップでその割り当てに基づいて各ガウスのパラメータを更新します。どの点がどの成分に属するかが未知(潜在変数)であるため、この鶏と卵の関係を反復で解きほぐすのがEMの役割です。対数尤度が収束するまで繰り返すと、データを最もよく説明するガウスの配置が得られます。詳細はEMアルゴリズムの記事に譲りますが、ここでは「データに複数のガウスを自動的にフィットさせる手続き」と捉えれば十分です。

異常スコア — 負の対数尤度

GMMで正常分布を学んだら、異常スコアは単純です。

異常スコア

$$ \begin{equation} \mathrm{score}(\bm{x}) = -\log p(\bm{x}) \end{equation} $$

学習した混合分布のもとで、点 $\bm{x}$ の確率密度 $p(\bm{x})$ を評価し、その負の対数を異常スコアとします。密度が高い(ありそうな)点はスコアが低く、密度が低い(ありえない)点はスコアが高い=異常。「正常モデルのもとでどれだけ起こりにくいか」を素直に数値化したものです。マハラノビス距離が「中心からの距離」だったのに対し、GMMは「確率密度の低さ」で測る——これが距離ベースと密度ベースの違いです。

Pythonで確かめる

左右に分かれた2つの正常クラスタに、「中央の谷の点」と「外側の外れ点」を異常として混ぜます。単一ガウス(マハラノビス距離)とGMM(2成分)で、異常をどれだけ捉えられるか比べます。

import numpy as np
from sklearn.mixture import GaussianMixture
from sklearn.covariance import EmpiricalCovariance
from sklearn.metrics import roc_auc_score

rng = np.random.default_rng(0)
Xn = np.vstack([rng.normal([-3,0], 0.6, (300,2)),
                rng.normal([ 3,0], 0.6, (300,2))])         # 正常:2クラスタ
Xa = np.array([[0,0],[0,0.5],[0,-0.5],[-3,3],[3,-3],[6,3]]) # 異常:中央の谷+外側
X = np.vstack([Xn, Xa]); y = np.r_[np.zeros(len(Xn)), np.ones(len(Xa))]

cov = EmpiricalCovariance().fit(Xn)                          # 単一ガウス
maha = cov.mahalanobis(X)
gmm = GaussianMixture(2, covariance_type="full", random_state=0).fit(Xn)
nll = -gmm.score_samples(X)                                 # GMM:負の対数尤度

print(f"単一ガウス(Mahalanobis) ROC-AUC = {roc_auc_score(y, maha):.3f}")
print(f"GMM(2成分)            ROC-AUC = {roc_auc_score(y, nll):.3f}")
print(f"中央(0,0): Mahalanobis²={cov.mahalanobis([[0,0]])[0]:.2f}  GMM-NLL={-gmm.score_samples([[0,0]])[0]:.2f}")

出力は次の通りです。

単一ガウス(Mahalanobis) ROC-AUC = 0.529
GMM(2成分)            ROC-AUC = 1.000
中央(0,0): Mahalanobis²=0.00  GMM-NLL=12.66

検出の比較

結果は決定的です。単一ガウスのROC-AUCは 0.529——ほぼランダム(0.5)と同じで、まったく機能していません。一方GMMは 1.000 と完璧です。とりわけ象徴的なのが中央の点(0,0)で、単一ガウスはマハラノビス距離²=0.00(最も正常と判定)なのに、GMMは負の対数尤度12.66(強い異常と判定)。同じ点に対して正反対の評価です。図でも、単一ガウス(左)は中央の谷の異常を完全に見逃していますが、GMM(右)は谷も外側もすべて捉えています。「正常の形」を正しく表現できるかどうかが、いかに決定的かを示す好例です。

成分数Kをどう選ぶか

GMMで悩むのは「成分数 $K$ をいくつにするか」です。多すぎると過学習(正常のノイズまで拾う)、少なすぎると表現力不足になります。

BICによる選択

これには BIC(ベイズ情報量基準) がよく使われます。BICは「データへの当てはまりの良さ」と「モデルの複雑さ(パラメータ数)」のバランスを測り、小さいほど良いモデルとされます。図のように $K$ を変えてBICを計算し、最小になる $K$ を選びます。今回のデータでは $K=2$ でBICが最小となり、データの真の構造(2クラスタ)を正しく言い当てました。BICのほかAIC(赤池情報量基準)も使われますが、AICはやや複雑なモデルを選びがちです。

共分散タイプの選択

GMMにはもう1つ調整点があります。各ガウスの共分散行列の形(covariance_type)です。

共分散タイプ

  • spherical:等方的な円(各成分は球形)。パラメータ最少。
  • diag:軸に沿った楕円(対角共分散)。
  • tied:全成分が同じ共分散を共有。
  • full:任意の向き・形の楕円(自由)。最も表現力が高いが過学習しやすい。

データが少ないときは制約の強いタイプ(spherical/diag)、データが豊富で複雑な形なら full、と使い分けます。これも表現力と過学習のトレードオフであり、BICで比較して選ぶのが定石です。

ROC比較

注意点

GMMによる異常検知の実務的な注意をまとめます。

  • 成分数と初期値に敏感:$K$ の選択を誤ると性能が落ちます。EMは局所最適に陥るため、複数の初期値から学習する(sklearnのn_init)のが安全です。
  • 高次元での密度推定は難しい:次元が高いとガウス分布のフィットに大量のデータが要り(次元の呪い)、共分散推定も不安定になります。高次元では次元削減や、後述のオートエンコーダ系と併用します。
  • 正常データの純度:他の密度ベース手法と同様、訓練データに異常が混ざると密度推定が歪みます。
  • 滑らかな密度の仮定:GMMはガウスの和なので、なめらかな密度しか表せません。複雑・非ガウス的な正常分布には、よりノンパラメトリックな手法(カーネル密度推定)や近傍ベース(次々回のLOF)が向くこともあります。

まとめ

混合ガウスモデル(GMM)による異常検知を解説しました。

  • 単一ガウス(マハラノビス)は多峰の正常で破綻し、2クラスタの中間(谷)を「最も正常」と誤判定する。実測でもROC-AUC 0.529とほぼランダムだった。
  • GMMは $K$ 個のガウスの混合 $p(\bm{x})=\sum_k \pi_k \mathcal{N}(\bm{x}\mid\bm{\mu}_k,\Sigma_k)$ で多峰の正常をモデル化。パラメータはEMアルゴリズムで推定。
  • 異常スコアは負の対数尤度 $-\log p(\bm{x})$。密度の低い点ほど異常。実測でGMMはROC-AUC 1.000、中央の谷も正しく異常と判定した。
  • 成分数 $K$ はBICで選択(今回は$K=2$が最適)。共分散タイプも表現力と過学習のバランスで選ぶ。
  • 高次元・非ガウス的な正常分布では限界があり、近傍ベースや再構成ベースへ続く。

次の記事では、確率分布を仮定せず、正常データを囲む境界を直接学ぶOne-Class SVMによる異常検知を掘り下げます。