scikit-learn準拠の変換器,推定器を自作する

こちらの記事、でscikit-learnのpipelineモジュールを用いた機械学習パイプラインの作成を紹介した。

pipelineモジュールに組み込めるのは、fit, transformメソッドなど持つ、sklean準拠の変換器(transformer)や推定器(Estimator)である。
そのため、独自の処理や予測手法を用いる場合には、これらを自作する必要がある。

本記事では変換器(transformer)や推定器(Estimator)の自作方法についてまとめた。

コード

Transformerを実装する手順参考

  • BaseEstimatorを継承する。(set_paramsget_paramsを使用できるようにするため)
  • TransformerMixinを継承する。(fit_transformを使用できるようにするため)
  • fitを実装する。
  • transformを実装する。

Estimatorを実装する手順参考

  • BaseEstimatorを継承する。(set_paramsget_paramsを使用できるようにするため)
  • 回帰ならRegressorMixin・分類ならClassifierMixin、もしくはTransformerMixinを継承する。(fit_transformを使用できるようにするため。RegressorMixin,ClassifierMixinを継承しているとscoreメソッドが使える様になるとのこと)
  • fitを実装する。
  • predictを実装する。
### データの準備
import pandas as pd
import numpy as np
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split

# サンプルデータの用意
boston = load_boston()
df_X = pd.DataFrame(data=boston.data, columns=boston.feature_names)
df_y =  pd.Series(boston.target, name="MEDV")

train_X, test_X, train_y, test_y = train_test_split(df_X,df_y)
# 検証用に欠損値を作る
train_X.iloc[5,5:8] = np.nan

print("欠損値のある列",train_X.columns[train_X.isnull().any()])
"""output
欠損値のある列 Index(['RM', 'AGE', 'DIS'], dtype='object')
"""

Transformerの自作

欠損値がある列を削除するメソッドを実装してみる。
(pandasのdropnaを使えば一発で削除できるが、練習のため)

from sklearn.base import BaseEstimator, TransformerMixin

class DeleteNullFeatures(BaseEstimator, TransformerMixin):
    def __init__(self,delete_col=None):
        self.delete_col = delete_col

    def fit(self, X, y=None):
        # 欠損値のある列の検出
        self.delete_col = df_X.columns[df_X.isnull().any()]
        return self

    def transform(self, X):
        if self.delete_col is None:
            return X
        else:
            return X.drop(self.delete_col,axis=1)
preprocess = DeleteNullFeatures()
train_X_transformed = preprocess.fit_transform(train_X)
test_X_transformed = preprocess.transform(test_X)

print(train_X_transformed.columns)
print(test_X_transformed.columns)
"""output
Index(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX',
       'PTRATIO', 'B', 'LSTAT'],
      dtype='object')
Index(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX',
       'PTRATIO', 'B', 'LSTAT'],
      dtype='object')
"""

Estimatorの自作

yの平均値を予測値として返すEstimatorを実装してみる

from sklearn.base import BaseEstimator,RegressorMixin
class MeanEstimator(BaseEstimator,RegressorMixin):
    def __init__(self):
        self.y_mean = None

    def fit(self, X, y=None):
        self.y_mean = y.mean()
        return self

    def predict(self, X):
        return np.full(X.shape[0],self.y_mean)
mean_model = MeanEstimator()

mean_model.fit(train_X,train_y)

train_y_pred = mean_model.predict(train_X)
test_y_pred = mean_model.predict(test_X)

print(train_y_pred[:10])
print(test_y_pred[:10])
"""output
[22.25567282 22.25567282 22.25567282 22.25567282 22.25567282 22.25567282
 22.25567282 22.25567282 22.25567282 22.25567282]
[22.25567282 22.25567282 22.25567282 22.25567282 22.25567282 22.25567282
 22.25567282 22.25567282 22.25567282 22.25567282]
"""

(おまけ)PipeLineへの組み込み

from sklearn.pipeline import Pipeline

pipeline = Pipeline(steps=[
                        ('standard_scaler', DeleteNullFeatures()),
                        ('regressor', MeanEstimator())
                        ])

pipeline.fit(train_X,train_y)

train_y_pred = pipeline.predict(train_X)
test_y_pred = pipeline.predict(test_X)

print(train_y_pred[:10])
print(test_y_pred[:10])
"""output
[22.25567282 22.25567282 22.25567282 22.25567282 22.25567282 22.25567282
 22.25567282 22.25567282 22.25567282 22.25567282]
[22.25567282 22.25567282 22.25567282 22.25567282 22.25567282 22.25567282
 22.25567282 22.25567282 22.25567282 22.25567282]
"""

参考

参考HP

関連書籍






関連Udemy