今回は、Losistic Regressionモデルと同様、強力で幅広く使われている機械学習アルゴリズムの「Support Vector Machines(SVM)」についてご紹介します。SVMは、Perceptronと同様に分類クラスの誤りを最小にするアルゴリズムを使用していることから、Perceptronの拡張とも考えられていますが、SVMでは、最適化の目的がマージンを最大にすることにあります。マージンとは、区切られたハイパープレインの距離と定義されます。このハイパープレインの近くに散在するトレーニングデータのサンプルをサポート・ベクターを呼びます。このSVMをモデル(Classifier)に使用して、今回、機械学習を行っていきたいと思います。

 

 

今回、使用するデータは、オープンソースであるUCI機械学習リポジトリから、「ウィスコンシン肺がんデータ」を使用します。569のデータからなり、第1列目はサンプルのID番号、2列目に’M’(悪性)または'B'(良性)かの分類クラスが、3列目から32列目までが変量になります。

 

https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data

 

30の変量がありますが、2次元の図にプロットする都合上、主成分分析により、2つの主成分を抽出し、Pythonを使用して肺がんが悪性か良性かを予測する機械学習モデルを作成します。主成分分析とPythonを使用した機械学習の流れは、概ね以下になります。なお、Pythonのバージョンは3.5以上を想定しています。

 

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

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

 

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

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

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

 

ここでは、以下のように、「plot_decision_regions」という名前のプロット出力用の関数を定義します。第6回から第9回で使用したものと全く同じ関数です。

 

import numpy as np

import matplotlib.pyplot as plt

from matplotlib.colors import ListedColormap

 

def plot_decision_regions(X, y, classifier, 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())

    # plot class samples
    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)
            

 

②データを入力する。

今回は、冒頭でご紹介した「ウィスコンシン肺がんデータ」を、オープンソースとして提供しているサイトのURLから、pandasライブラリーを使用して以下のようにデータを抽出します。変量Xの配列(569 x 30)に、ラベル(悪性か良性か)を y(569x 1)という配列に569サンプル分のデータを格納します。sklearn.preprocessingライブラリーのLabelEncoder関数を使用して、ラベルの'M'(悪性)を数字の'1'に、'B'(良性)を数字の'0'に、それぞれ変換しています。

 

import pandas as pd

df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data', header=None)

 

from sklearn.preprocessing import LabelEncoder

X = df.loc[:, 2:].values

y = df.loc[:, 1].values

le = LabelEncoder()

y = le.fit_transform(y)

 

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

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

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

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=1)

 

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

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がscikit-learnライブラーの中でサポートされています。線形データとして分類できる場合は、Perceptron, Adaptive Linear Neuron(Adaline),Logistic regulation, Support Vector Machines(SVM),Decision tree, Random forests, K-nearest neighbors(KNN)などがあります。今回は、 Support Vector Machines(SVM)を選択することにいたします。sklearn.svmライブラリーのSVC関数を使用して以下のように記述します。

from sklearn.svm import SVC
svm = SVC(kernel='linear',C=1.5, random_state=0)

 

まず、kernelの値に指定出来るのは、‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’,‘precomputed’のいずれかで、デフォルトは、‘rbf’です。ここでは、線形に分類するため、kernel='linear'を採用します。Cは、第8回でご紹介した正則化(regularization)のパラメータで、Cが小さい程、正則化の罰則(penalty)が多くなります。デフォルトは C=1.0ですが、ここでは、C=1.5を指定します。

 

⑦主成分分析により、入力データから上位2つの主成分を抽出する。

sklearn.decompositionライブラリーの中でサポートされているPCA関数を用いて、トレーニングデータについて主成分分析を行い、トレーニングデータ及びテストデータについて、2つの主成分を抽出します。

 

from sklearn.decomposition import PCA

pca = PCA(n_components=2)

X_train_pca = pca.fit_transform(X_train_std,y_train)

X_test_pca = pca.transform(X_test_std)

 

⑧主成分分析により抽出されたトレーニングデータを使用して、モデルに機械学習させる。

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

svm.fit(X_train_pca, y_train)

 

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

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

 

from sklearn.metrics import accuracy_score

y_pred = svm.predict(X_test_pca)

print('Accuracy: %.3f' % accuracy_score(y_test,y_pred))

         

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

Accuracy: 0.956

 

Support Vector Machines(SVM)にご興味のある方は、以下の本の第3章を是非、読んでみてください。

「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

 

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

①で定義したplot_decision_regions関数を用いて、トレーニングデータとテストデータについて、それぞれ、抽出した第1主成分(PC1)を横軸に、第2主成分(PC2)を縦軸にした2次元領域にプロットします。

 

まず、トレーニングデータについてプロットします。

plot_decision_regions(X_train_pca, y_train, classifier=svm)

plt.xlabel('PC 1')

plt.ylabel('PC 2')

plt.legend(loc='lower left')

plt.tight_layout()

plt.show()

 

×印と青い領域が「悪性: 1」、■印と赤い領域が「良性:0」を表しています。

複数のサンプルに例外がありますが、トレーニングデータについて、概ね、直線で、分類されていることがわかります。

 

次に、テストデータについてプロットします。

plot_decision_regions(X_test_pca, y_test, classifier=svm)

plt.xlabel('PC 1')

plt.ylabel('PC 2')

plt.legend(loc='lower left')

plt.tight_layout()

plt.show()

 

テストデータについても、4つのサンプルに例外がありますが、概ね、直線で、分類されていることがわかります。

 

 

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

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

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

def plot_decision_regions(X, y, classifier, 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())

    # plot class samples
    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)


import pandas as pd

df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data', header=None)

from sklearn.preprocessing import LabelEncoder
X = df.loc[:, 2:].values
y = df.loc[:, 1].values
le = LabelEncoder()
y = le.fit_transform(y)

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=1)

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.svm import SVC
svm = SVC(kernel='linear',C=1.5, random_state=0)

from sklearn.decomposition import PCA
pca = PCA(n_components=2)
X_train_pca = pca.fit_transform(X_train_std,y_train)
X_test_pca = pca.transform(X_test_std)
svm.fit(X_train_pca, y_train)

from sklearn.metrics import accuracy_score
y_pred = svm.predict(X_test_pca)
print('Accuracy: %.3f' % accuracy_score(y_test,y_pred))

plot_decision_regions(X_train_pca, y_train, classifier=svm)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()

plot_decision_regions(X_test_pca, y_test, classifier=svm)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()