MT法(マハラノビス・タグチ法)による異常検知を理解する

MT法(マハラノビス・タグチ法, Mahalanobis-Taguchi method)は、マハラノビス距離を基盤とした異常検知手法です。田口玄一によって提唱された品質工学(タグチメソッド)の一部であり、正常データの分布からの逸脱度を測ることで異常を検知します。

MT法はシンプルでありながら実用性が高く、製造業の品質管理やロケットのヘルスモニタリングなど、幅広い分野で活用されています。IHIが開発するイプシロンロケットでもMT法に基づく異常検知が利用されています。

本記事の内容

  • MT法の理論的背景
  • マハラノビス距離の正規化
  • SN比による特徴量選択
  • Pythonでのスクラッチ実装

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

MT法の概要

MT法は以下の3つのステップで構成されます。

  1. 単位空間の構築: 正常データ群(基準データ)から平均ベクトルと共分散行列を計算
  2. マハラノビス距離の計算: 評価対象データの正常データからの距離を算出
  3. 特徴量選択: SN比を用いて有効な特徴量を選択(MTS法)

マハラノビス距離の定義

$p$ 次元のデータ $\bm{x}$ に対するマハラノビス距離は、正常データの平均 $\bm{\mu}$ と共分散行列 $\bm{\Sigma}$ を用いて以下のように定義されます。

$$ D^2(\bm{x}) = (\bm{x} – \bm{\mu})^T \bm{\Sigma}^{-1} (\bm{x} – \bm{\mu}) $$

MT法では、これを次元数 $p$ で正規化したマハラノビス距離(MD)を用います。

$$ MD(\bm{x}) = \frac{1}{p} (\bm{x} – \bm{\mu})^T \bm{\Sigma}^{-1} (\bm{x} – \bm{\mu}) $$

正規化することで、正常データにおける $MD$ の期待値がおよそ1になります。これにより、変数の数によらず統一的な基準で異常度を評価できます。

導出: なぜ $p$ で正規化するのか

正常データが $p$ 次元の多変量正規分布 $\mathcal{N}(\bm{\mu}, \bm{\Sigma})$ に従うとき、マハラノビス距離の二乗はカイ二乗分布に従います。

$$ D^2(\bm{x}) = (\bm{x} – \bm{\mu})^T \bm{\Sigma}^{-1} (\bm{x} – \bm{\mu}) \sim \chi^2(p) $$

カイ二乗分布 $\chi^2(p)$ の期待値は $p$ であるため、

$$ E[D^2] = p $$

したがって、$MD = D^2 / p$ とすると $E[MD] = 1$ となり、正常データのMDは1付近の値を取ります。MDが1から大きく離れたデータを異常と判定します。

SN比による特徴量選択(MTS法)

MT法の発展形であるMTS法(Mahalanobis-Taguchi System)では、SN比(Signal-to-Noise ratio)を用いて有効な特徴量を選択します。

全特徴量を使ったMDと、一部の特徴量を除外したMDを比較し、異常データと正常データの分離度が向上する特徴量の組み合わせを探索します。

SN比は以下の「望大特性」で評価します。

$$ \eta = -10 \log_{10}\left(\frac{1}{n_a}\sum_{i=1}^{n_a} \frac{1}{MD_i}\right) $$

ここで $n_a$ は異常データの数、$MD_i$ は異常データのマハラノビス距離です。SN比が大きいほど、正常と異常の分離が良いことを意味します。

Pythonでの実装

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

np.random.seed(42)

class MTMethod:
    """MT法(マハラノビス・タグチ法)による異常検知"""

    def __init__(self):
        self.mu = None
        self.sigma_inv = None
        self.p = None

    def fit(self, X_normal):
        """正常データから単位空間を構築"""
        self.p = X_normal.shape[1]
        self.mu = X_normal.mean(axis=0)
        sigma = np.cov(X_normal.T)
        self.sigma_inv = np.linalg.inv(sigma)
        return self

    def mahalanobis_distance(self, X):
        """正規化マハラノビス距離(MD)を計算"""
        diff = X - self.mu
        md = np.array([d @ self.sigma_inv @ d for d in diff]) / self.p
        return md

    def predict(self, X, threshold=None):
        """異常判定(threshold=Noneの場合はMD>4を閾値とする)"""
        md = self.mahalanobis_distance(X)
        if threshold is None:
            threshold = 4.0  # 一般的な経験的閾値
        return (md > threshold).astype(int), md

# --- データ生成 ---
n_normal = 200
n_anomaly = 15
p = 3

# 正常データ
mean_normal = np.array([5.0, 3.0, 7.0])
cov_normal = np.array([
    [1.0, 0.5, 0.3],
    [0.5, 1.5, 0.2],
    [0.3, 0.2, 2.0]
])
X_normal = np.random.multivariate_normal(mean_normal, cov_normal, n_normal)

# 異常データ(平均からずれたデータ)
X_anomaly = np.random.multivariate_normal(
    mean_normal + np.array([3.0, 2.0, 4.0]),
    cov_normal * 0.5,
    n_anomaly
)

# --- MT法の適用 ---
mt = MTMethod()
mt.fit(X_normal)

# 正常データのMD
md_normal = mt.mahalanobis_distance(X_normal)

# 異常データのMD
md_anomaly = mt.mahalanobis_distance(X_anomaly)

# 全データの異常判定
X_all = np.vstack([X_normal, X_anomaly])
labels_true = np.array([0] * n_normal + [1] * n_anomaly)
predictions, md_all = mt.predict(X_all)

print(f"=== MT法による異常検知結果 ===")
print(f"正常データのMD: 平均={md_normal.mean():.3f}, 標準偏差={md_normal.std():.3f}")
print(f"異常データのMD: 平均={md_anomaly.mean():.3f}, 標準偏差={md_anomaly.std():.3f}")
print(f"検出された異常数: {predictions.sum()} / 実際の異常数: {labels_true.sum()}")

# --- 可視化 ---
fig, axes = plt.subplots(1, 3, figsize=(18, 5))

# MDのヒストグラム
ax1 = axes[0]
ax1.hist(md_normal, bins=30, alpha=0.6, label='Normal', color='blue', density=True)
ax1.hist(md_anomaly, bins=15, alpha=0.6, label='Anomaly', color='red', density=True)
ax1.axvline(x=4.0, color='green', linestyle='--', linewidth=2, label='Threshold=4')
ax1.set_xlabel('Mahalanobis Distance (MD)')
ax1.set_ylabel('Density')
ax1.set_title('Distribution of MD')
ax1.legend()
ax1.grid(True, alpha=0.3)

# MDの時系列的なプロット
ax2 = axes[1]
ax2.scatter(range(n_normal), md_normal, c='blue', s=10, alpha=0.5, label='Normal')
ax2.scatter(range(n_normal, n_normal + n_anomaly), md_anomaly,
            c='red', s=30, alpha=0.8, label='Anomaly')
ax2.axhline(y=4.0, color='green', linestyle='--', linewidth=2, label='Threshold')
ax2.set_xlabel('Sample Index')
ax2.set_ylabel('MD')
ax2.set_title('MD for Each Sample')
ax2.legend()
ax2.grid(True, alpha=0.3)

# 正常データのMDとカイ二乗分布の比較
ax3 = axes[2]
md_sorted = np.sort(md_normal * p)  # p倍してカイ二乗分布と比較
x_chi2 = np.linspace(0, md_sorted.max(), 200)
ax3.hist(md_sorted, bins=30, density=True, alpha=0.6, color='blue', label='Data')
ax3.plot(x_chi2, stats.chi2.pdf(x_chi2, df=p), 'r-', linewidth=2,
         label=f'$\\chi^2({p})$')
ax3.set_xlabel('$D^2$')
ax3.set_ylabel('Density')
ax3.set_title('$D^2$ vs $\\chi^2$ Distribution')
ax3.legend()
ax3.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

正常データのMDがおよそ1付近に集中し、異常データのMDが大きな値を取ることが確認できます。また、正規化前のマハラノビス距離の二乗 $D^2$ がカイ二乗分布に従うことも可視化で確認しています。

まとめ

本記事では、MT法(マハラノビス・タグチ法)による異常検知について解説しました。

  • MT法は正常データの平均と共分散から単位空間を構築し、マハラノビス距離で異常度を評価する手法
  • 次元数 $p$ で正規化することで、正常データのMDの期待値が1になる
  • $D^2 \sim \chi^2(p)$ の性質に基づき、統計的な閾値設定が可能
  • MTS法ではSN比を用いた特徴量選択によってさらに判別精度を向上できる

次のステップとして、以下の記事も参考にしてください。