Scikit-learnのpipeleine.Pipelineが便利

分析する際に、次元圧縮→分類のような流れで行う場合には、scikit-learnのPipelineが便利。特にハイパーパラメーターを探すときには手続が煩雑になることもありますが、まとめて分類器としててGridSearchCVに突っ込むだけで良いのでめんどくさいこと考えずに済みますね。

今回はScikit-learnのサンプルデータの中から、the digits datasetのデータをロードし、PCAでの次元圧縮からSVMでの分類をPipelineでまとめて実行する手順を確認してみました。

コード

まずはデータを読み込み、訓練データとテストデータに分割。
また手書き文字のデータがどんなものかを描き出します。

import numpy as np

from sklearn import svm
from sklearn.decomposition import PCA

from sklearn import datasets
from sklearn.grid_search import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.cross_validation import train_test_split
from sklearn import metrics

from matplotlib import pyplot as plt
from matplotlib import cm
%matplotlib inline

digits = datasets.load_digits()
X = digits.data
y = digits.target
print 'Number of data = {0}, Dimension = {1}'.format(X.shape[0],X.shape[1])

p = np.random.random_integers(0, len(digits.data), 25)
for index, (data, label) in enumerate(np.array(zip(digits.data, digits.target))[p]):
    plt.subplot(5, 5, index + 1)
    plt.axis('off')
    plt.imshow(data.reshape(8, 8), cmap=plt.cm.gray_r, interpolation='nearest')
    plt.title('%i' % label)
plt.show()


#Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

Number of data = 1797, Dimension = 64

f:id:tkzs:20160626092429p:plain


続いて、PCAで次元削減、SVMでの分類という2つの手順を一つのPipelineで分類器としてまとめます。
今回グリッドサーチでパラメータ探索するためにリスト形式で候補を入れてます。
複数の関数にまたがってパラメーターを指定することになるため、ハイフン二つの後にパラメーター名を指定することで、コントラクタに渡すようになってます。

estimators = [('pca', PCA()),
              ('svm', svm.SVC())]


parameters = {"pca__n_components" : range(2, 6),
              "svm__kernel" : ["linear", "poly", "rbf", "sigmoid"],
              'svm__C': np.logspace(0, 2, 10).tolist(),
              "svm__gamma": np.logspace(-3, 0, 10).tolist()}

pl = Pipeline(estimators)

最後にplを一つの分類器としてみなし、そのままGridSearchCVに突っ込みます。

clf = GridSearchCV(pl, parameters, n_jobs=-1)
clf.fit(X_train, y_train)
print 'Best_estimator = {0}'.format(clf.best_estimator_.get_params())

#予測
Predict = clf.predict(X_test)

n_samples = len(digits.data) 
expected = digits.target[n_samples * -4 / 10:] 
predicted = clf.predict(digits.data[n_samples * -4 / 10:]) 


print("Classification report for classifier %s:\n%s\n"
      % (clf, metrics.classification_report(expected, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted))

Best_estimator = {'svm__max_iter': -1, 'svm__coef0': 0.0, 'svm': SVC(C=1.6681005372, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape=None, degree=3, gamma=0.01, kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False), 'svm__random_state': None, 'pca__copy': True, 'svm__degree': 3, 'pca__n_components': 5, 'svm__gamma': 0.01, 'svm__shrinking': True, 'pca__whiten': False, 'svm__tol': 0.001, 'svm__verbose': False, 'svm__C': 1.6681005372000588, 'steps': [('pca', PCA(copy=True, n_components=5, whiten=False)), ('svm', SVC(C=1.6681005372, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape=None, degree=3, gamma=0.01, kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False))], 'svm__probability': False, 'svm__class_weight': None, 'pca': PCA(copy=True, n_components=5, whiten=False), 'svm__decision_function_shape': None, 'svm__kernel': 'rbf', 'svm__cache_size': 200}
Classification report for classifier GridSearchCV(cv=None, error_score='raise',
       estimator=Pipeline(steps=[('pca', PCA(copy=True, n_components=None, whiten=False)), ('svm', SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False))]),
       fit_params={}, iid=True, n_jobs=-1,
       param_grid={'pca__n_components': [2, 3, 4, 5], 'svm__C': [1.0, 1.6681005372000588, 2.7825594022071245, 4.641588833612778, 7.742636826811269, 12.91549665014884, 21.544346900318832, 35.93813663804626, 59.94842503189409, 100.0], 'svm__gamma': [0.001, 0.0021544346900318843, 0.004641588833612777, 0.01, 0.021544346900318832, 0.046415888336127774, 0.1, 0.21544346900318823, 0.46415888336127775, 1.0]},
       pre_dispatch='2*n_jobs', refit=True, scoring=None, verbose=0):
             precision    recall  f1-score   support

          0       1.00      0.96      0.98        71
          1       0.99      0.97      0.98        73
          2       0.94      0.93      0.94        71
          3       0.95      0.96      0.95        74
          4       0.96      0.96      0.96        74
          5       0.97      1.00      0.99        71
          6       0.99      1.00      0.99        74
          7       0.93      0.92      0.92        72
          8       0.84      0.85      0.85        68
          9       0.90      0.92      0.91        71

avg / total       0.95      0.95      0.95       719


Confusion matrix:
[[68  0  0  0  2  0  1  0  0  0]
 [ 0 71  0  0  0  0  0  1  0  1]
 [ 0  0 66  1  0  0  0  0  2  2]
 [ 0  0  0 71  0  0  0  2  0  1]
 [ 0  0  0  0 71  0  0  0  3  0]
 [ 0  0  0  0  0 71  0  0  0  0]
 [ 0  0  0  0  0  0 74  0  0  0]
 [ 0  1  0  0  0  0  0 66  5  0]
 [ 0  0  4  0  1  0  0  2 58  3]
 [ 0  0  0  3  0  2  0  0  1 65]]