機械学習ライブラリScikit-learn
前回は機械学習ライブラリScikit-learnのiris(アヤメ)のデータセットをmlxtendを使って分類の境界を可視化してみました。
今回は機械学習に用いるデータの量を変えた場合、正解率にどのように影響が出るのかを試してみましょう。
ということで準備から行っていきます。
データの読み込み、機械学習用のデータの分割、サポートベクターマシンを使った機械学習、結果の評価は前に解説していますので、まずはそのまま記載しておきます。
from sklearn.datasets import load_iris
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df["target"] = iris.target
x = df.loc[:, ["sepal length (cm)", "sepal width (cm)", "petal length (cm)", "petal width (cm)"]]
y = df.loc[:, "target"]
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, train_size=0.8)
model = SVC(gamma="auto")
model.fit(x_train, y_train)
pred_y = model.predict(x_test)
print(accuracy_score(y_test, pred_y))
ここから少し組み替えていきましょう。
2つのモデルを構築する
まずは全てのデータを使って機械学習させたモデルと、2種類(petal lengthとpetal width)のデータを使って機械学習させてたモデルを準備していきます。
ということでまずは特徴量をまとめたデータを2種類準備します。
x_all = df.loc[:, ["sepal length (cm)", "sepal width (cm)", "petal length (cm)", "petal width (cm)"]]
x_two = df.loc[:, ["petal length (cm)", "petal width (cm)"]]
y = df.loc[:, "target"]
「x_all」が4つ全ての特徴量を格納したデータ、「x_two」がpetal lengthとpetal widthのみをまとめたデータです。
「y」は分類結果なので一つで大丈夫です。
次にtrain_test_splitで学習用データとテストデータに分類していきますが、この際に「x_all」と「x_two」の二つのデータそれぞれに分割したデータセットを作成します。
x_all_train, x_all_test, y_all_train, y_all_test = train_test_split(x_all, y, test_size=0.2, train_size=0.8)
x_two_train, x_two_test, y_two_train, y_two_test = train_test_split(x_two, y, test_size=0.2, train_size=0.8)
ここまでいけばあとはそれぞれに対してモデルを作り、学習させ、予想をさせ、評価するという流れを「x_all」と「x_two」に対してそれぞれ作るだけです。
model_all = SVC(gamma="auto")
model_two = SVC(gamma="auto")
model_all.fit(x_all_train, y_all_train)
model_two.fit(x_two_train, y_two_train)
pred_y_all = model_all.predict(x_all_test)
pred_y_two = model_two.predict(x_two_test)
print(accuracy_score(y_all_test, pred_y_all), accuracy_score(y_two_test, pred_y_two))
ということでこんな感じ。
from sklearn.datasets import load_iris
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df["target"] = iris.target
x_all = df.loc[:, ["sepal length (cm)", "sepal width (cm)", "petal length (cm)", "petal width (cm)"]]
x_two = df.loc[:, ["petal length (cm)", "petal width (cm)"]]
y = df.loc[:, "target"]
x_all_train, x_all_test, y_all_train, y_all_test = train_test_split(x_all, y, test_size=0.2, train_size=0.8)
x_two_train, x_two_test, y_two_train, y_two_test = train_test_split(x_two, y, test_size=0.2, train_size=0.8)
model_all = SVC(gamma="auto")
model_two = SVC(gamma="auto")
model_all.fit(x_all_train, y_all_train)
model_two.fit(x_two_train, y_two_train)
pred_y_all = model_all.predict(x_all_test)
pred_y_two = model_two.predict(x_two_test)
print(accuracy_score(y_all_test, pred_y_all), accuracy_score(y_two_test, pred_y_two))
実行結果
0.9666666666666667 0.9333333333333333
一回実行してみると、「x_all」では「0.9666…」となり、「x_two」では「0.9333…」となりました。
「x_all」の方が精度良く予想できているようですが、まだ1回学習・評価しただけの結果。
ということで次に何十回と学習・評価した場合、どれくらいの差が出るのかを試していきたいと思います。
繰り返し学習・評価を行うように変更
ということで何度も繰り返し学習・評価を行うように変更してみましょう。
numpyを使うので、numpyをインポートします。
ということでインポートするのはこんな感じ。
from sklearn.datasets import load_iris
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
import numpy as np
この次に試行数を気軽に変更できるよう試行数の変数を追加します。
trial = 100
とりあえず試行数は100回としておきます。
次に機械学習・評価を繰り返すようにプログラムを編集していきましょう。
変える部分は、学習用データとテスト用データを分割するこのコマンド以降のところ。
x_all_train, x_all_test, y_all_train, y_all_test = train_test_split(x_all, y, test_size=0.2, train_size=0.8)
x_two_train, x_two_test, y_two_train, y_two_test = train_test_split(x_two, y, test_size=0.2, train_size=0.8)
model_all = SVC(gamma="auto")
model_two = SVC(gamma="auto")
model_all.fit(x_all_train, y_all_train)
model_two.fit(x_two_train, y_two_train)
pred_y_all = model_all.predict(x_all_test)
pred_y_two = model_two.predict(x_two_test)
ここをfor文で繰り返し動作するように変更します。
for i in range(trial):
x_all_train, x_all_test, y_all_train, y_all_test = train_test_split(x_all, y, test_size=0.2, train_size=0.8)
x_two_train, x_two_test, y_two_train, y_two_test = train_test_split(x_two, y, test_size=0.2, train_size=0.8)
model_all = SVC(gamma="auto")
model_two = SVC(gamma="auto")
model_all.fit(x_all_train, y_all_train)
model_two.fit(x_two_train, y_two_train)
pred_y_all = model_all.predict(x_all_test)
pred_y_two = model_two.predict(x_two_test)
また先ほどは最後にprint関数で結果を表示していたのですが、今回は何百回と繰り返すと表示させても確認するのが一苦労です。
ということでまずは評価結果をリストに入れ、平均値を計算し、表示するというプログラムに変えることにします。
そのためこちらの行は削除します。
print(accuracy_score(y_all_test, pred_y_all), accuracy_score(y_two_test, pred_y_two))
そして新たに評価結果を入れる空のリストの作成、そして評価結果を入れるプログラムを追加します。
all_pred = []; two_pred=[]
for i in range(trial):
x_all_train, x_all_test, y_all_train, y_all_test = train_test_split(x_all, y, test_size=0.2, train_size=0.8)
x_two_train, x_two_test, y_two_train, y_two_test = train_test_split(x_two, y, test_size=0.2, train_size=0.8)
model_all = SVC(gamma="auto")
model_two = SVC(gamma="auto")
model_all.fit(x_all_train, y_all_train)
model_two.fit(x_two_train, y_two_train)
pred_y_all = model_all.predict(x_all_test)
pred_y_two = model_two.predict(x_two_test)
all_pred.append(accuracy_score(y_all_test, pred_y_all))
two_pred.append(accuracy_score(y_two_test, pred_y_two))
最初の「all_pred = []; two_pred = []」で空のリストを作成しています。
またこちらの2行のプログラムで評価結果をそれぞれのリストに格納しています。
all_pred.append(accuracy_score(y_all_test, pred_y_all))
two_pred.append(accuracy_score(y_two_test, pred_y_two))
そして最後に平均値を計算し、表示するプログラムを追加しましょう。
all_ave = np.average(np.array(all_pred))
two_ave = np.average(np.array(two_pred))
print(all_ave, two_ave)
ということで全体はこんな感じになります。
from sklearn.datasets import load_iris
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
import numpy as np
trial = 100
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df["target"] = iris.target
x_all = df.loc[:, ["sepal length (cm)", "sepal width (cm)", "petal length (cm)", "petal width (cm)"]]
x_two = df.loc[:, ["petal length (cm)", "petal width (cm)"]]
y = df.loc[:, "target"]
all_pred = []; two_pred=[]
for i in range(trial):
x_all_train, x_all_test, y_all_train, y_all_test = train_test_split(x_all, y, test_size=0.2, train_size=0.8)
x_two_train, x_two_test, y_two_train, y_two_test = train_test_split(x_two, y, test_size=0.2, train_size=0.8)
model_all = SVC(gamma="auto")
model_two = SVC(gamma="auto")
model_all.fit(x_all_train, y_all_train)
model_two.fit(x_two_train, y_two_train)
pred_y_all = model_all.predict(x_all_test)
pred_y_two = model_two.predict(x_two_test)
all_pred.append(accuracy_score(y_all_test, pred_y_all))
two_pred.append(accuracy_score(y_two_test, pred_y_two))
all_ave = np.average(np.array(all_pred))
two_ave = np.average(np.array(two_pred))
print(all_ave, two_ave)
試行回数を変えてどちらのモデルがいいか検討してみる
これで4種類の特徴量データを使った方がいいのか、2種類の特徴量データを使った方がいいのか検討をしてみましょう。
今回は試行回数100回の平均値を出していきますが、それを5回行ってみることにします。
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
all | 0.97600 | 0.97300 | 0.97400 | 0.97500 | 0.97600 |
two | 0.96800 | 0.96266 | 0.96266 | 0.96266 | 0.96400 |
4種類全部を使った方がどうやらほんの少しだけいいようです。
ここでは前回、前々回で調べてきたようにしっかり分類してくれそうな「petal lengthとpetal width」を使っています。
ではちょっと分類の境界が曖昧そうな「sepal lengthとsepal width」を使ったらどうなるでしょうか。
ということでデータを格納するこの部分のプログラムを変更します。
x_all = df.loc[:, ["sepal length (cm)", "sepal width (cm)", "petal length (cm)", "petal width (cm)"]]
x_two = df.loc[:, ["sepal length (cm)", "sepal width (cm)"]]
そして同じように100回の平均値を5回取得してみましょう。
1回目 | 2回目 | 3回目 | 4回目 | 5回目 | |
all | 0.97766 | 0.97300 | 0.96500 | 0.97100 | 0.97333 |
two | 0.80133 | 0.79766 | 0.79466 | 0.78733 | 0.78566 |
今回は大きな差が出ました。
やはりsepal lengthとsepal width」はあまり3種類のアヤメ(iris)を見分けるには差があまりなく、このデータだけで機械学習をするとあまり精度が上がらないようです。
なかなか面白い検討でしたね。
今回言えることとしては、やはり機械学習の精度にデータの質が大きく関わってくるということです。
ということはどうやってデータを準備するのか、また今回のように得られたデータのうちどれを使うのかというのはなかなか重要な仕事であるということです。
こればかりは機械学習の経験値を増やしていくしかないのではないかと思います。
ただもう一つ重要なのは、機械学習は今回のように分類するだけのものではありません。
他の機械学習の手法やその結果を学ぶことも重要なことなので、次回はScikit-learnに含まれる他のデータセットを試してみましょう。
ということで今回はこんな感じで。
コメント