Kohei Blog

夫・父親・医療系エンジニア

【K近傍法】scikit-learnでアヤメの多クラス分類(iris-dataset)

3種類のアヤメについて、それぞれ50サンプルのデータがあります。 それぞれ、Iris setosa、Iris virginica、Iris versicolorという名前で、全部で150のデータ。

4つの特徴量が計測されていて、これが説明変数。

  • 萼片(sepal)の長さ(cm)
  • 萼片(sepal)の幅(cm)
  • 花びら(petal)の長さ(cm)
  • 花びら(petal)の幅(cm)

アヤメの分類は3つのクラス

  • Iris-setosa (n=50)
  • Iris-versicolor (n=50)
  • Iris-virginica (n=50)

特徴量から、それぞれの分類を予測していきます。

データ準備

import numpy as np
import pandas as pd
from pandas import Series,DataFrame

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')

%matplotlib inline
from sklearn import linear_model
from sklearn.datasets import load_iris

# データの読み込み
iris = load_iris()

# 説明変数をXに
X = iris.data

#目的変数をYに
Y = iris.target
iris_data = DataFrame(X,columns=['Sepal Length','Sepal Width','Petal Length','Petal Width'])

iris_target = DataFrame(Y,columns=['Species'])
def flower(num):
   ''' 数字を受け取って、対応する名前を返す'''
   if num == 0:
       return 'Setosa'
   elif num == 1:
       return 'Veriscolour'
   else:
       return 'Virginica'

iris_target['Species'] = iris_target['Species'].apply(flower)
# 1つのテーブルにまとめる
iris = pd.concat([iris_data,iris_target],axis=1)

iris.head()

特徴量を可視化

#pairPlot で可視化
sns.pairplot(iris,hue='Species',size=2)

f:id:kei_01011:20210521123443p:plain

plt.figure(figsize=(12,4))
sns.countplot('Petal Length',data=iris,hue='Species')

f:id:kei_01011:20210521123520p:plain

plt.figure(figsize=(12,4))
sns.countplot('Petal Width',data=iris,hue='Species')

f:id:kei_01011:20210521123542p:plain

ロジスティック回帰で予測 

ここではロジスティック回帰による分類を簡単に実装してみる。

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

logreg = LogisticRegression()

# テストが全体の40%
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.4,random_state=3)

# データを使って学習
logreg.fit(X_train, Y_train)
LogisticRegression()
# 精度計算
from sklearn import metrics

# テストデータを予測
Y_pred = logreg.predict(X_test)

# 精度を計算
print(metrics.accuracy_score(Y_test,Y_pred))
0.9666666666666667

0.9666666666666667 とかなり精度が高い。

次に、K近傍法で予測してみる

K近傍法で予測

K近傍法は英語で、k-nearest neighbor

学習のプロセスは、単純に学習データを保持するだけ。

与えられたサンプルのk個の隣接する学習データのクラスを使い、このサンプルのクラスを予測します。

f:id:kei_01011:20210521123627p:plain

★が新しいサンプル

これを中心に、 K=3ではAが1つ、Bが2つなので、分類されるクラスは、Bです。 K=6ではAが4つ、Bが2つなので、Aと判別される。

Kの選び方によっては、同数になってしまうことがあるので注意が必要な手法

# K近傍法
from sklearn.neighbors import KNeighborsClassifier

# k=3
knn = KNeighborsClassifier(n_neighbors = 3)

# 学習
knn.fit(X_train,Y_train)

# テストデータを予測
Y_pred = knn.predict(X_test)

# 精度 check
print(metrics.accuracy_score(Y_test,Y_pred))

→ 0.95

# k=1にしてみる
knn = KNeighborsClassifier(n_neighbors = 1)

knn.fit(X_train,Y_train)
Y_pred = knn.predict(X_test)
print(metrics.accuracy_score(Y_test,Y_pred))
0.9666666666666667

もっとも近いサンプルに合わせて分類すると精度が上がった

kの数値による予測精度の推移を見てみる

# 1~90まで繰り返す
k_range = range(1, 90)

accuracy = []

for k in k_range:
   knn = KNeighborsClassifier(n_neighbors=k)
   knn.fit(X_train, Y_train)
   Y_pred = knn.predict(X_test)
   accuracy.append(metrics.accuracy_score(Y_test, Y_pred))

# plot
plt.plot(k_range, accuracy)
plt.xlabel('K for kNN')
plt.ylabel('Testing Accuracy')

f:id:kei_01011:20210521123729p:plain

kは増やしすぎても精度が下がる

こんな感じで、もっとも精度の高いところを選択するのが良さそう