【AIプログラミング】いろいろな分類器でDigitを分類してみたい、まずはk近傍法

Digitデータをいろいろな分類器で試してみることにしました。

今までの復習とか、それぞれのアルゴリズムの違いがわかるかもね。

前回、初めての画像系の分類ということで、scikit-learnのデータセットであるDigitデータを確認しました。今回は、機械学習アルゴリズムで実際に分類してみようと思います。これまでにいくつか分類の機械学習アルゴリズムは勉強をしていますが、まず基本的なところで「k最近傍法」を思い出しつつ、使ってみたいと思います。

前回のdigitデータについての記事はこちらをご参考ください。

ぱんだクリップ
【AIプログラミング】digitデータを知る、手書き文字の分類 | ぱんだクリップ digitという手書き文字のデータがあって、それを分類してみたい。 初めての画像系だね! scikit-learnの中に、digitという手書き文字の分類があるそうです。今までは、数値...

k最近傍法の過去の記事についてはこちらをご参考ください。

ぱんだクリップ
【AIプログラミング】k最近傍法で分類、アヤメのデータを分類しよう | ぱんだクリップ 機械学習に至るまでのデータ作成が長かったな・・・やっとAIっぽいことができそう。 やっと訓練できるね。まずはscikit-learnで実際にどんなプログラムになるか見ていこう...

こんな人の役に立つかも

・機械学習プログラミングを勉強している人

・scikit-learnのdigitデータを分類したい人

・scikit-learnのdigitデータをk最近傍法で分類したい人

目次

k最近傍法で分類

今まで勉強をした流れで、

・訓練データとテストデータへ分割

・交差検証でパラメータをチューニング

・アルゴリズムを訓練してテストデータで評価

という流れを行いたいと思います。

また、評価の時は、アルゴリズムのscoreで算出するのではなく、ConfusionMatrixと、ClassificationReportで行います。

importから

importからdigitデータの読み込み、訓練データとテストデータに分割するところまでの流れです。

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
import numpy as np

#結果評価関連
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report

panda_box = datasets.load_digits()

X = panda_box.data
y = panda_box.target

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

次に、3分割交差検証を行います。まずは、k最近傍法のパラメータは、近傍の数「n_neighbors」を3としてみます。

from sklearn.neighbors import KNeighborsClassifier

#k-最近傍法
clf = KNeighborsClassifier(n_neighbors = 3)

#交差検証
score = cross_val_score(clf, X_train, y_train, cv=3)

#結果の表示
print("交差検証の結果")
print(score)
print("交差検証の平均")
print("{:.4f}".format(np.mean(score)))

#テストデータ評価
clf.fit(X_train, y_train)
predict = clf.predict(X_test)
print("==ClassificationReport==")
print(classification_report(y_test, predict,digits=4))

適当に当てはめたパラメータでも98.67%も出ています。

交差検証の結果
[0.98663697 0.9844098  0.97772829]
交差検証の平均
0.9829
==ClassificationReport==
              precision    recall  f1-score   support

           0     1.0000    1.0000    1.0000        45
           1     0.9787    1.0000    0.9892        46
           2     1.0000    1.0000    1.0000        44
           3     0.9375    0.9783    0.9574        46
           4     1.0000    0.9778    0.9888        45
           5     1.0000    1.0000    1.0000        46
           6     1.0000    1.0000    1.0000        45
           7     0.9783    1.0000    0.9890        45
           8     1.0000    0.9535    0.9762        43
           9     0.9773    0.9556    0.9663        45

    accuracy                         0.9867       450
   macro avg     0.9872    0.9865    0.9867       450
weighted avg     0.9870    0.9867    0.9867       450

念の為、パラメータ「n_neighbors」が1〜30までで、どのようにスコアが変化していくかを次にようにmatplotlibでプロットして確認してみます。

import matplotlib.pyplot as plt
import numpy as np

train_dat_array = []

loop = 30

for i in range(loop):
    clf = KNeighborsClassifier(n_neighbors=(i+1))
    score = cross_val_score(clf, X_train, y_train, cv=3)
    train_dat_array.append(np.mean(score))

#グラフ
X_axis = np.linspace(1,loop+1,loop)
plt.plot(X_axis, train_dat_array)

交差検証の結果、n_neighborsが5前後の時がスコアが高く、n_neighborsが増えるにつれてスコアが低下していきます。1の時は訓練データに過適合していそうなので、今回は5を選択します。

「5」とした場合でテストデータのスコアを出してみます。

clf = KNeighborsClassifier(n_neighbors = 5).fit(X_train, y_train)

#テストデータ評価
predict = clf.predict(X_test)
print("==ConfusionMatrix==")
print(confusion_matrix(y_test, predict))
print("==ClassificationReport==")
print(classification_report(y_test, predict,digits=4))
==ConfusionMatrix==
[[45  0  0  0  0  0  0  0  0  0]
 [ 0 46  0  0  0  0  0  0  0  0]
 [ 0  1 43  0  0  0  0  0  0  0]
 [ 0  0  0 44  0  0  0  1  1  0]
 [ 0  0  0  0 44  0  0  0  1  0]
 [ 0  0  0  0  0 46  0  0  0  0]
 [ 0  0  0  0  0  0 45  0  0  0]
 [ 0  0  0  0  0  0  0 45  0  0]
 [ 0  1  0  1  0  0  0  0 41  0]
 [ 0  0  0  2  0  1  0  0  0 42]]
==ClassificationReport==
              precision    recall  f1-score   support

           0     1.0000    1.0000    1.0000        45
           1     0.9583    1.0000    0.9787        46
           2     1.0000    0.9773    0.9885        44
           3     0.9362    0.9565    0.9462        46
           4     1.0000    0.9778    0.9888        45
           5     0.9787    1.0000    0.9892        46
           6     1.0000    1.0000    1.0000        45
           7     0.9783    1.0000    0.9890        45
           8     0.9535    0.9535    0.9535        43
           9     1.0000    0.9333    0.9655        45

    accuracy                         0.9800       450
   macro avg     0.9805    0.9798    0.9799       450
weighted avg     0.9804    0.9800    0.9800       450

98%と、若干、テストデータに対してはスコアが低下してしまいましたが、今回のテストデータの場合だと若干低下しているように見えるだけなのかもしれません。

ClassificationReportのaccuracy、0.9800という数値が今までscoreで出していたものと同じ数値となります。

試しに、アルゴリズムのscoreでもみてみますね。

print(clf.score(X_test, y_test))
0.98

同じ正解率を出しています。

正解率結構高い・・・

今回学んだこと

最初、私はテストデータへのスコアを見てパラメータを変化させていました。

しかし、実際テストデータへ合わせても、他のデータにすり替わったらその調整は意味のないものになってしまいます。

パラメータチューニングのために交差検証があるので、今回のように3から5へ交差検証の結果をみてパラメータチューニングをしたにも関わらず、テストデータでスコアが低下してしまったとしても、それは偶然今回のテストデータでスコアが低下してしまった可能性が高いです。

テストデータへのスコアをみてパラメータを変更させては意味がない、勉強しました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次