データ分析ガチ勉強アドベントカレンダー 10日目。
- データを集め、前処理を行い、学習をする。
- どういう学習器が良いのかの評価基準
の勉強までできた。でも、データがあって、評価基準がわかっていても、どうやって評価すればいいかについてはまだあまり触れていない。
もうちょっと具体的に言うと、データと学習器があって、どういう風に教師データとテストデータを分ければいいのか。この方法について、実はまだ何も言っていない。
そこで登場するのが、sklearn.model_selection
いよいよ最後の仕上げ。良い学習器、良いパラメータの探り方について学ぶ
Validationとは
モデルを作ってデータを分析する際、データをtrain data, validation data, test dataに分ける。 最終的なテストをする前に、訓練データの中を分割してテストを回すことで、パラメータ調整を行うために用いられる。
sklearnでは、originalデータをtrainとtestに分けるところをsklearn.model_selection.test_train_split
で行い、Validationデータに分けるところにもsklearn.model_selection.cross_val_score
などが用意されている。
また、それにしたがって学習器のパタメータを変えながら評価していく仕組みも用意されていて、sklearn.model_selection.GridSearchCV
で実現される。(後述)
skleanのCross Validation
cross_val_score
sklearnで最も簡単にCross Validationをするには、cross_val_score
という関数を用いる。
`cross_val_score(clf, data, target, cv=5, scoring="accuracy")`
変数 | 役割 |
---|---|
clf | 学習器 |
data | データ |
target | ラベル |
cv | クロスバリデーションの回数 |
scoring | 評価する指標(参照:metrics) |
scoringには、下記の値を用いることができる。
['accuracy', 'adjusted_rand_score', 'average_precision', 'f1', 'f1_macro', 'f1_micro', 'f1_samples', 'f1_weighted', 'neg_log_loss', 'neg_mean_absolute_error', 'neg_mean_squared_error', 'neg_median_absolute_error', 'precision', 'precision_macro', 'precision_micro', 'precision_samples', 'precision_weighted', 'r2', 'recall', 'recall_macro', 'recall_micro', 'recall_samples', 'recall_weighted', 'roc_auc']
各評価値が何なのかを詳しく知りたい方は、Day9を参照
出力は、cv
の回数分の、評価値の配列となっている。例として、digitsデータをRandomForestで取り扱ってみる。
from sklearn.datasets import load_digits from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import cross_val_score digits = load_digits() clf = RandomForestClassifier() scoring = "f1_macro" scores = cross_val_score(clf, digits.data, digits.target, cv=5, scoring=scoring) print("{}:{:.3f}+/-{:.3f}".format(scoring, scores.mean(), scores.std()))
結果
f1_macro:0.901+/-0.031
pipline
cross validationを行う際に、sklearn.pipeline
を使うと、処理が簡潔に書ける。(参考)
例 : 正規化した後の効果をcross_validationしたい
# 通常 from sklearn import preprocessing X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, train_size=0.8) scaler = preprocessing.StandardScaler().fit(X_train) X_train_transformed = scaler.transform(X_train) clf = SVC(C=1).fit(X_train_transformed, y_train) X_test_transformed = scaler.transform(X_test) print(clf.score(X_test_transformed, y_test)) # pipeline from sklearn.pipeline import make_pipeline # 処理を流す順に関数を書いていく scoring = "f1_macro" clf = make_pipeline(preprocessing.StandardScaler(), SVC(kernel="linear",C=1)) scores = cross_val_score(clf, digits.data, digits.target, cv=5, scoring=scoring) print("{}:{:.3f}+/-{:.3f}".format(scoring, scores.mean(), scores.std()))
pipelineを使うと、複数処理を一括でCVにかけられるので、とてもよい。
cross_validate
関数
sklearn 0.19.1から、cross_validate
が用意された。
さっきまでのがcross_val_scores
関数。ややこしいが少し違う
- 評価に複数の指標を考慮できる
- テストスコアに加えて、学習の時のスコア、学習時間、テストの時間などを算出してくれる。
つまり、より強力なcross validationを行える。
from sklearn.model_selection import cross_validate from sklearn.metrics import recall_score from sklearn.svm import SVC scoring = ["f1_macro", "recall_macro"] clf = SVC(C=1) scores = cross_validate(clf, digits.data, digits.target, scoring=scoring, cv=5) for key,value in scores.items(): print("{}:{:.2f}+/-{:.2f}".format(key, value.mean(), value.std()))
結果はこちら
fit_time:0.51+/-0.01 score_time:0.12+/-0.00 test_f1_macro:0.50+/-0.04 train_f1_macro:1.00+/-0.00 test_recall_macro:0.45+/-0.04 train_recall_macro:1.00+/-0.00
Validation iterators
CrossValidationを行うときの、データセットの分け方にも、いろんなバリエーションがある。
sklearn.model_selection
内には、いろんなCVの分け方の方法が載っている。
- i.i.d data
- K-fold
- Repeated K-Fold
- Leave One Out (LOO)
- Leave P out (LPO)
- Shuffle & Split
- iterators with stratification based on class labels(サンプリングとか)
- Stratified k-fold
- Stratified Shuffle Split
- Grouped data i.i.dデータと基本おなじ
代表的なのが、K-Fold法とLeave One Out法。両者を図にするとこんな感じ
今回は、K-Fold法でのCrossValidationを実装してみる
import numpy as np from sklearn.model_selection import KFold from sklearn.datasets import load_digits from sklearn.metrics import accuracy_score # K-Fold交差検定 iterater = KFold(n_splits=5) results = [] for train_indexes, test_indexes in iterater.split(digits.data): # print(train_indexes, test_indexes) X = digits.data[train_indexes] y = digits.target[train_indexes] clf = RandomForestClassifier() clf.fit(X,y) pred_y = clf.predict(digits.data[test_indexes]) ac = accuracy_score(digits.target[test_indexes], pred_y) results.append(ac) results = np.array(results) print("KFold accuracy: {:.2f}+/-{:.2f}".format(results.mean(),results.std()))
出力
KFold accuracy: 0.90+/-0.04
パラメータを調整する
機械学習は複雑なので、モデルの持つパラメータをどのように調節すべきか難しい。
sklearnでは、下記の方法でパラメータ探索が行えるようになっている(参考 : Tuning the hyper-parameters of an estimator)
- グリッドサーチ : パラメータを総当り式で調べる
- ランダム選択 : ランダムにパラメータをサンプリングして試す
- モデルに合わせた賢いCV*1
他に、変数最適化の問題として、ある指標を評価関数にして解くというのもよさそう。Gaussian Process Optimizationなどがよさげ (参考)
今回は、グリッドサーチでの方法を載せる
パラメータ
SVCのパラメータである、C
, kernel
, その他変数について調整する。調整する
パラメータは下記のように、キーとリストで保持する。
param_grid = [ {'C': [1, 10, 100, 1000], 'kernel': ['linear']}, {'C': [1, 10, 100, 1000], 'kernel': ['rbf'], 'gamma': [0.001, 0.0001]}, {'C': [1, 10, 100, 1000], 'kernel': ['poly'], 'degree': [2, 3, 4], 'gamma': [0.001, 0.0001]}, {'C': [1, 10, 100, 1000], 'kernel': ['sigmoid'], 'gamma': [0.001, 0.0001]} ]
関数にはsklearn.model_selection.GridSearchCV
を用いる。引数は
実装
実装は下記の通り
from sklearn.model_selection import GridSearchCV import pandas as pd clf.get_params() svc = SVC() scoring = "f1_macro" param_grid = [ {'C': [1, 10, 100, 1000], 'kernel': ['linear']}, {'C': [1, 10, 100, 1000], 'kernel': ['rbf'], 'gamma': [0.001, 0.0001]}, {'C': [1, 10, 100, 1000], 'kernel': ['poly'], 'degree': [2, 3, 4], 'gamma': [0.001, 0.0001]}, {'C': [1, 10, 100, 1000], 'kernel': ['sigmoid'], 'gamma': [0.001, 0.0001]} ] clf = GridSearchCV(svc, param_grid,cv=4) clf.fit(digits.data, digits.target) df = pd.DataFrame(clf.cv_results_) df_scored = df.sort_values(by=["rank_test_score"])[["params","mean_test_score","std_test_score","mean_fit_time"]]
結果を見る
結果は、pandasのデータフレームに保管可能になっていて、簡単に好きな値でソートができる。今回はテストスコアの良い順にソートを行ってみた。(pandasの扱いが苦手な人はDay4をご覧ください)
こんな風に、どういうパラメータがどういう結果だったかが保存されているので、より良いパラメータを選ぶことができる。
まとめ
今日は学習器の調整に重要なCross Validationとパラメータサーチの方法について触れた。 実際の業務の場では、パラメータを調整する機会もとても多いので、知っておくと良い。また、少し述べたが、もう少し効率的なパラメータ調整方法についても勉強しておきたい。
機械学習の一連の流れがコレでざっと洗えたと思う。明日はscikit-learnのチートシートについてでも触れようかな。明日もお楽しみに!
*1:ドキュメントによればあるらしい...?