ナード戦隊データマン

データサイエンスを用いて悪と戦うぞ

パイプラインを用いて一連の処理を一つのEstimatorにする

特徴量選択、前処理、パラメータ設定、機械学習アルゴリズムの選択…という一連のプロセスを一つのEstimatorとして定義できると、API化が容易になったり、あるいはGridSearchによる自動化ができるようになります。ここでは、PiplineオブジェクトとGridSearchCVを組合せて自動化します。

とりあえずコード見ればわかる

from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.pipeline import Pipeline, make_pipeline
from sklearn.feature_selection import SelectFromModel

cancer = load_breast_cancer()

pipe = Pipeline([('feature_selection', None), ('preprocessing', None), ('classifier', None)])

param_grid =[
    {
        'classifier':[SVC()], 
        'preprocessing':[StandardScaler(), None],
        'feature_selection': [SelectFromModel(RandomForestClassifier(n_estimators=100, random_state=42)), None],
        'classifier__gamma':[0.001, 0.01, 0.1, 1],
        'classifier__C':[0.001, 0.01, 0.1, 1, 10]
    },
    {
        'classifier':[RandomForestClassifier()], 
        'preprocessing': [None], 
        'feature_selection':[None],
        'classifier__max_features': [1, 2, 3]
    }
]


grid = GridSearchCV(pipe, param_grid, cv=5, scoring='roc_auc')

X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target)

grid.fit(X_train, y_train)

print("best params: {}".format(grid.best_params_))
print("best score: {}".format(grid.best_score_))
print("test score: {}".format(grid.score(X_test, y_test)))
best params: {'classifier': SVC(C=10, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma=0.01, kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False), 'classifier__C': 10, 'classifier__gamma': 0.01, 'feature_selection': None, 'preprocessing': StandardScaler(copy=True, with_mean=True, with_std=True)}
best score: 0.995319389010372
test score: 0.9982631350412506

説明

GridSearchでは、指定したパラメータの組合せの交差検証の結果をブルートフォースでチェックしますが、Pipelineを用いると、以下の点が付け加えられます。

上記のコードの出力結果は、精度の最も良いパラメータの組合せです。SVC正則化パラメータC=10にし、rbf半径gammaを0.01にして、特徴量選択を行わず、StandardScalerによるスケール化を行ったモデルが最も精度を発揮します。

IBM SPSSでは似たような概念として"ストリーム"というものがあります。sklearnのpipelineは、ストリームのようなものとして考えることができます。つまり、一連の処理を結合し、一つのfitで呼び出すということです。

このストリームは、transformとfitをインターフェースとして定義することにより実現しています。あるオブジェクトがデータに対してfitを呼び出し、次のオブジェクトに対してtransformで変換されたデータを入力してfitを呼び出します。これを繰り返しているのです。

  1. T1.fit(X, y)
  2. T2.fit(T1.transform(X), y)
  3. Classifier.fit(T2.transform(T1.transform(X)), y)

注意点

注意すべきなのは、処理速度です。GridSearchはパラメータの組合せを試行しますが、パラメータの種類と数によって爆発的に増加します。

パラメータの種類がm, 各パラメータの数がnだとすると、組合せの数はnmです。m=5, n=2とすると、試行回数は32回となります。さらに、内部ではk-fold交差検証をしているので、検証回数はknmとなります。しかも、データが増えるほど訓練時間も予測時間も増えていきます。

したがって、現実的なパラメータを少数選択して使ったほうがよいでしょう。

参考

1.sklearn.pipeline.Pipeline — scikit-learn 0.19.0 documentation 2.