機械学習(Machine Learning)の勉強を始めました。第5回

今回は、前回(第4回)でご紹介した「アイリス花データ」を使用して、機械学習を実際に実行してみたいと思います。第3回でご紹介したように、機械学習には、大きく分けて、「Supervised Learning」、「Unsupervised Learning」、「Reinforcement Learning」の3種類がありました。ここでは、Supervised Learningをまず、ご紹介します。

 

Supervised Learningというのは、出力データにラベルを付けられるもので、例えば、ウイルスに感染しているか否か、スパムメールかどうか、花の種類といったように、結果にラベルを付けて分類できるデータを扱うものになります。アイリス花データの場合、変量として、がく片(sepal)の長さと幅、花びら(petal)長さと幅をcmで計測した4つの変量があり、ラベルとしては、アイリスの花の種類(Iris setosa/Iris versicolor/Iris virginica)の3種類がありました(詳しくは第4回をご参照ください)。

 

4つの変量がありますが、2次元の図にプロットする都合上、花びらの長さ[cm]と花びらの幅[cm]の2つの変量から、Pythonを使用してアイリスの花の種類を予測する機械学習モデルを作成します。Pythonを使用した機械学習の流れは、概ね以下になります。なお、Pythonのバージョンは3.5以上を想定しています。

 

  1. プロット出力用の関数を定義する。
  2. データを入力する。
  3. 入力データを、トレーニングデータとテストデータに分ける。
  4. トレーニングデータを使用してデータの標準偏差と平均値を求める。
  5. 標準偏差と平均値を使用して、トレーニングデータとテストデータを、それぞれ標準化する。
  6. 適切なモデル(Classifier)を選択する。
  7. トレーニングデータを使用して、モデルに機械学習させる。
  8. テストデータを使用して、ラベルの分類を行い、モデルを評価する。
  9. 学習結果を図にプロットする。

では、各ステップを詳しく見ていきましょう。

 

①プロット出力用の関数を定義する。

まず、対話形式ではなく、Pythonスクリプトをファイルで用意します。Pythonスクリプトの先頭に以下の2行を添付しておくことをお勧めします。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

 

ここでは、以下のように、「plot_decision_regions」という名前のプロット出力用の関数を定義します。
 
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):


    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
                    alpha=0.8, c=cmap(idx),
                    marker=markers[idx], label=cl)

    # highlight test samples
    if test_idx:
        # plot all samples
        X_test, y_test = X[test_idx, :], y[test_idx]

        plt.scatter(X_test[:, 0],
                    X_test[:, 1],
                    c='black',
                    alpha=0.5,
                    linewidths=1,
                    marker='o',
                    s=55, label='test set')
          
 

②データを入力する。

前回の第4回でご紹介した「アイリス花データ」は、オープンソースとして提供しているサイトのURLから、pandasライブラリーを使用して入力しましたが、実は、scikit-learningライブラリーの中に、アイリス花データがサポートされています。今回は、こちらのscikit-learning ライブラリーから、以下のようにデータを抽出します。変量の内、花びらの長さと幅だけを取り出すために、iris.dataの変量の内、2番目と3番目の要素だけを抽出してXの配列(150 x 2)に、ラベル(花びらの種類)を y(150 x 1)という配列に150サンプル分のデータを格納します。

from sklearn import datasets
iris = datasets.load_iris()
X = iris.data[:,[2,3]]
y = iris.target

 

③入力データを、トレーニングデータとテストデータに分ける。

 scikit-learning.cross_validationライブラリーのtrain_test_split関数を使用して、

変量配列Xとラベル配列yについて、トレーニングデータとテストデータに分けます。変量配列Xを、それぞれ、X_train配列, X_test配列に分割し、ラベル配列yは、y_tarin配列, y_test配列へそれぞれ分割します。test_sizeのパラメータにより、テストデータの割合を指定できます。ここでは、0.3を指定することで、テストデータの割合を全体の30%と指定しています。全150サンプルの30%(= 45サンプル)がテストデータで、残りの105サンプルがトレーニングデータとなります。random_state=0を指定することにより、ランダムにトレーニングデータとテストデータを分割することができます。

from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.3, random_state=0)

 

④トレーニングデータを使用してデータの標準偏差と平均値を求める。

 sklearn.preprocessingライブラリーのStandardScaler関数を用いて、変量配列X_trainとX_testを標準化します。まず、標準化のための標準偏差と平均値は、トレーニングデータのみを使用して計算しなければなりません。fitメソッドを使用して以下のように行います。

from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train)

 

標準偏差と平均値を使用して、トレーニングデータとテストデータを、それぞれ標準化する。

次に、変量配列のトレーニングデータとテストデータを、transformメソッドを用いて、それぞれ標準化します。標準化した変量配列をそれぞれ、X_train_std, X_test_stdに格納します。

X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)

 

⑥適切なモデル(Classifier)を選択する。

様々なClassifierがPythonライブラーの中でサポートされています。線形データとして分類できる場合は、Perceptron, Adaptive Linear Neuron(Adaline),Logistic regulation, Support Vector Machine(SVM),Decision tree, Random forests, K-nearest neighbors(KNN)などがあります。「アイリス花データ」は線形データとして分類できるデータであるため、ここでは、最もシンプルなPerceptronのモデルを選択することとします。sklearn.linear_modelライブラリーのPerceptron関数を使用して以下のように記述します。

from sklearn.linear_model import Perceptron
ppn = Perceptron(n_iter=40,eta0=0.1, random_state=0)

ここで、n_iterは、「Epoch」と呼ばれる機械学習の試行回数で、eta0は、変量の各試行における係数の更新分Δω ( ω := ω + Δω)を調整する値です。Perceptronのモデルでは、データが完全に線形である時、試行を重ねる毎に、係数ωの値が最適化されて行きます。eta0の値が小さい程、最適値に収束しやすくなりますが、試行回数 n_iterの数を大きくなる傾向があり、eta0とn_iterの値のバランスを、うまく取る必要があります。

ラベルの予測値を、φ(z) で表すと、各学習試行のおける係数の更新Δωは、次のように表されます。

数式の詳細にご興味のある方は、以下の本の第2章を是非、読んでみてください。

Python Machine Learning: Unlock Deeper Insights into Machine Learning With This Vital Guide to Cutting-edge Predictive Analytics」

Sebastian Raschka (著)

出版社: Packt Publishing (2015/9/23)

言語: 英語

ISBN-10: 1783555130

ISBN-13: 978-1783555130

 

⑦トレーニングデータを使用して、モデルに機械学習させる。

トレーニングデータにfitメソッドを適用して、学習させます。

ppn.fit(X_train_std, y_train)

 

テストデータを使用して、ラベルの分類を行い、モデルを評価する。

テストデータを使用して、ラベルの分類を行い、sklearn.metricsライブラリーのaccuracy_score関数を用いて、モデルの精度を評価します。

from sklearn.metrics import accuracy_score
y_pred = ppn.predict(X_test_std)
print('Accuracy: %.2f' % accuracy_score(y_test,y_pred))

出力結果は、以下のように91%の精度と表示されます。
Accuracy: 0.91

⑨学習結果を図にプロットする。

①で定義したplot_decision_regions関数を用いて、150サンプル全データについて、花びらの長さ[cm]を横軸に、花びらの幅[cm]を縦軸にした2次元領域にプロットします。●で囲まれた点がテストデータを用いて予測したラベルのデータとなります。テストデータ45サンプルの内、4サンプルが正しく分類できませんでした。図の内、赤の領域が今回の機械学習で得られたモデルにより予測したIris setosa(値:0)の領域です。青の領域は、機械学習モデルが予想したIris versicolor(値:1)の領域です。ライトグリーンの領域は、機械学習モデルが予測したIris virginica(値:2)の領域です。若干、正しく分類できていないデータがありますが、概ね、直線で分類ができていることがわかるかと思います。

import numpy as np
X_combined_std = np.vstack((X_train_std, X_test_std))
y_combined = np.hstack((y_train, y_test))

plot_decision_regions(X=X_combined_std, y=y_combined,
                      classifier=ppn, test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()

 

全体を通してのコードは以下のようになります。なお、本コードの稼働環境は、Python3.5以上を想定しています。

import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):


    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
                    alpha=0.8, c=cmap(idx),
                    marker=markers[idx], label=cl)

    # highlight test samples
    if test_idx:
        # plot all samples
        X_test, y_test = X[test_idx, :], y[test_idx]

        plt.scatter(X_test[:, 0],
                    X_test[:, 1],
                    c='black',
                    alpha=0.5,
                    linewidths=1,
                    marker='o',
                    s=55, label='test set')

from sklearn import datasets
iris = datasets.load_iris()
X = iris.data[:,[2,3]]
y = iris.target

from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.3, random_state=0)

from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train)

X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)

from sklearn.linear_model import Perceptron
ppn = Perceptron(n_iter=40,eta0=0.1, random_state=0)

ppn.fit(X_train_std, y_train)

from sklearn.metrics import accuracy_score
y_pred = ppn.predict(X_test_std)
print('Accuracy: %.2f' % accuracy_score(y_test,y_pred))

import numpy as np
X_combined_std = np.vstack((X_train_std, X_test_std))
y_combined = np.hstack((y_train, y_test))

plot_decision_regions(X=X_combined_std, y=y_combined,
                      classifier=ppn, test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()