PythonのScikit-LearnによるSVMとKernel SVMの実装

サポートベクターマシン(SVM)は、教師あり機械学習の分類アルゴリズムの一種である。SVMは1960年代に導入され、その後1990年代に改良された。SVMは1960年代に導入され、1990年代に改良されましたが、現在ではその優れた能力により、非常に人気が高まっています。SVMは他の機械学習アルゴリズムと比較すると、ユニークな方法で実装されています。

この記事では、サポートベクターマシンアルゴリズムとは何か、サポートベクターマシンの背後にある簡単な理論、そしてPythonのScikit-Learnライブラリでの実装を紹介します。その後、カーネルSVMと呼ばれる高度なSVMの概念に触れ、Scikit-Learnの助けを借りてそれを実装していきます。

シンプルなSVM

図1のような2次元の線形分離可能なデータの場合、典型的な機械学習アルゴリズムでは、誤判定誤差が最小になるようにデータを分割する境界を探そうとする。図1をよく見ると、データ点を正しく分割する境界線がいくつか存在することがわかる。2本の破線と1本の実線は正しくデータを分類しています。

図1:複数の判定境界

SVMが他の分類アルゴリズムと異なる点は、すべてのクラスの最も近いデータ点からの距離が最大になるような境界を選択する点である。SVMは、単に決定境界を見つけるだけでなく、最も最適な決定境界を見つけるのです。

最適な決定境界とは、全クラスの最近接点からのマージンが最大となる決定境界のことです。図2に示すように、決定境界と点の距離が最大となる決定境界からの最近接点をサポートベクターと呼ぶ。サポートベクターマシンの場合の判定境界は、最大マージン分類器、あるいは最大マージン超平面と呼ばれる。

図2:サポートベクターによる判定境界

サポートベクターを見つけ、決定境界とサポートベクター間のマージンを計算し、このマージンを最大化するためには、複雑な数学が関係しています。このチュートリアルでは、数学の詳細には触れず、SVMとカーネルSVMがPython Scikit-Learnライブラリでどのように実装されるかを見ていきます。

Scikit-LearnでSVMを実装する。

このセクションで使用するデータセットは、決定木チュートリアルの分類のセクションで使用したものと同じです。

我々の課題は、紙幣の4つの属性、すなわち、ウェーブレット変換された画像の歪度、画像の分散、画像のエントロピー、画像の曲率に基づいて、紙幣が本物かどうかを予測することです。これは二値分類問題であり、この問題を解決するためにSVMアルゴリズムを使用します。残りの部分は標準的な機械学習のステップで構成されています。

ライブラリのインポート

以下のスクリプトは、必要なライブラリをインポートします。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline


データセットのインポート

データは以下のリンクからダウンロード可能です。

302 Moved

データの詳細情報は、以下のリンクから入手可能です。

UCI Machine Learning Repository: banknote authentication Data Set

Google driveのリンクからデータセットをダウンロードし、自分のマシンにローカルに保存します。この例では、データセットのCSVファイルは、WindowsコンピュータのDドライブの「Datasets」フォルダに保存されている。スクリプトはこのパスからファイルを読み取ります。お使いのコンピュータのファイルパスは適宜変更してください。

CSVファイルからデータを読み込むには、pandasライブラリの read_csv メソッドを使用するのが最も簡単な方法です。以下のコードでは、銀行券のデータをpandasのデータフレームに読み込んでいます。

bankdata = pd.read_csv("D:/Datasets/bill_authentication.csv")


探索的データ解析

Pythonの様々なライブラリを使ってデータセットを分析する方法は、事実上無限にあります。ここでは、簡単のために、データの次元と最初の数レコードを見るだけにしておきます。データの行と列を見るには、以下のコマンドを実行します。

bankdata.shape


出力に(1372,5)と表示されます。これは、銀行券のデータセットが1372行5列であることを意味します。

データセットが実際にどのように見えるかを知るために、次のコマンドを実行してみてください。

bankdata.head()


出力はこのようになる。

| 分散|歪度|カートーシズ|エントロピー|クラス|…
| — | — | — | — | — | — |
| 0 | 3.62160 | 8.6661 | -2.8073 | -0.44699 | 0 |
| 1 | 4.54590 | 8.1674 | -2.4586 | -1.46210 | 0 |
| 2 | 3.86600 | -2.6383 | 1.9242 | 0.10645 | 0 |
| 3 | 3.45660 | 9.5228 | -4.0112 | -3.59440 | 0 |
| 4 | 0.32924 | -4.4552 | 4.5718 | -0.98880 | 0 |

データセットのすべての属性が数値であることがわかります。ラベルも数値、すなわち0と1である。

データ前処理

データの前処理として、(1)データを属性とラベルに分ける、(2)データをトレーニングセットとテストセットに分ける、があります。

データを属性とラベルに分けるには、以下のコードを実行する。

X = bankdata.drop('Class', axis=1)
y = bankdata['Class']


上記のスクリプトの最初の行では、bankdata データフレームのうち、ラベルカラムである “Class” カラムを除く全てのカラムが X 変数に格納されています。drop()` メソッドはこのカラムを削除します。

2 行目では、class カラムだけが y 変数に格納されています。この時点では、X変数に属性が格納され、y変数に対応するラベルが格納されています。

データが属性とラベルに分割されたら、最後の前処理として、データをトレーニングセットとテストセットに分割する必要があります。幸運なことに、Scikit-Learn ライブラリの model_selection ライブラリには train_test_split メソッドがあり、これを使えばシームレスにデータをトレーニングセットとテストセットに分割することができる。

以下のスクリプトを実行してください。

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


アルゴリズムの学習

データをトレーニングセットとテストセットに分けました。次は学習データに対して SVM を学習させる番です。Scikit-Learn には svm ライブラリがあり、さまざまな SVM アルゴリズムの組み込みクラスが含まれています。ここでは分類タスクを実行するので、サポートベクター分類器クラスを使用します。Scikit-Learn の svm ライブラリでは SVC と記述されています。このクラスは1つのパラメータを受け取り、それはカーネルタイプです。これは非常に重要なことです。単純なSVMの場合、単純なSVMは線形分離可能なデータしか分類できないので、このパラメータを単純に「線形」に設定します。次の節では、非線形カーネルについて見ていきます。

SVC クラスの fit メソッドにパラメータとして渡された学習データを用いて、アルゴリズムを学習させます。以下のコードを実行して、アルゴリズムを学習してください。

from sklearn.svm import SVC
svclassifier = SVC(kernel='linear')
svclassifier.fit(X_train, y_train)


予想すること

予測を行うには、SVC クラスの predict メソッドを使用します。以下のコードを見てください。

y_pred = svclassifier.predict(X_test)


アルゴリズムの評価

Confusion matrix, precision, recall, F1 メトリクスは分類タスクで最もよく使われるメトリクスです。Scikit-Learnの metrics ライブラリには classification_reportconfusion_matrix メソッドがあり、これらの重要なメトリックスの値を簡単に見つけることができます。

以下は、これらのメトリクスを求めるためのコードです。

from sklearn.metrics import classification_report, confusion_matrix
print(confusion_matrix(y_test,y_pred))
print(classification_report(y_test,y_pred))


結果

評価結果は以下のとおりです。

[[152    0]
 [  1  122]]
              precision   recall   f1-score   support


0       0.99     1.00       1.00       152
           1       1.00     0.99       1.00       123


avg / total        1.00     1.00       1.00       275


結果から、SVMは決定木アルゴリズムよりわずかに優れていることが観察される。決定木アルゴリズムの場合、4つの誤分類があったのに対し、SVMアルゴリズムの場合、誤分類は1つだけであった。

カーネルSVM

前節では、線形分離可能なデータに対して、単純な SVM アルゴリズムで決定境界を求める方法を見た。しかし、図3のような非線形分離可能なデータの場合、直線は判定境界として使用できない。

図3:非線型分離可能なデータ

非線形分離可能なデータの場合、単純なSVMアルゴリズムでは対応できない。そこで、カーネルSVMと呼ばれるSVMの改良版を使用する。

基本的に、カーネルSVMは、異なるクラスに属するデータ点が異なる次元に割り当てられるように、非線形分離可能なデータの低次元を線形分離可能なデータの高次元に投影する。ここでも複雑な数学が登場しますが、SVMを利用する上では気にする必要はありません。むしろ、PythonのScikit-Learnライブラリを使って、カーネルSVMを実装し、利用することができるのです。

Scikit-LearnによるカーネルSVMの実装

Scikit-Learn を用いたカーネル SVM の実装は、単純な SVM と同様である。ここでは、有名な虹彩のデータセットを使って、萼幅、萼長、花弁幅、花弁長の4つの属性から、植物がどのカテゴリに属するかを予測することにする。

データセットは以下のリンクからダウンロードできる。

UCI Machine Learning Repository: Data Set

残りのステップは典型的な機械学習のステップであり、カーネルSVMを訓練する部分に到達するまではほとんど説明が必要ない。

ライブラリのインポート

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd


データセットのインポート

url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"


# Assign colum names to the dataset
colnames = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'Class']


# Read dataset to pandas dataframe
irisdata = pd.read_csv(url, names=colnames)


Preprocessing

False Code

Train Test Split

Fake Code

アルゴリズムの学習

カーネル SVM の学習には、Scikit-Learn の svm ライブラリにある SVC クラスを利用します。違いは SVC クラスのカーネルパラメータの値です。単純なSVMの場合、カーネルパラメータの値として “linear “を使いました。しかし、カーネルSVMでは、ガウスカーネル、多項式カーネル、シグモイドカーネル、計算可能カーネルを使用することができます。ここでは、多項式カーネル、ガウシアンカーネル、シグモイドカーネルを実装し、我々の問題に対してどれがより効果的であるかを確認します。

1. 多項式カーネル

多項式カーネルの場合、 SVC クラスの degree パラメータにも値を渡す必要があります。これは基本的に多項式の次数です。カーネル SVM を実装するために、どのように多項式カーネルを使用できるかを見てみましょう。

X = irisdata.drop('Class', axis=1)
y = irisdata['Class']


予想すること

さて、アルゴリズムの学習が終わったら、次はテストデータに対して予測を行います。

以下のスクリプトを実行してください。

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


アルゴリズムの評価

機械学習アルゴリズムの最終段階として、多項式カーネルを評価する。以下のスクリプトを実行する。

from sklearn.svm import SVC
svclassifier = SVC(kernel='poly', degree=8)
svclassifier.fit(X_train, y_train)


多項式カーネルを用いたカーネルSVMの出力は以下のようになります。

y_pred = svclassifier.predict(X_test)


次にガウシアンカーネルとシグモイドカーネルについて同じステップを繰り返してみましょう。

2. ガウシアンカーネル

多項式カーネルを使ってカーネルSVMを実装する方法を見てみましょう。

from sklearn.metrics import classification_report, confusion_matrix
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))


ガウシアンカーネルを使用するには、SVC クラスの Kernel パラメータに ‘rbf’ を指定する必要があります。

予測・評価

[[11  0  0]
 [ 0 12  1]
 [ 0  0  6]]
                 precision   recall   f1-score   support


Iris-setosa       1.00     1.00       1.00        11
Iris-versicolor       1.00     0.92       0.96        13
 Iris-virginica       0.86     1.00       0.92         6


avg / total       0.97     0.97       0.97        30


from sklearn.svm import SVC
svclassifier = SVC(kernel='rbf')
svclassifier.fit(X_train, y_train)


ガウシアンカーネルを用いたカーネルSVMの出力は以下のようになります。

y_pred = svclassifier.predict(X_test)


3. シグモイドカーネル

最後に、カーネルSVMを実装するためにシグモイドカーネルを使用してみましょう。以下のスクリプトを見てください。

from sklearn.metrics import classification_report, confusion_matrix
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))


シグモイドカーネルを使うには、 SVC クラスの kernel パラメータに ‘sigmoid’ を指定する必要があります。

予測・評価

[[11  0  0]
 [ 0 13  0]
 [ 0  0  6]]
                 precision   recall   f1-score   support


Iris-setosa       1.00     1.00       1.00        11
Iris-versicolor       1.00     1.00       1.00        13
 Iris-virginica       1.00     1.00       1.00         6


avg / total       1.00     1.00       1.00        30


from sklearn.svm import SVC
svclassifier = SVC(kernel='sigmoid')
svclassifier.fit(X_train, y_train)


シグモイドカーネルを用いたカーネルSVMの出力は以下のようになります。

y_pred = svclassifier.predict(X_test)


カーネル性能の比較

異なるタイプのカーネルの性能を比較すると、シグモイドカーネルの性能が最も悪いことがはっきりわかります。これは、シグモイド関数が0と1の2つの値を返すため、2値分類の問題に適しているためです。しかし、我々のケースでは、3つの出力クラスがありました。

ガウスカーネルと多項式カーネルのうち、ガウスカーネルは完璧な100%の予測率を達成したのに対し、多項式カーネルは1つのインスタンスを誤って分類していることがわかります。したがって、ガウスカーネルの方が若干性能が良いことがわかります。しかし、すべてのシナリオでどのカーネルが最もよく機能するかについて、厳密で速いルールはありません。すべてのカーネルをテストし、テストデータセットで最も良い結果を得たカーネルを選択することが重要なのです。

さらに上を目指す – 手作りのEnd to Endプロジェクト

好奇心旺盛なあなたは、もっと先を目指したいと思っていませんか?そんなあなたには、ガイド付きプロジェクトがおすすめです。「ハンズオン住宅価格予測 – Pythonによる機械学習” をご覧ください。

をご覧ください。
このプロジェクトでは、Scikit-LearnとKerasのモデルから住宅価格を予測するために、従来の機械学習モデルや深層学習モデル、Ensemble Learning、メタラーを利用した強力な構築方法を学ぶことができます。
>
>
>

Tensorflowの上に構築された深層学習APIであるKerasを使って、アーキテクチャを試し、積み重ねたモデルのアンサンブルを構築し、メタラーナーのニューラルネットワーク(レベル1モデル)を訓練して、家の価格を割り出すことにします。

ディープラーニングは素晴らしいものですが、それに頼る前に、浅い学習アルゴリズムのような、より単純な技術で問題を解決することも試みることをお勧めします。ベースラインの性能は、ランダムフォレスト回帰アルゴリズムに基づくものです。さらに、Scikit-Learnを使用して、バギングや投票などの手法により、モデルのアンサンブルを作成することも検討します。

これはエンドツーエンドのプロジェクトであり、他の機械学習プロジェクトと同様に、探索的データ分析から始まり、データ前処理を経て、最後に浅い学習と深い学習のモデルを構築して、以前に探索とクリーニングを行ったデータに適合させます。

結論

この記事では、単純なSVMとカーネルSVMの両方について勉強しました。SVMアルゴリズムの背後にある直感と、それがPythonのScikit-Learnライブラリでどのように実装されるかを学びました。また、カーネルSVMを実装するために使用できる様々な種類のカーネルを勉強しました。これらのアルゴリズムをkaggle.comのような場所で入手可能な実世界のデータセットで実装してみることをお勧めします。

また、SVMの背後にある実際の数学について調べてみることをお勧めします。SVMアルゴリズムを使うのに必ずしもそれが必要なわけではありませんが、アルゴリズムが決定境界を見つけるときに、舞台裏で実際に何が起こっているかを知ることは非常に便利です。

タイトルとURLをコピーしました