はじめに
正則化回帰は割と定番のモデルなのですが、sklearnのAPIリファレンスをよく見ると、CVが末尾についたモデルがあることがわかります。
- Lasso→LassoCV
- Ridge→RidgeCV
- ElasticNet→ElasticNetCV
API Reference — scikit-learn 0.21.2 documentation
なんのこっちゃと思っていたのですが、このCVはCross Validation、要は交差検証です。正則化回帰では正則化パラメータを定める必要があるのですが、一概にどの値が良いとは言えないので、パラメータチューニングを行う必要があります。CV付きのモデルは内部的にチューニングを行ってくれるようです。
どうせチューニングするので、使えるものは使った方が良さそうにも思います。でも、GridSearchCVという見慣れたモデルもあるので、そちらとどちらが良いのか気になりますね。
試してみましょう。
実験
Ridgeで、3次多項式の回帰。係数は適当
import time import numpy as np from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import Ridge, RidgeCV from sklearn.model_selection import KFold, GridSearchCV from sklearn.pipeline import Pipeline from sklearn.metrics import r2_score def main(): np.random.seed(0) x = np.arange(-5, 5, 0.3) y = 7 + 5*x + 3*x**2 + 1*x**3 + np.random.normal(scale=3, size=x.shape) X = x.reshape(-1, 1) x_test = np.arange(-7, 7, 0.1) y_test = 7 + 5*x_test + 3*x_test**2 + 1*x_test**3 X_test = x_test.reshape(-1, 1) ridge_origin = Pipeline( [("pf", PolynomialFeatures(degree=3, include_bias=False)), ("r", Ridge())]) ridge_cv = Pipeline( [("pf", PolynomialFeatures(degree=3, include_bias=False)), ("r", RidgeCV(cv=KFold(n_splits=6, shuffle=True, random_state=0)))]) ridge_grid = GridSearchCV( Pipeline( [("pf", PolynomialFeatures(degree=3, include_bias=False)), ("r", Ridge())]), param_grid={"r__alpha":[0.1, 1.0, 10.0]}, cv=KFold(n_splits=6, shuffle=True, random_state=0)) for name, reg in [("origin", ridge_origin), ("CV", ridge_cv), ("GridSearchCV", ridge_grid)]: t1 = time.time() reg.fit(X, y) t2 = time.time() fit_time = t2 - t1 y_pred = reg.predict(X_test) score = r2_score(y_test, y_pred) print("{0:13} fit_time:{1:.6f} r^2:{2:.6f}".format( name, fit_time, score)) print(ridge_cv.named_steps.r.alpha_) print(ridge_grid.best_estimator_.named_steps.r.get_params()["alpha"]) if __name__ == "__main__": main()
結果。
origin fit_time:0.002750 r^2:0.999419 CV fit_time:0.031689 r^2:0.999850 GridSearchCV fit_time:0.053099 r^2:0.999850 10.0 10.0
RidgeCVでやろうとGridSearchCVでやろうと同じ結果に落ち着いているようですが、RdigeCVの方が微妙に速いです。
考察すると、やはりGridSearchCVだと汎用的なぶん余計なオーバーヘッドが多く、RdigeCVの方は高速に実行できるようです。あと、n_jobsを指定したら理不尽なほど遅くなったので、そういう方向で高速化も無理だと思います。
まとめ
こういうものがある、ということを知っておくと、パラメータチューニングが捗るかと思います。あと、LogisticRegressionCVもあったりするので、分類でも使えます。
なんでもかんでもGridSearchCV、というのではなく、使えるモデルを使い分けるという姿勢が大切だと思いました。