【AIプログラミング】過学習と汎化性能の勉強、k最近傍法のパラメータ調整

ハンカセーノー・・・

知らないデータでどこまで正解をだせるか・・・

k最近傍法で、アヤメのデータを分類してみることで機械学習プログラミングの流れや仕組みがある程度勉強できました。機械学習プログラミングでは、データの準備とその整理がかなり大事ですね。今回は、前回まで作成したプログラムの内容を、過学習と汎化性能という観点からみてみたいと思います。

今回の記事は、以前アヤメのデータ分類を行ったプログラムをもとに書いています。アヤメのデータ分類の記事はこちらからどうぞ。

ぱんだクリップ
scikit-learnのアヤメのデータ、機械学習のプログラミングで重要なデータの観測 | ぱんだクリップ 機械学習プログラミングの勉強をはじめて、まずはアヤメのデータの分類をしようとしてます。アヤメのデータはscikit-learnにすでに含まれているんだね。 アヤメのデータは...
目次

汎化性能は、未知データへの正解率

教師あり学習の分類では

未知のデータを入力したときに正解を出すことができる確率が高いこと

がとても重要になってきます。

今、自分で摘み取ってきたアヤメをこのプログラムに花びらを入力したときに、しっかり分類してくれるか、ということが重要です。

全く今までにないデータを入れても正確に分類できるか、という性能が汎化性能です。

てことは、汎化性能って計測できないの??

計測できるように、データを訓練データとテストデータに分割するんだよ

テストデータとして、訓練させないデータを持っておくことで、プログラムから見ると未知のデータになっているという点が重要でした。

プログラムでは、実際に正解ができる性能をテストデータの正解率とすることで、未知のデータに対してどれだけ正解できるか、を算出しました。

knc.score(X_test, y_test)

ただ、train_test_splitというデータ分割する機能は、毎回データをシャッフルしてくれるので、実行するたびに違うシャッフル結果となります。

運よく100%正解する訓練データとテストデータとなってしまう場合もありました。

そこで、私の作成したプログラムでは、train_test_splitを10回行い、その正解率を10回出した上で、平均の正解率とすることで、正解率を平均化して出していました。

#10回の評価
result = np.zeros(10)

for i in range(10):
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.5, stratify=y)
  knc.fit(X_train, y_train)
  result[i] = knc.score(X_test, y_test)

この10回繰り返して平均を出すという点は、100回などにすることで今回の150個のデータの平均には近づいてくると思います。

訓練データへの過学習(オーバーフィッティング)

過学習、過適合と呼ばれる現象は、訓練データ特有の傾向に合わせた判定条件になってしまうことで未知のデータへの正解率が下がるという現象です。

訓練データとして準備するデータは具体的なデータなので、そのデータの集まりになることで特有の特徴や傾向まで判断の条件としてしまうといけないよってことです。

k再近傍法でのkパラメータの調整

k再近傍法では、kのパラメータが小さいほど、訓練データに適合することになりますので、k=1が一番過学習になっていると考えられます。

k最近傍法は、訓練データをfitした時、データを保存して、predictした時は訓練データを参照するだけなので、過「学習」というよりも過「適合」と行った方がしっくりくるかもしれませんね。

↓プログラム全体です。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
#k-最近傍法のimport
from sklearn.neighbors import KNeighborsClassifier

import numpy as np
import pandas as pd

panda_box = load_iris()

X = panda_box.data
y = panda_box.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.5, stratify=y)

#k-最近傍法のオブジェクトの宣言
knc = KNeighborsClassifier(n_neighbors = 1)

#10回の評価
result = np.zeros(50)

for i in range(50):
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.5, stratify=y)
  knc.fit(X_train, y_train)
  result[i] = knc.score(X_test, y_test)

#numpyの表示を小数点2桁までに変更
np.set_printoptions(precision=2)
print("50回の結果を表示")
print(result)

print("50回の平均的な正解確率")
print("{:.4f}".format(result.sum()/50))

さりげなく、データの分割を50回に変更したのと、平均的な正解率も小数点4桁まで出すように変更しました。

この結果、

50回の平均的な正解確率
0.9544

この50回のループを何回かやってみましたが、96%を超えることはあまりなく、基本的に95%程度の正解率を保っていました。

次に、k=9としてみました。

#k-最近傍法のオブジェクトの宣言
knc = KNeighborsClassifier(n_neighbors = 9)

この結果、

50回の平均的な正解確率
0.9645

なんだか、少しだけ正解率の幅が上昇した感じがします。何回か実行した結果、悪くても95%台になることはなかったです。

k=9としたことで、過学習によって正解率が下がっていた部分が解消された気がします。

次に、k=32でやってみます。

50回の平均的な正解確率
0.9072

かなり未知のデータに対する正解率が低下しました。

これは、kの数が多いほど分類する境界線が単純になっていくので、正解率が下がっています。

究極にいくと、75個の訓練データなので、75にしてみます。

50回の平均的な正解確率
0.3333

これはもう何回やっても、75個のデータの多数決にしかならないので、意味ないですね^^;

ということで、k再近傍法においては、kの数値を大きくしてあげることで、複雑すぎない判定条件とすることができ、さらにkの数値が大きすぎないことで単純化されすぎないいい感じの点を探すことが重要であることがわかりました。

これが汎化性能をあげるということか・・・

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