はじめに
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は一貫性が高いところが魅力的で、簡単に機械学習を進めることができます。