EnsekiTT Blog

EnsekiTTが書くブログです。

scikit-learnのcross_validateでCross Validationしてみた話

つまりなにしたの?

データ分析をやったら、Cross Validation(交差検定)などをやって分析手法が妥当か調べることが多い。
そこでscikit-learnのcross_validateを使ってCross Validationをやってみる
f:id:ensekitt:20181023131026j:plain

やりたいこと

  • Cross Validationとはなにか
  • データセットを用意する
  • 分割の仕方
  • cross_validateを使ったCross Validation

環境

 % python
Python 3.6.4 (default, Mar  2 2018, 00:45:54)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> import pandas
>>> import sklearn
>>> numpy.__version__
'1.15.3'
>>> pandas.__version__
'0.23.4'
>>> sklearn.__version__
'0.20.0'

Cross Validationとはなにか

ここでは一般的なCross Validationの一つであるk-Fold Cross Validationについて紹介する。
Cross Validationの目的は、主に解析の目標が予測であり、予測モデルが実際にどの程度正確に実行されるかを推定することにある。
これは、学習データへの過学習(オーバーフィッティング)を避けることである。
その方法はいくつかあるが、k-Fold Cross Validationでは使える学習データをk個に分割して、
k-1つのデータで学習、別の1つのデータで検証を行うことで実現する。
f:id:ensekitt:20181023131047j:plain
こんなイメージ。
事前にシャッフルしたり、各クラスごとに比率をあわせたりするテクニックが併せて使われる

データセットを用意する

よく使うWineのデータを使うことにしてみた。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import datasets

wine_data = datasets.load_wine()
wine_df = pd.DataFrame(wine_data.data, columns=wine_data.feature_names)
wine_df.head()

wine_df_tgt = pd.DataFrame(wine_data.target, columns=['target'])
wine_df_tgt.head()

分割の仕方

K-foldでの分割とShuffleSplitでの分割を試してみた。

from sklearn.model_selection import KFold
# 4つのデータセットをつくる。
kf = KFold(n_splits=4)
for learn,test in kf.split([i for i in range(16)]):
    print(learn, test)

[ 4  5  6  7  8  9 10 11 12 13 14 15] [0 1 2 3]
[ 0  1  2  3  8  9 10 11 12 13 14 15] [4 5 6 7]
[ 0  1  2  3  4  5  6  7 12 13 14 15] [ 8  9 10 11]
[ 0  1  2  3  4  5  6  7  8  9 10 11] [12 13 14 15]
from sklearn.model_selection import ShuffleSplit
# 4つのデータセットをテストサイズ20%でつくる。乱数を固定するためにrandom_state=0とした
ss = ShuffleSplit(n_splits=4, test_size=0.2, random_state=0)
for learn,test in ss.split([i for i in range(16)]):
    print(learn, test)
[13  4  2 14 10  7 15 11  3  0  5 12] [1 6 8 9]
[ 0  3  4 10 11  5 15  8 13  7  6  1] [ 2 14 12  9]
[10 14  6 11  9 12  1  8  3  2  0 15] [ 5 13  7  4]
[ 6 13  9 15 14 12  2  3  7  4 10  0] [11  8  1  5]

Wineのデータのようにラベルが綺麗に整列していると普通に分割した時に、
0と1のクラスで学習して2のクラスを予測するみたいな話になるのでシャッフルとかが必要になる。
f:id:ensekitt:20181023130331p:plain

cross_validateを使ったCross Validation

実際にcross_validateを使ってPrecisionとRecallを出してみることにする。

from sklearn.model_selection import cross_validate
from sklearn.metrics import recall_score

scoring = ['precision_macro', 'recall_macro']
clf = svm.SVC(kernel='linear', C=1, random_state=0)

# 分割の仕方
cv = ShuffleSplit(n_splits=4, test_size=0.2, random_state=0)

# Cross Validation
scores = cross_validate(clf, wine_df, np.array(wine_df_tgt['target']), scoring=scoring, cv=cv, return_train_score=False)

# 表示
print(sorted(scores.keys()))
print(scores['test_recall_macro'])
print(scores['test_precision_macro'])

#結果
['fit_time', 'score_time', 'test_precision_macro', 'test_recall_macro']
[1.         0.91666667 0.8962963  0.93333333]
[1.         0.96666667 0.8962963  0.91666667]

Fitにかかる時間やスコアを出す時間とともにテストのPrecision、Recallが出せている。

クリエイティブ・コモンズ・ライセンス
この 作品 は クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの下に提供されています。