Python

Pythonで機械学習を学ぶ k近傍法(k-NN)

入力されたデータの属性に近いデータをk個選び、そのk個のデータがどの分類に多いかを調べて、多いものを入力データの分類とする分類方法。

サンプルコードでは、以下のモデルを構築します。
目的変数:赤ワイン、白ワインか分類
説明変数:説明変数:固定酸度、揮発性の酸度、クエン酸、残糖、塩化物など11の入力

以下のワインのデータセットで実験します。

ポルトガルワイン「Vinho Verde」の赤と白の変数に関するもの。プライバシーとロジスティックの問題のため、物理化学的変数(入力)と感覚的変数(出力)のみが利用可能。

より詳しい情報は、[Cortez et al., 2009]を参照。
入力変数(物理化学的試験に基づく)は以下の通り。
1 – 固定酸度
2 – 揮発性の酸度
3 – クエン酸
4 – 残糖
5 – 塩化物
6 – 遊離二酸化硫黄
7 – 全二酸化硫黄
8 – 密度
9 – pH
10 – 硫酸塩
11 – アルコール


出力変数(感覚データに基づく)は以下の通り。
12 – 品質(0から10の間のスコア)

https://archive.ics.uci.edu/ml/datasets/Wine+Quality

データの読み込みと確認と整理

import pandas as pd
import requests
import io
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# 読み込み
url_red = 'https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv'
res_red = requests.get(url_red).content
data_red = pd.read_csv(io.StringIO(res_red.decode('utf-8')),
                       header=None, skiprows=1, delimiter=";")
# 赤を0, 白を1とする
data_red['type'] = [0] * data_red.shape[0]
data_red.columns = ['fixedacidity', 'volatileacidity', 'citricacid', 'residualsugar', 'chlorides',
                    'freesulfurdioxide', 'totalsulfurdioxide', 'density', 'pH', 'sulphates', 'alcohol', 'quality', 'type']

url_white = 'https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv'
res_white = requests.get(url_white).content
data_white = pd.read_csv(io.StringIO(res_white.decode(
    'utf-8')), header=None, skiprows=1, delimiter=";")
# 赤を0, 白を1とする
data_white['type'] = [1] * data_white.shape[0]
data_white.columns = ['fixedacidity', 'volatileacidity', 'citricacid', 'residualsugar', 'chlorides',
                      'freesulfurdioxide', 'totalsulfurdioxide', 'density', 'pH', 'sulphates', 'alcohol', 'quality', 'type']

# 確認
print('データ形式:{}'.format(data_red.shape))
print(data_red.head())
print('データ形式:{}'.format(data_white.shape))
print(data_white.head())
# print(data.dtypes)

# 結合
data = pd.concat([data_red, data_white])
print('データ形式:{}'.format(data.shape))
print(data.head())

モデルの構築と評価

# 目的変数、説明変数
X = data[['fixedacidity', 'volatileacidity', 'citricacid', 'residualsugar', 'chlorides',
          'freesulfurdioxide', 'totalsulfurdioxide', 'density', 'pH', 'sulphates', 'alcohol']]
y = data['type']

# 訓練データとテストデータに分ける
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.5, random_state=0)

# グラフ描画用
training_accuracy = []
test_accuracy = []
k_range_max = 50

# 学習
for n_neighbors in range(1, k_range_max):
    model = KNeighborsClassifier(n_neighbors=n_neighbors)
    model.fit(X_train, y_train)
    training_accuracy.append(model.score(X_train, y_train))
    test_accuracy.append(model.score(X_test, y_test))

# グラフ描画
plt.plot(range(1, k_range_max), training_accuracy, label='Training')
plt.plot(range(1, k_range_max), test_accuracy, label='Test')
plt.ylabel('Accuracy')
plt.xlabel('n_neighbors')
plt.show()

結果

学習とテスト時の乖離があります。n_neighborsは、7-10くらいが良さそうです。