今回は scikit-learn の cross_validate() 関数で、組み込みでは用意されていないような評価指標を計算する方法について書く。
使った環境は次の通り。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.14.3 BuildVersion: 18D109 $ python -V Python 3.7.2
下準備
下準備として、事前に scikit-learn をインストールしておく。
$ pip install scikit-learn
cross_validate() 関数について
まずは cross_validate()
関数のおさらいから。
この関数は、その名の通り機械学習モデルの汎化性能を Cross Validation (交差検証) で評価するためにある。
次のサンプルコードでは、Breast Cancer データセットをランダムフォレストで学習させた場合の汎化性能を Stratified k-Fold CV で評価している。
cross_validate()
関数は、一度に複数の評価指標を計算できる点も特徴的。
以下では、組み込みで用意されている Accuracy, Precision, Recall, F1-Value について計算している。
#!/usr/bin/env python # -*- coding: utf-8 -*- from sklearn import datasets from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import StratifiedKFold from sklearn.model_selection import cross_validate def main(): # データセットを読み込む dataset = datasets.load_breast_cancer() X, y = dataset.data, dataset.target # モデルを用意する clf = RandomForestClassifier(n_estimators=100, random_state=42) # Stratified k-Fold で汎化性能を評価する skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) # 評価する指標 score_funcs = [ 'accuracy', 'precision', 'recall', 'f1', ] # Cross Validation で検証する scores = cross_validate(clf, X, y, cv=skf, scoring=score_funcs) # 得られた指標を出力する print('accuracy:', scores['test_accuracy'].mean()) print('precision:', scores['test_precision'].mean()) print('recall:', scores['test_recall'].mean()) print('f1:', scores['test_f1'].mean()) if __name__ == '__main__': main()
上記の実行結果は次の通り。
$ python cv.py accuracy: 0.9631088880338592 precision: 0.961883227291678 recall: 0.9805164319248826 f1: 0.9708395567654284
独自の評価指標を組み込む
続いて本題の独自の評価指標を組み込む方法について。 独自の評価指標を計算したいときは、真の値と推定した値を引数として受け取る関数を定義する。 そして、関数では引数を元に評価指標を計算して返す。
以下のサンプルコードでは、手始めに精度 (Accuracy) を計算する関数 accuracy_score
を定義している。
精度 (Accuracy) の計算は組み込みでも用意されているけど、まずはそれと差異が出ないことを比較できるようにするため。
ポイントとして、定義した関数は make_scorer()
関数でラップする必要がある。
#!/usr/bin/env python # -*- coding: utf-8 -*- from sklearn import datasets from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import StratifiedKFold from sklearn.model_selection import cross_validate from sklearn.metrics import make_scorer def accuracy_score(y_true, y_pred): """オリジナルの評価関数 (ただし単なる精度の計算)""" accuracy = sum(y_true == y_pred) / len(y_true) return accuracy def main(): dataset = datasets.load_breast_cancer() X, y = dataset.data, dataset.target clf = RandomForestClassifier(n_estimators=100, random_state=42) skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) score_funcs = { 'builtin_accuracy': 'accuracy', # オリジナルの評価関数を登録する 'custom_accuracy': make_scorer(accuracy_score), # make_scorer() でラップする } scores = cross_validate(clf, X, y, cv=skf, scoring=score_funcs) print('built-in accuracy:', scores['test_builtin_accuracy'].mean()) print('custom accuracy:', scores['test_custom_accuracy'].mean()) if __name__ == '__main__': main()
上記の実行結果は次の通り。 組み込みの精度 (Accuracy) 計算と同じ値が得られていることが分かる。
$ python acc.py built-in accuracy: 0.9631088880338592 custom accuracy: 0.9631088880338592
回帰問題でもやってみる
先ほどは分類問題だったので、念のため次は回帰問題でも確認しておこう。
以下のサンプルコードでは Boston データセットを ElasticNet 回帰で処理している。
独自の評価指標を計算する関数は rmse_score()
という関数を用意した。
これは、文字通り RMSE (Root Mean Square Error: 平均二乗誤差平方根) を計算する関数になっている。
#!/usr/bin/env python # -*- coding: utf-8 -*- import math from sklearn import datasets from sklearn.linear_model import ElasticNet from sklearn.model_selection import KFold from sklearn.model_selection import cross_validate from sklearn.metrics import mean_squared_error from sklearn.metrics import make_scorer def rmse_score(y_true, y_pred): """RMSE (Root Mean Square Error: 平均二乗誤差平方根) を計算する関数""" mse = mean_squared_error(y_true, y_pred) rmse = math.sqrt(mse) return rmse def main(): # Boston データセットを使った回帰問題 dataset = datasets.load_boston() X, y = dataset.data, dataset.target # ElasticNet 回帰 reg = ElasticNet(random_state=42) kf = KFold(n_splits=5, shuffle=True, random_state=42) score_funcs = { 'rmse': make_scorer(rmse_score), } scores = cross_validate(reg, X, y, cv=kf, scoring=score_funcs) mean_rmse = scores['test_rmse'].mean() print('RMSE:', mean_rmse) if __name__ == '__main__': main()
上記の実行結果は次の通り。
$ python rmse.py
RMSE: 5.274746876673534
ちゃんと計算できているようだ。
めでたしめでたし。
機械学習のための特徴量エンジニアリング ―その原理とPythonによる実践
- 作者: Alice Zheng,Amanda Casari,株式会社ホクソエム
- 出版社/メーカー: オライリージャパン
- 発売日: 2019/02/23
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログ (1件) を見る