はじめに
scikit-learnはPythonの便利な機械学習ライブラリで、Numpy・Scipy・Matplotlibと一緒に気軽に使うことができます。
scikit-learnは、APIのデザインパターンを知ると飛躍的に使いやすくなります。
今回はscikit-learnの著者による論文をもとに、scikit-learnの魅力を解説します。
基本デザイン
scikit-learnのオブジェクトはAPIの一貫性を保つため、いくつかのパターンに従って設計されています。
このパターンを理解することでどのオブジェクトでも不自由なく使うことが出来ます。
Estimator
scikit-learnではEstimatorというインターフェースが基本となっています。
Estimatorは、データに基づき何らかのモデル(のパラメータ)を学習させます。
必ずfitというメソッドを持っていて、fitの引数にデータを流すことで学習を行います。
また、学習に必要なハイパーパラメータを(コンストラクタまたはset_paramsメソッドで)設定することができます。
ロジスティック回帰を行うLogisticRegressionというクラスもEstimatorの一つです。
from sklearn.linear_model import LogisticRegession
clf = LogisticRegression(penalty="l1") # ハイパーパラメータの設定
clf.fit(X_train, y_train) # 訓練データに基づきモデルを学習
Predictor
Estimatorの多くは同時にPredictorのインターフェスを導入しています。
Predictorはfitで学習したモデルをもとに予想(出力)を行います。
predictのメソッドにデータを引数として渡すと、予想が返されます。
また、scoreというメソッドを持っており、データセットとラベルを渡すことでモデルを評価できます。
例えば、LogisticRegressionはPredictorなので、predict、scoreのメソッドを問題なく使えます。
clf.predict(X_test) # テストデータについて予測
clf.score(X_test, y_test) # テストデータについての予想と実際の答えを比較
Transformer
Predictorの他に、Transformerというインターフェスを導入するクラスもあります。
名前にある通り、Transformerはデータを変形することができます。
機械学習モデルよりはデータ処理のAPIにおいて多用されます。
transformというメソッドを使って変形されたデータを返します。
また、fit_transformというメソッドを使うと、学習と変形を同時に行うことが出来るような設計です。
下の例では、データセットの標準化を行うStandardScalerによる変形を実装します。
StandardScalerの場合、複雑なモデルではなく各特微量の平均と分散を学習します。
from sklearn.preprocessing import StandardScaler
scaler = StandScaler()
X_train = scaler.fit_transform(X_train) # 訓練データを学習・変形
X_test = scaler.transform(X_test) # テストデータは学習せず変形(訓練データの平均・分散を用いる)
また、PredictorとTransformerのインターフェスは同時に導入することができます。
パラメータ・ハイパーパラメータの取得
自分が設定したハイパーパラメータ、学習されたパラメータはオブジェクトの中に保存されています。(学習されたパラメータの名前はアンダーバーで終わります)
パラメータ・ハイパーパラメータのアクセス方法については、各オブジェクトのドキュメントで「Attributes」を参照してください。
例:StandardScalerが学習した平均、分散を取得する
# 前から続く
mean = scaler.mean_
variance = scaler.var_
よって、どのEstimatorでも
- インスタンスを作りハイパーパラメータを設定する
-
fitで学習する -
predict、score、transformなどで目的を達成する、学習されたパラメータを確認する
という手順に従うことで、簡単にワークフローを構築することができます。
データ全処理からモデル学習・評価までの実装が全てEstimatorを使って行えます。
応用デザイン
Estimatorの合成
全てのEstimatorが同じメソッドを持っているため、複数のEstimatorを簡単に合成することができます。
並列処理の場合Pipeline、並行処理の場合FeatureUnionを使って合成します。
例えば、データを標準化しロジスティック回帰を行いたい場合、パイプラインを使うことできれいに処理を実装できます。
from sklearn.pipeline import Pipeline
pipe = Pipeline([
{'std_scaler', StandardScaler()},
{'log_reg', LogisticRegression()} # transformerの変形したデータを受け取る
])
pipe.fit(X_train, y_train)
pipe.score(X_test, y_test)
Cross ValidationもEstimator
scikit-learnではGridSearchCVやRandomSearchCVなどといったクラスを使ってハイパーパラメータの検証を行うことができます。
これらも、Estimatorのインターフェスを導入しており、fitを使って学習を行います。
例:ロジスティック回帰に最適なハイパーパラメータをGrid Searchを使って求める
from sklearn.model_selection import GridSearchCV
clf = GridSearchCV(
estimator=LogisticRegression(),
param_grid={
'C' = [1, 3, 10, 30, 100]
}
)
clf.fit(X_train, y_train) # param_gridにあるハイパーパラメータを一つずつ適用して複数のモデルを学習させる
best_clf = clf.best_estimator_ # 最適なEstimatorをゲット!
自前のEstimatorを作る
fitなど、インターフェースに定義されたメソッドを持つクラスを作ることで、簡単にパイプラインや検証に使うことができます。
Estimatorを作る場合、BaseEstimatorを継承し、さらにTransformerなどを作る場合は同時に適当なMixinを継承します。
Transformerの例:
from sklearn.base import BaseEstimator, TransformerMixin
class MyTransformer(BaseEstimator, TransformerMixin):
def __init__(self, param_1, param_2):
# ハイパーパラメータの処理
self.param_1 = param_1
# ...
def fit(self, X, y=None):
# 処理
return self
def transform(self, X, y=None):
# Numpy行列の処理
# X = ...
return X
# fit_transformは自動的にTransformerMixinが実装
transformer = MyTransformer()
X_transformed = transformer.fit_transform(X_train)
結論
scikit-learnには色々な機械学習手法を実装したオブジェクトが用意されていますが、内容が分からなくてもEstimator、Predictor、Transformerのデザインパターンを理解していれば一通り使えてしまいます。
scikit-learnのAPIは一貫性が高いところが魅力的で、簡単に機械学習を進めることができます。