前回は数量化理論Ⅳ類について書きました。
今回は類似度を測るうえで使う距離について品質で知ったことをまとめてみました。
一般的にはコサイン距離
cos(θ) = \frac{x・y}{|x||y|}
とユークリッド距離
euc(x, y) = \sqrt{\sum_{i=1}^{N}{(x_i - y_i)^2}}
の他にもマハラノビスというものがあります。
mrv(i, j) = \sqrt{(x_i - x_j)^T S^{-1}(x_i - x_j)}
というのがあります。
距離を使った類似度は通常標準化して単位尺度を合わせる必要があるのですが、マハラノビス距離というのは尺度に依存しないという特徴があるそうです。
それを検証するために実際にコーディングして試してみます。
ライブラリ
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データを使います
df = pd.read_csv("wine.csv")
df.head()
目的変数と説明変数で分ける
y = df["Wine"].values
x_tab = df.drop("Wine", axis=1)
x = x_tab.values
適合用データと検証用データで分ける
誰がやっても結果が同じになるようにします。
x_train, x_test, y_train, y_test = tts(x, y, random_state=0, test_size=0.3)
適合と分類
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])
コサイン距離の結果
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のデータはすべて当たって他は分類できていないですね。
ユークリッド距離
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
コサイン距離よりは精度が上がりました。
マハラノビス距離
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
標準化してもしなくても分類の内訳が変わらなかったことが分かります。
確かに尺度に依存しないことが分かりました。