43
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

マハラノビス距離を徹底解説

Last updated at Posted at 2022-12-14

異常検知で良く用いられる「マハラノビス距離」について徹底解説します。

STEP1. さっと雰囲気をつかむ

マハラノビス距離とは、データの外れ具合を定量化する指標です。下の例で考えてみましょう。

fig1.png

平均からのユークリッド距離は点1も点2も同じですが、データの分布を考慮すると、点1よりも点2の方が平均から外れているように見えると思います。

計算方法は後で示すとして、マハラノビス距離とユークリッド距離の計算結果をまとめると下表のようになります。

特徴 平均との間のマハラノビス距離 平均との間のユークリッド距離
点1 分布から外れていない 2.12 3
点2 分布から大きく外れている 5.20 3

マハラノビス距離は、ユークリッド距離とは違い、分布からの外れ具合を定量化できていることが分かります。

マハラノビス距離は異常検知によく使われます。

STEP2. イメージで詳細を理解する

2.1 正規分布を仮定している

マハラノビス距離はデータが正規分布に従う場合にうまく働きます。 正規分布とはよく見るこれです。

fig2.png

山が高い $x=0$ 付近はデータがよく発生し、山が低い $x=4$ や $x=-4$ 付近はほとんどデータが発生しないことを表します。

山の頂点のある $x=0$ から離れれば離れるほど山が低くなり、データが発生しにくくなります。

一方で、2次元の正規分布は次のようになります。

fig3.png

この山を平面で表すと下のようになります。色が山の高さを示します。

fig4.png

1次元の時と同様に、山が高い $(x,y)=(0,0)$ 付近はデータがよく発生し、そこから離れれば離れるほど山が低くなり、データが発生しにくくなります。

マハラノビス距離は、こういう一つの山の形をした分布に対して適用することができます。

2.2 マハラノビス距離 = 山の形を統一して測ったユークリッド距離

さて、冒頭の図を見てみましょう。(実は、水色の楕円は山の等高線を示していました。)

fig1.png

「マハラノビス距離 = 山の形を統一して測ったユークリッド距離」です。まず、各方向で山の形がどうなっているかを見ていきます。

fig5.png

標準偏差とは、山の形を決める数値のうちの一つです。標準偏差が大きいほど、データのバラつきが大きくなり、山がなだらかになります。

データのばらつき 山の形 標準偏差
縦軸(青) 大きい なだらか 大きい(1.41)
横軸(赤) 小さい 急峻 小さい(0.58)

山の形を統一する、すなわち、縦横軸方向の標準偏差を1にするために、縦軸、横軸を標準偏差で割ってみます。

fig6.png

標準偏差で割ることで山の形が同じになりました(5つあるうちの一番右上の図に注目)。

マハラノビス距離は、山の形を標準形(標準偏差=1)に統一して測ったユークリッド距離と言えます。

山の形を統一すると、「平均からのユークリッド距離が大きいほど、データの外れ具合が大きくなる」という単純な関係が成立するようになります。なので、わざわざ、山の形を統一した後に、ユークリッド距離を測っているのです。

マハラノビス距離とユークリッド距離は下のようになりました(STEP1の表と同じ)。

特徴 平均との間のマハラノビス距離 平均との間のユークリッド距離
点1 分布から外れていない 2.12 3
点2 分布から大きく外れている 5.20 3

2.3 全ての方向で山の形を同じにするには

2.2節では、縦軸、横軸方向を、それぞれの標準偏差で割ることにより、平均と点1、点2の間のマハラノビス距離を測れるようになりました。

しかし、同じ操作では、平均と「点3」の間のマハラノビス距離を測ることができません。なぜなら緑の方向で見ると山の形が標準形(標準偏差=1)になっていないからです。

fig7.png

任意の点と平均の間のマハラノビス距離を測れるように、全ての方向で山の形を統一してみましょう。次の操作で統一することができます。

fig8.png

山の形を統一した後(4つあるうちの一番右上の図)でユークリッド距離を測ることでマハラノビス距離を求めることができます。

平均と点1、点2、点3の間のマハラノビス距離、ユークリッド距離は下の通りとなります(点1、点2の結果は2.2節の結果と同じ)。

特徴 平均との間のマハラノビス距離 平均との間のユークリッド距離
点1 分布から外れていない 2.12 3
点2 分布から大きく外れている 5.20 3
点3 分布から外れている 3.00 6.71

STEP3. 説明済みのイメージと数式を対応づける

マハラノビス距離の2乗 ${d_m}^2$ はこのように定義されます。ただし、$\boldsymbol{\mu}$、$\Sigma$はデータの平均と、分散共分散行列です。

{d_m}^2={(\boldsymbol{x}-\boldsymbol{\mu})^T\Sigma^{-1}}(\boldsymbol{x}-\boldsymbol{\mu})\\

冒頭の図のデータ(下図の小さい黒点)は、

\boldsymbol{\mu}=
\begin{pmatrix}
0\\
0
\end{pmatrix},

\Sigma = 
\begin{pmatrix}
1 & -2\\
-2 & 6
\end{pmatrix}

の正規分布から発生させました。

fig1.png

このとき、平均$\boldsymbol{\mu}=(0,0)^T$ と 任意の点$\boldsymbol{x}=(x,y)^T$の間のマハラノビス距離の2乗${d_m}^2$を見ていきます。



${d_m}^2$は次式で与えられます。

{d_m}^2 = 
\begin{pmatrix}
x & y
\end{pmatrix}
\begin{pmatrix}
1 & -2\\
-2 & 6
\end{pmatrix}^{-1}
\begin{pmatrix}
x \\
y
\end{pmatrix}

一方、$\boldsymbol{\mu}=(0,0)^T$ と $\boldsymbol{x}=(x,y)^T$の間のユークリッド距離の2乗${d_e}^2$は次式で与えられます。

{d_e}^2 = 
\begin{pmatrix}
x & y
\end{pmatrix}
\begin{pmatrix}
x \\
y
\end{pmatrix}
=x^2+y^2

${d_m}^2$ と ${d_e}^2$違いは、

\begin{pmatrix}
1 & -2\\
-2 & 6
\end{pmatrix}^{-1}

をかけているか否かです。この行列は何をしているのでしょうか?

実はこの行列が、2.3節で説明した「全ての方向で山の形を同じにする」操作に関連しているのです。

実際、${d_m}^2$は次の通り変形できます。

{d_m}^2 = 
\begin{pmatrix}
x & y
\end{pmatrix}
\begin{pmatrix}
1 & -2\\
-2 & 6
\end{pmatrix}^{-1}
\begin{pmatrix}
x \\
y
\end{pmatrix}
=
\begin{pmatrix}
z_x & z_y
\end{pmatrix}
\begin{pmatrix}
z_x \\
z_y
\end{pmatrix}={z_x}^2+{z_y}^2

ただし、

\begin{pmatrix}
z_x \\
z_y
\end{pmatrix}
=

\begin{pmatrix}
1/0.55 & 0\\
0 & 1/2.59
\end{pmatrix}
\begin{pmatrix}
\cos161^\circ & -\sin161^\circ\\
\sin161^\circ & \cos161^\circ
\end{pmatrix}
\begin{pmatrix}
x \\
y
\end{pmatrix}

です。(この変形は難しいので、変形が正しい証拠を付録に示して、説明を省略。$\Sigma$の固有値分解などにより得られます。)

つまり、$(x, y)$を161度回転させ、横軸方向に÷0.55して、縦軸方向に÷2.59をした後にユークリッド距離を測るとそれはマハラノビス距離になるということです。

これは、2.3節で説明した下の操作と一致します。

fig8.png

下の式は難解に見えますが、「全ての方向で山の形を同じにした後に、ユークリッド距離をとる」をやっているだけなのです。

{d_m}^2={(\boldsymbol{x}-\boldsymbol{\mu})^T\Sigma^{-1}}(\boldsymbol{x}-\boldsymbol{\mu})\\
  • 付録)変形が正しい証拠(Python)
import numpy as np

print(np.linalg.inv(np.array([[1, -2], [-2, 6]])))
# [[3.  1. ]
#  [1.  0.5]]


theta = np.deg2rad(161)
A  = np.dot(np.array([[1 / 0.55, 0], [0, 1 / 2.59]]),
            np.array([[np.cos(theta), - np.sin(theta)],
                      [np.sin(theta),   np.cos(theta)]])
           )
print(np.dot(A.T, A))
# [[2.97119067 0.97173287]
#  [0.97173287 0.48366797]]
43
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?