K最近傍法(K-Nearest Neighbor) 分類 基礎

#K近傍法 (K-Nearest Neighbor)  概要
k近傍法（以下k-NN)はもっとも単純な分類アルゴリズムであり、予測したいデータと距離の近い、k個の訓練データの正解ラベルから予測値を決定するアルゴリズムである。

**<メリット>**
- モデルの過度な調整無しにある程度の精度が出る
- アルゴリズムの理解が容易

**<デメリット>**
- データの前処理必須
- 特徴量（数百以上)の多いデータセットでは上手く機能しない
- 疎なデータセットでは精度が出ない
- 処理速度が遅い

上記デメリットから実務上あまり使われることはない。

K-NNの以下の2つのうち分類(Classification)について本記事ではまとめる。

1. **Nearest Neighbor Classification (分類)**
2. Nearest Neighbor Regression (回帰)


#分類: Nearest Neighbor Classification

予測のためのHyper Parameter は以下。
参考=> [sklearn](https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html)


|Parameters|詳細|
|:---|:---|
|n_neighbors|アルゴリズム判断に用いる近傍点の数 (default=5)|
|weights|予測判断に用いる重みの設定 (default="uniform")<br><br>"uniform":均一な重み<br>"distance":距離に応じた重み|
|algorithm|予測のためのアルゴリズム (default="auto")<br> <br>"ball_tree":BallTreeアルゴリズム<br>"kd_tree"：KD Treeアルゴリズム<br>"brute":総当たり探索<br>"auto": 最適なアルゴリズムを自動で選択|
|leaf_size|KD Tree, Ball Treeアルゴリズムを用いるときのリーフサイズ|
|metric|距離の測定方法 (default="minkowski)|
|p| Minkowski metricにおけるPower Parameter|
|n_jobs|利用するCPU数の設定 (default=1)|


#Cancer Datasetでの予測分類
実際にsklearnのcancer datasetにて分類予測を行う。

まず必要なライブラリを読み込む。
classfication_reportは予測値の評価に用いる。

```python
#必要なライブラリの読み込み
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

#sklean cancer dataの読み込み
from sklearn.datasets import load_breast_cancer
```

Cancer DataSetの詳細を確認する。
sklearn cancer datasetには説明変数(特徴量)が30、569のデータポイントがある。
目的変数(ラベル)のうち"0"が悪性の腫瘍(malignant)、"1"が良性の腫瘍(benign)を示す。

```python
dataset = load_breast_cancer()

# 特徴量 (説明変数)
X = pd.DataFrame(dataset.data,
                 columns=dataset.feature_names)
#ラベル（目的変数)
y = pd.Series(dataset.target, name='y')

# データ詳細確認
print('X shape: (%i,%i)' %X.shape)
print(y.value_counts())
display(X.join(y).head())
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560775/332d3440-cf31-3752-0126-6bbdbf072ddc.png)

実際に訓練データ/テストデータに分割の上、予測精度の確認を行う。
ハイパーパラメーターのうち近傍オブジェクト数を変数(1~10)とし、予測精度の変化をプロットする。

```python

from sklearn.neighbors import KNeighborsClassifier

#データセットをtest sampleを割合20%でホールドアウトする。
X_train, X_test, y_train, y_test = train_test_split(X,y, random_state=0, test_size=0.2)

#近傍オブジェクト数とその予測スコアを格納するリストを準備
List_n_neighbors = []
List_train_score = []
List_test_score = []

#近傍オブジェクト数を1-10で予測値を比較。訓練データに対してfitする。
for n_neighbors in range(1,11):
    clf = KNeighborsClassifier(n_neighbors = n_neighbors).fit(X_train,y_train)

#訓練スコアと予測スコアを算出してリストに格納
    List_n_neighbors.append(n_neighbors)
    List_train_score.append(clf.score(X_train,y_train))
    List_test_score.append(clf.score(X_test,y_test))

#近傍オブジェクト数に対して訓練スコア、テストスコアをプロットする
fig = plt.figure(figsize = (10,6))
plt.plot(List_n_neighbors, List_train_score, label = "training accuracy")
plt.plot(List_n_neighbors, List_test_score, label = "test accuracy")
plt.ylabel("Accuracy")
plt.xlabel("n_neighbors")
plt.xticks(np.linspace(1,11,11))
plt.legend()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560775/95976037-8c63-e037-ba90-5d13ba264c17.png)

#まとめ
Cancer Datasetを用いた予測においては近傍オブジェクト数(k)が**k=6**あたりが最良の性能であることがうかがえる。ただしK=2の場合でも88%程度の精度が担保されており、特徴量30程度のCancer Datasetに関してはNearest Neighbor Classificationによる分類は十分に機能しているといえる。

以下classification_reportによる結果を確認しても再現率(recall)、適合率(precision)ともに大きな偏りなく精度を保っていることが確認できる。

ただし実際に実務上、ガンの診断に使えるかというと以下classification_reportによる結果を確認するとmalignant再現率(recall)の精度から悪性47件のうち3件程度は悪性腫瘍(malignant)を良性(benign)と判断してしまう点から十分な精度ではないと思われる。

```python

clf = KNeighborsClassifier(n_neighbors = 6).fit(X_train,y_train)
predict_result = clf.predict(X_test)
print(classification_report(y_test,predict_result, target_names=["malignant","benign" ]))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560775/dbaeadb4-0ff8-c810-cea6-7070b17591e6.png)