マハラノビス距離は、ユークリッド距離のような統計的な距離の指標であり、多変量のデータ解析や異常検知でよく使われる指標です。
$$ d^2 = (\bm{x} – \bm{\mu})^T \bm{\Sigma}^{-1} (\bm{x} – \bm{\mu}) $$
機械学習をやっていると頻繁に登場するマハラノビス距離ですが、実際には幾何学的にも面白い特徴があります。今回はこのマハラノビス距離について、数学的な定義から幾何学的な意味、そして Python での可視化まで解説を行います。
本記事の内容
- マハラノビス距離の定義と直感的な理解
- ユークリッド距離との比較
- 共分散行列と楕円体の関係
- Python での実装と可視化
前提知識
この記事を読む前に、以下の概念を理解しておくと理解が深まります。
- 多変量ガウス分布の基本(平均ベクトル、共分散行列)
- 線形代数の基本(固有値分解、逆行列)
マハラノビス距離とは
マハラノビス距離は、インドの統計学者 P.C. マハラノビスが1936年に提案した距離指標です。
ユークリッド距離は各次元を等しく扱いますが、マハラノビス距離はデータの分散や相関を考慮した距離です。つまり、分散が大きい方向には距離を短く、分散が小さい方向には距離を長く測ります。
数学的定義
$D$ 次元のデータ点 $\bm{x}$ と、平均ベクトル $\bm{\mu}$、共分散行列 $\bm{\Sigma}$ が与えられたとき、マハラノビス距離の二乗は次のように定義されます。
$$ \begin{equation} d_M^2(\bm{x}, \bm{\mu}) = (\bm{x} – \bm{\mu})^T \bm{\Sigma}^{-1} (\bm{x} – \bm{\mu}) \end{equation} $$
ここで $\bm{\Sigma}^{-1}$ は共分散行列の逆行列(精度行列)です。
ユークリッド距離との関係
共分散行列が単位行列 $\bm{\Sigma} = \bm{I}$ のとき、マハラノビス距離はユークリッド距離に一致します。
$$ d_M^2 = (\bm{x} – \bm{\mu})^T \bm{I}^{-1} (\bm{x} – \bm{\mu}) = (\bm{x} – \bm{\mu})^T (\bm{x} – \bm{\mu}) = \|\bm{x} – \bm{\mu}\|^2 $$
つまり、マハラノビス距離はユークリッド距離の一般化と言えます。
幾何学的な意味
マハラノビス距離の幾何学的な意味を理解するために、共分散行列の固有値分解を考えましょう。
共分散行列 $\bm{\Sigma}$ は対称正定値行列であるため、次のように固有値分解できます。
$$ \begin{equation} \bm{\Sigma} = \bm{U} \bm{\Lambda} \bm{U}^T \end{equation} $$
ここで $\bm{U}$ は固有ベクトルを列に並べた直交行列、$\bm{\Lambda} = \text{diag}(\lambda_1, \lambda_2, \dots, \lambda_D)$ は固有値を対角に並べた行列です。
このとき、$\bm{\Sigma}^{-1}$ は、
$$ \begin{equation} \bm{\Sigma}^{-1} = \bm{U} \bm{\Lambda}^{-1} \bm{U}^T = \bm{U} \text{diag}(1/\lambda_1, 1/\lambda_2, \dots, 1/\lambda_D) \bm{U}^T \end{equation} $$
ここで $\bm{z} = \bm{U}^T (\bm{x} – \bm{\mu})$ と変数変換すると、マハラノビス距離は、
$$ \begin{align} d_M^2 &= (\bm{x} – \bm{\mu})^T \bm{U} \bm{\Lambda}^{-1} \bm{U}^T (\bm{x} – \bm{\mu}) \\ &= \bm{z}^T \bm{\Lambda}^{-1} \bm{z} \\ &= \sum_{i=1}^{D} \frac{z_i^2}{\lambda_i} \end{align} $$
(4) 式は、各主軸方向の距離を固有値(分散)で正規化したものであることを示しています。固有値 $\lambda_i$ が大きい方向(分散が大きい方向)ではスケーリング係数 $1/\lambda_i$ が小さくなるため、その方向への距離は短く測られます。
等距離面は楕円体
$d_M^2 = c$(定数)とすると、(4) 式は、
$$ \sum_{i=1}^{D} \frac{z_i^2}{\lambda_i} = c $$
となり、これは主軸方向に $\sqrt{c \lambda_i}$ を半径とする楕円体の方程式です。
多変量ガウス分布との関係
多変量ガウス分布の確率密度関数は、
$$ \mathcal{N}(\bm{x}|\bm{\mu}, \bm{\Sigma}) = \frac{1}{\sqrt{(2\pi)^D |\bm{\Sigma}|}} \exp\left(-\frac{1}{2} d_M^2\right) $$
つまり、マハラノビス距離はガウス分布の指数部分に直接現れます。マハラノビス距離が等しい点は、ガウス分布の等確率密度面(楕円体)上の点に対応します。
Python での実装
マハラノビス距離の幾何学的意味を Python で可視化しましょう。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from scipy.spatial.distance import mahalanobis
# 2次元データの生成
np.random.seed(42)
mean = np.array([2, 3])
cov = np.array([[3.0, 1.5],
[1.5, 1.0]])
data = np.random.multivariate_normal(mean, cov, 300)
# 共分散行列の固有値分解
eigenvalues, eigenvectors = np.linalg.eigh(cov)
angle = np.degrees(np.arctan2(eigenvectors[1, 1], eigenvectors[0, 1]))
# マハラノビス距離の計算
cov_inv = np.linalg.inv(cov)
distances = np.array([mahalanobis(x, mean, cov_inv) for x in data])
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
# 左: ユークリッド距離
ax1 = axes[0]
euclidean_dist = np.sqrt(np.sum((data - mean)**2, axis=1))
scatter1 = ax1.scatter(data[:, 0], data[:, 1], c=euclidean_dist, cmap='viridis', s=15, alpha=0.7)
# 等距離円
for r in [1, 2, 3]:
circle = plt.Circle(mean, r, fill=False, color='red', linestyle='--', alpha=0.5)
ax1.add_patch(circle)
ax1.set_xlabel('x1', fontsize=12)
ax1.set_ylabel('x2', fontsize=12)
ax1.set_title('Euclidean Distance', fontsize=13)
ax1.set_aspect('equal')
ax1.set_xlim(-3, 7)
ax1.set_ylim(-1, 7)
plt.colorbar(scatter1, ax=ax1, label='Distance')
ax1.grid(True, alpha=0.3)
# 右: マハラノビス距離
ax2 = axes[1]
scatter2 = ax2.scatter(data[:, 0], data[:, 1], c=distances, cmap='viridis', s=15, alpha=0.7)
# 等距離楕円
for r in [1, 2, 3]:
ell = Ellipse(xy=mean,
width=2*r*np.sqrt(eigenvalues[1]),
height=2*r*np.sqrt(eigenvalues[0]),
angle=angle,
fill=False, color='red', linestyle='--', alpha=0.5)
ax2.add_patch(ell)
ax2.set_xlabel('x1', fontsize=12)
ax2.set_ylabel('x2', fontsize=12)
ax2.set_title('Mahalanobis Distance', fontsize=13)
ax2.set_aspect('equal')
ax2.set_xlim(-3, 7)
ax2.set_ylim(-1, 7)
plt.colorbar(scatter2, ax=ax2, label='Distance')
ax2.grid(True, alpha=0.3)
plt.suptitle('Euclidean vs Mahalanobis Distance', fontsize=14)
plt.tight_layout()
plt.show()
左のグラフではユークリッド距離による等距離面(円)、右のグラフではマハラノビス距離による等距離面(楕円)が描かれています。マハラノビス距離の方がデータの分布形状を適切に反映していることがわかります。
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial.distance import mahalanobis
# 異常検知への応用例
np.random.seed(42)
mean = np.array([0, 0])
cov = np.array([[2.0, 1.2],
[1.2, 1.0]])
# 正常データ
normal_data = np.random.multivariate_normal(mean, cov, 200)
# 異常データ
anomaly_data = np.array([[4, 0], [-3, 3], [3, -2], [0, 4]])
cov_inv = np.linalg.inv(cov)
# 閾値(マハラノビス距離 = 3)
threshold = 3.0
fig, ax = plt.subplots(figsize=(8, 6))
ax.scatter(normal_data[:, 0], normal_data[:, 1], c='blue', s=15, alpha=0.5, label='Normal')
for i, pt in enumerate(anomaly_data):
d = mahalanobis(pt, mean, cov_inv)
color = 'red' if d > threshold else 'orange'
ax.scatter(pt[0], pt[1], c=color, s=100, marker='x', linewidths=2)
ax.annotate(f'd={d:.2f}', (pt[0]+0.1, pt[1]+0.2), fontsize=10)
# 閾値楕円
eigenvalues, eigenvectors = np.linalg.eigh(cov)
angle = np.degrees(np.arctan2(eigenvectors[1, 1], eigenvectors[0, 1]))
from matplotlib.patches import Ellipse
ell = Ellipse(xy=mean, width=2*threshold*np.sqrt(eigenvalues[1]),
height=2*threshold*np.sqrt(eigenvalues[0]),
angle=angle, fill=False, color='green', linestyle='--', linewidth=2, label=f'Threshold (d={threshold})')
ax.add_patch(ell)
ax.set_xlabel('x1', fontsize=12)
ax.set_ylabel('x2', fontsize=12)
ax.set_title('Anomaly Detection with Mahalanobis Distance', fontsize=13)
ax.legend(fontsize=10)
ax.set_aspect('equal')
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
このコードでは、マハラノビス距離を使った異常検知の例を示しています。楕円の外側にある点ほど異常の可能性が高いと判断されます。
まとめ
本記事では、マハラノビス距離の幾何学的な意味を解説しました。
- マハラノビス距離はデータの分散と相関を考慮した距離指標であり、ユークリッド距離の一般化
- 共分散行列の固有値分解により、各主軸方向の距離を分散で正規化したものと解釈できる
- 等距離面は楕円体であり、多変量ガウス分布の等確率密度面に対応する
- 異常検知において、マハラノビス距離はデータの分布構造を考慮した判定ができる
次のステップとして、以下の記事も参考にしてください。