sklearn.pipelineを試す
sklearn.pipelineとは
sklearn.pipeline
とは、前処理用のScaler(変換器)や機械学習モデルを一括で処理するためのオブジェクトを生成する。
これをおこなうことで、管理が容易になったり処理コード部分を簡潔に書くことができる。
実装
データはボストン住宅価格を使用する。
from sklearn.datasets import load_boston dsn = load_boston() X = pd.DataFrame(dsn.data, columns=dsn.feature_names) y = pd.DataFrame(dsn.target, columns=['target'])
Scaler
Scalerは以下の2つを用いる
StandardScaler
StandardScaler
はデータの標準化をおこなう。
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() scaler.fit_transform(X)
このとき、返り値はArray
となる。
自作Scaler
以下で自作のScalerを作成する。自作Scalerという概念の詳細はそのうち記事に書くので省略。
ここで作成するAddCrim2
は特徴量CRIM
の値を引数value
倍(初期値は2)したCRIM2
という特徴量を追加するシンプルな内容(例示用なのでこの処理自体に意味はないです)。
from sklearn.base import BaseEstimator, TransformerMixin class AddCrim2(BaseEstimator, TransformerMixin): def __init__(self,value=2): self.value = value def fit(self, X, y=None): return self def transform(self, X): # 直接の書き換えが起きないようにcopy _X = X.copy() # 新たな特徴量の作成 _X['CRIM2'] = _X['CRIM'] * self.value return _X tranceformer = AddCrim2(value=3) tranceformer.fit_transform(X)
pipeline
ここから本題のpipline
について。
処理としては、
- 前述の自作Scaler
AddCrim2
で変換をおこなう - 前述の
sklearn
のScalerStandardScaler
で変換をおこなう - 機械学習モデル
LinearRegression
で線形回帰をおこなう
といった流れとなる。
pipline
を使わないと以下のような処理となる。
from sklearn.linear_model import LinearRegression # AddCrim2でXを変換(特徴量追加) scaler1 = AddCrim2(value=4) X2 = scaler1.fit_transform(X) # StandardScalerでX2,yを変換 scaler2 = StandardScaler() X3 = scaler2.fit_transform(X2) y3 = scaler2.fit_transform(y) # LinearRegressionをX3, y3で学習 model = LinearRegression() model.fit(X3, y3) # LinearRegressionの学習結果をX3,yで評価 model.score(X3, y3) # => 0.7406426641094093
pipeline
を使用する場合、任意の処理名と処理クラスのセットのタプルを各処理の順番で渡す。ちなみに辞書ではないのは、明確に処理に順番があるため。
また、各処理の引数はset_params
関数を用いて、引数を 処理名__引数名
で指定することができる(_
は2つなので注意)。
pipeline
オブジェクトが作成できたらfit
でデータを渡す。
from sklearn.pipeline import Pipeline add_scale_ols_pipeline = Pipeline([ ('add', AddCrim2()), ('scaler', StandardScaler()), ('ols', LinearRegression()) ]) add_scale_ols_pipeline.set_params(add__value=4) # AddCrim2の引数valueを4に設定 add_scale_ols_pipeline.fit(X, y)
なお、pipeline
オブジェクトを作成した際に、各処理の引数がどう設定されているかが表示されるので引数指定の際に参考になる。
このpipeline
オブジェクトでの変換・学習結果の評価もおこなえる。
scale_ols_add_pipeline.score(X, y)
# =>0.7406426641094095
pipelineの注意点
各処理で設定する引数
AddCrim2
のコードは特徴量に関するコードなのでX
だけを処理する。しかし、引数としてy = None
とわざわざ設定している理由について。
先程のpipeline
コードではLinearRegression
用にfit
時にX, yを渡している。そのため、各fit
処理でX, yが引数として渡される。
そのため、AddCrim2
でのfit
でも共通してX, yともに渡す必要があるので、引数yへの処理が記載されていないと引数が多くてエラーとなる。そのため、yについての引数についても書きつつ、使用自体はしないのでy = None
と指示している。
# オリジナル class AddCrim2(BaseEstimator, TransformerMixin): def __init__(self,value=2): self.value = value def fit(self, X, y=None): return self def transform(self, X): # 直接の書き換えが起きないようにcopy _X = X.copy() # 新たな特徴量の作成 _X['CRIM2'] = _X['CRIM'] * self.value return _X # 引数1つ class AddCrim2_2(BaseEstimator, TransformerMixin): def __init__(self,value=2): self.value = value def fit(self, X): return self def transform(self, X): # yへの引数なし # 直接の書き換えが起きないようにcopy _X = X.copy() # 新たな特徴量の作成 _X['CRIM2'] = _X['CRIM'] * self.value return _X scale_ols_add_pipeline = Pipeline([ ('add', AddCrim2_2()), # 引数1つ ('scaler', StandardScaler()), ('ols', LinearRegression()) ]) scale_ols_add_pipeline.set_params(add__value=4) scale_ols_add_pipeline.fit(X,y) # AddCrim2_2, StandardScaler, LinearRegressionそれぞれのfitが走る。AddCrim2_2のfitはfit(X, y)として走るがfit(X)と定義されているので引数エラーとなる
各処理の順番
前述のように、指定された順番で処理が走る。つまり、前工程で処理したデータを次工程に渡す。このとき、前工程でどのような形で返ってくるか、次工程でどのような形でデータを受け取るかを意識しておく必要がある。
今回の例示コードのAddCrim2
は、前述のように データフレームを受け取って処理する 。また、StandardScaler
は受け取る形はデータフレームでもArrayでも良いが 処理結果はArrayで返ってくる。
そのため、処理順がAddCrim2
→ StandardScaler
は良いが、逆の StandardScaler
→ AddCrim2
ではエラーが起きる(仮にエラーが出なくても、標準化してから特徴量を掛け算して加えるという処理はわけがわからないので例示用として考えてください)。
scale_ols_add_pipeline = Pipeline([ ('scaler', StandardScaler()), # 順番入れ替える ('add', AddCrim2()), ('ols', LinearRegression()) ]) scale_ols_add_pipeline.set_params(add__value=4) scale_ols_add_pipeline.fit(X,y)
参考
pipeline
についてよくまとまっている、また、pipeline
の簡素版であるmake_pipeline
の紹介もおこなっている。