マハラノビス距離を使って分類

<a href="https://qiita.com/murasaki1994/items/d5c655ecb3206cfb1d45">前回</a>は数量化理論Ⅳ類について書きました。

https://qiita.com/murasaki1994/items/d5c655ecb3206cfb1d45

今回は類似度を測るうえで使う距離について品質で知ったことをまとめてみました。
一般的にはコサイン距離
```math
cos(θ) = \frac{x・y}{|x||y|}
```
とユークリッド距離
```math
euc(x, y) = \sqrt{\sum_{i=1}^{N}{(x_i - y_i)^2}}
```
の他にもマハラノビスというものがあります。
```math
mrv(i, j) = \sqrt{(x_i - x_j)^T S^{-1}(x_i - x_j)}
```
というのがあります。
距離を使った類似度は通常標準化して単位尺度を合わせる必要があるのですが、マハラノビス距離というのは尺度に依存しないという特徴があるそうです。
それを検証するために実際にコーディングして試してみます。
# ライブラリ
```Python3
import numpy as np
import pandas as pd
from scipy.spatial import distance # マハラノビス距離はこれでできる
from sklearn.model_selection import train_test_split as tts
from sklearn.metrics import classification_report
```

# データの読み込み
データはWineデータを使います
```Python3
df = pd.read_csv("wine.csv")
df.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/5eb5ce27-a7c2-0f63-b2d7-d0ac6eb7e826.png)

# 目的変数と説明変数で分ける
```Python3
y = df["Wine"].values
x_tab = df.drop("Wine", axis=1)
x = x_tab.values
```

# 適合用データと検証用データで分ける
誰がやっても結果が同じになるようにします。
```Python3
x_train, x_test, y_train, y_test = tts(x, y, random_state=0, test_size=0.3)
```

# 適合と分類
```Python3
euc = []
cos = []
mrv = []
cov = np.cov(x_train.T)
cov_i = np.linalg.inv(cov)
for i in range(len(x_test)):
    tmp_euc = []
    tmp_cos = []
    tmp_mrv = []
    for j in range(len(x_train)):
        tmp_euc.append([y_train[j], np.linalg.norm(x_test[i]-x_train[j])])
        tmp_cos.append([y_train[j], np.dot(x_test[i], x_train[j])/np.linalg.norm(x_test[i])*np.linalg.norm(x_train[j])])
        tmp_mrv.append([y_train[j], distance.mahalanobis(x_test[i], x_train[j], cov_i)])
    tmp_cos = sorted(tmp_cos, key=lambda x: x[1], reverse=True)
    tmp_euc = sorted(tmp_euc, key=lambda x: x[1])
    tmp_mrv = sorted(tmp_mrv, key=lambda x: x[1])
    cos.append(tmp_cos[0])
    euc.append(tmp_euc[0])
    mrv.append(tmp_mrv[0])
```
# コサイン距離の結果
```Python3
cos = np.array(cos)
print(classification_report(y_test, cos[:, 0]))
```
```
              precision    recall  f1-score   support

           1       0.35      1.00      0.52        19
           2       0.00      0.00      0.00        21
           3       0.00      0.00      0.00        14

    accuracy                           0.35        54
   macro avg       0.12      0.33      0.17        54
weighted avg       0.12      0.35      0.18        54
```
1のデータはすべて当たって他は分類できていないですね。
# ユークリッド距離
```Python3
euc = np.array(euc)
print(classification_report(y_test, euc[:, 0]))
```
```
              precision    recall  f1-score   support

           1       0.85      0.89      0.87        19
           2       0.76      0.90      0.83        21
           3       0.56      0.36      0.43        14

    accuracy                           0.76        54
   macro avg       0.72      0.72      0.71        54
weighted avg       0.74      0.76      0.74        54
```
コサイン距離よりは精度が上がりました。
# マハラノビス距離
```Python3
mrv = np.array(mrv)
print(classification_report(y_test, mrv[:, 0]))
```
```
              precision    recall  f1-score   support

           1       0.90      0.95      0.92        19
           2       0.95      0.90      0.93        21
           3       1.00      1.00      1.00        14

    accuracy                           0.94        54
   macro avg       0.95      0.95      0.95        54
weighted avg       0.95      0.94      0.94        54
```
94%にまで向上しました。
また、3のデータは正解率100%です。

ちなみに標準化するとこうなりました。
# コサイン類似度(標準化)
```
              precision    recall  f1-score   support

           1       1.00      0.79      0.88        19
           2       0.80      0.95      0.87        21
           3       0.93      0.93      0.93        14

    accuracy                           0.89        54
   macro avg       0.91      0.89      0.89        54
weighted avg       0.90      0.89      0.89        54
```
大幅に精度が上がりましたが、マハラノビス距離より精度は上がりませんでした。
# ユークリッド距離(標準化)
```
              precision    recall  f1-score   support

           1       0.90      1.00      0.95        19
           2       1.00      0.86      0.92        21
           3       0.93      1.00      0.97        14

    accuracy                           0.94        54
   macro avg       0.95      0.95      0.95        54
weighted avg       0.95      0.94      0.94        54
```
精度はマハラノビス距離と同じになりましたが先ほどのマハラノビス距離と分類結果が異なることが分かります。
# マハラノビス距離(標準化)
```
              precision    recall  f1-score   support

           1       0.90      0.95      0.92        19
           2       0.95      0.90      0.93        21
           3       1.00      1.00      1.00        14

    accuracy                           0.94        54
   macro avg       0.95      0.95      0.95        54
weighted avg       0.95      0.94      0.94        54
```
標準化してもしなくても分類の内訳が変わらなかったことが分かります。
確かに尺度に依存しないことが分かりました。