LoginSignup
17
14

More than 1 year has passed since last update.

【異常検知】マハラノビス距離を嚙み砕いて理解する (2)

Last updated at Posted at 2022-01-05

1.はじめに

前回の記事【異常検知】マハラノビス距離を嚙み砕いて理解する (1)の続きです。
今回は、実際のデータセットを利用して、マハラノビス距離を計算してみます。

2.データセット(Davis)

有名なDavisデータセットを使います。元を辿ると1990年の論文のデータです。
C.Davis, "Body image and weight preoccupation: A comparison between exercising and non-exercising women" (1990) Link

データCSVのダウンロードはこちらです。
Davis Dataset

データの集計(平均、分散)

 データを覗くと、Featureは['sex', 'weight', 'height', 'repwt', 'repht']の五つで、データの長さは200です。従ってshapeは(5,200)

 この中で'weight', 'height'を選び、マハラノビス距離を計算します。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.spatial import distance

#Davis Dataset
df = pd.read_csv('Davis.csv')
print(df.head())
print(df.columns)
df = df[['weight', 'height']]

data = df.to_numpy()


print('data',data.shape)
print('data.T',data.T.shape)
print(data.T[0])

#Plot
fig1 = plt.figure(figsize=(8,5))
ax1 = fig1.add_subplot()
ax1.scatter(data.T[0], data.T[1])
ax1.set_title('Davis Data')
ax1.set_xlabel('weight')
ax1.set_ylabel('height')
ax1.set_aspect('equal')
ax1.grid()
plt.show()

怪しい奴が二つ見えてますね。
(w,h) = (120,180)
(w,h) = (165,50)

Figure_1.png

3.マハラノビス距離の計算

それでは、このデータ('weight', 'height'の2組(=次元)のデータ群)のマハラノビス距離を計算してみましょう。
マハラノビス距離の式はこちらです。

image.png
image.png

必要なパラメータを計算しましょう。

#統計情報の集計

#mean
mu_mat = np.mean(data, axis=0)
print(mu_mat)

#data - mean
data_m_mat = data - mu_mat

#covariance matrix
cov_mat = np.cov(data.T)
cov_i_mat = np.linalg.pinv(cov_mat)
print(cov_mat)
print(cov_i_mat)

結果
print(mu_mat)
[ 65.8  170.02]

print(cov_mat)
[[227.85929648  34.3758794 ]
 [ 34.3758794  144.19055276]]

print(cov_i_mat)
[[ 0.00455241 -0.00108532]
 [-0.00108532  0.00719401]]

3.1.scipyの関数利用

scipy.spacialのdistanceにマハラノビスを計算する関数があるので、それを利用します。


mahala_result = []
for i in range(len(data_m_mat)):
    mahala_result.append(distance.mahalanobis(data[i],mu_mat, cov_i_mat ))
    print(data[i])

プロットしてみます。

fig2 = plt.figure(figsize=(8,5))
ax1 = fig2.add_subplot()
ax1.plot(mahala_result)
ax1.set_title('Mahalanobis Distance')
ax1.set_xlabel('sample')
ax1.set_ylabel('Mahalanobis Distance')
# ax1.set_aspect('equal')
ax1.grid()

Figure_2.png

3.2.numpyの利用

同様にnumpyを利用し、直接にマハラノビス距離を計算することも可能です。こちらのほうが早い気がします。

mahala_result = np.sqrt(np.sum(np.dot(data_m_mat,cov_i_mat)*data_m_mat,axis = 1))

4.等高線図の作成

それでは、見やすくするため、マハラノビス距離の等高線を書いてみます。
やり方は、x座標、y座標、そして、(x,y)座標に対応するマハラノビス距離を格納する3次元のデータを作成します。(x座標、y座標、マハラノビス距離)の3組(次元)データ。 それをmatplotのcontourを利用して描画します。
その後、scatterを利用し、一緒に描画するだけです。


#Contour

# weight [30,200]
# height [50,210]


z = np.array(
    [
        [(i,j, distance.mahalanobis([i,j], mu_mat, cov_i_mat))
         for i in np.linspace(30,200,100)]
        for j in np.linspace(50,210,100)
    ]

)

print('z shape',z.shape)
print(z[:,:,0])

fig3 = plt.figure()
ax1 = fig3.add_subplot()
ax1.set_title('Davis Data, Mahalanobis Distance')
CS = ax1.contour(z[:,:,0], z[:,:,1],z[:,:,2])
ax1.clabel(CS)
ax1.set_xlabel('weight')
ax1.set_ylabel('height')
ax1.set_aspect('equal')

ax1.grid()

ax1.scatter(data.T[0], data.T[1])

plt.show()

Figure_3.png

5.結論

マハラノビス距離、知れば知るほどすごいですね。多次元データの異常検知では、やはりこれを使わない手はないと思います。

5. 参考資料

  1. 井出剛さんのTwitter
  2. 入門 機械学習による異常検知―Rによる実践ガイド
  3. On the generalized distance in statistics
  4. マハラノビス距離の意味を2次元の場合で理解する
  5. 異常検知 マハラノビス距離を実装してみる
  6. Maharanobis Distance at Scipy
  7. 【python できること】異常検知 マハラノビス距離を実装してみる
17
14
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
17
14