sklearn を利用した SVM 判別器の作り方

scikit-learn (sklearn) は Python パッケージの一つで、様々な機械学習アルゴリズムが実装されている。scikit-learn を利用すると、関数一つで特定の機械学習アルゴリズムを呼び出して、学習や予測が行えるようになる。SVM は、scikit-learn の sklearn.svm モジュールで定義されている。このページは、SVM で判別器の作り方を示す。

ここでサンプルデータセットとして scikit-learn パッケージに実装されている乳がんに関するデータセットを使用する。このデータセットには 569 サンプルを含み、30 個の特徴量を持つ。モデルを構築するにあたって、569 サンプルのうち 60% を学習用に使用し、40% を検証用に使用する。なお、学習データと検証データの振り分けについて、再現性を持たせるように random_state=1234 を指定しておく。

簡単な SVM モデルの作り方

まず、ソフトマージン法 SVM のハイパーパラメーター C を 0.1 に固定して、モデルを作成してみる。

import sklearn.datasets
import sklearn.model_selection
import sklearn.metrics
import sklearn.svm

cancer = sklearn.datasets.load_breast_cancer()
X = cancer.data
y = cancer.target

X_train, X_test, y_train, y_test =\
  sklearn.model_selection.train_test_split(X, y, test_size=0.4, random_state=1234)

clf = sklearn.svm.SVC(kernel='rbf', C=0.1)
clf.fit(X_train, y_train)

y_pred = clf.predict(X_test)
score = sklearn.metrics.accuracy_score(y_test, y_pred)
print(score)
# 0.7105263157894737

次に、ハイパーパラメーター C の値を 1.0 に固定して、上と同様なコードでモデルを作成してみる。C の値が大きくなると予測精度が上がることがわかる。

import sklearn.datasets
import sklearn.model_selection
import sklearn.metrics
import sklearn.svm

cancer = sklearn.datasets.load_breast_cancer()
X = cancer.data
y = cancer.target

X_train, X_test, y_train, y_test =\
  sklearn.model_selection.train_test_split(X, y, test_size=1.0, random_state=1234)

clf = sklearn.svm.SVC(kernel='rbf', C=0.1)
clf.fit(X_train, y_train)

y_pred = clf.predict(X_test)
score = sklearn.metrics.accuracy_score(y_test, y_pred)
print(score)
# 0.8947368421052632

交差検証

次に、もう少し真面目にモデルを構築してみる。まず特徴量を標準化してから主成分分析を行い、データ全体の 60% を説明できるまでの上位にある主成分を使って SVM 判別器を構築する。データについて、学習データをさらにサブセットに分けて 5-fold 交差検証を行うことにする。

import numpy as np
import pandas as pd
import sklearn.model_selection
import sklearn.metrics
import sklearn.preprocessing
import sklearn.decomposition
import sklearn.pipeline

X_train, X_test, y_train, y_test =\
  sklearn.model_selection.train_test_split(X, y, test_size=0.4, random_state=1234)

# 5-fold cross-validation
k = 5
skf = sklearn.model_selection.StratifiedKFold(n_splits=k, random_state=1234, shuffle=True)

c_values = [0.01, 0.1, 1.0, 10, 100]
scoring = ['f1_macro', 'precision_macro', 'recall_macro']
scores = None

for c in c_values:    
    pipe = sklearn.pipeline.Pipeline([
            ('scaler', sklearn.preprocessing.StandardScaler()),
            ('pca', sklearn.decomposition.PCA(0.6)),
            ('clf', sklearn.svm.SVC(kernel='rbf', C=c))
        ])
    
    score = sklearn.model_selection.cross_validate(pipe, X_train, y_train, scoring=scoring, cv=skf)
    x = pd.concat([pd.Series(np.full(k, c), name='C'), pd.DataFrame(score)], axis=1)
    
    scores = pd.concat([scores, x])
    
print(scores)
##         C  fit_time  ...  test_precision_macro  test_recall_macro
## 0    0.01  0.004720  ...              0.311594           0.500000
## 1    0.01  0.003941  ...              0.316176           0.500000
## 2    0.01  0.003821  ...              0.316176           0.500000
## :
## :
## 3  100.00  0.003433  ...              0.988372           0.980769
## 4  100.00  0.003202  ...              0.950768           0.956960

次に交差検証で決めた最適な C を使って、モデルを構築する。この際に、学習データのすべてを使ってモデルを構築する(5-fold 交差検証に分けていたサブセットを考慮しない)。次に、構築したモデルを、テストデータでテストする。

best_c = scores.loc[scores.loc[:, 'test_f1_macro'] == max(scores.loc[:, 'test_f1_macro']), 'C'].values[0]
print(best_c)
## 100.0

 pipe = sklearn.pipeline.Pipeline([
            ('scaler', sklearn.preprocessing.StandardScaler()),
            ('pca', sklearn.decomposition.PCA(0.6)),
            ('clf', sklearn.svm.SVC(kernel='rbf', C=best_c))
        ])
    
pipe.fit(X_train, y_train)

y_pred = pipe.predict(X_test)
score = sklearn.metrics.accuracy_score(y_test, y_pred)
print(score)
## 0.9035087719298246