半歩ずつ進める機械学習　～scikit-learnボストン住宅価格編～⑤

##前回まで
[前々回][1]にscikit-learnの`LinearRegression`を使って
ボストン住宅価格を予測するモデルを作り、交差検証を行いました
しかし学習・テストデータの分割方法が原因（仮定）で交差検証結果のバラつきが大きい事を受けて
[前回の投稿][2]で、複数のデータ分割方法について学びました
今回は、前回学んだ事を踏まえて、モデルの検証と精度アップを試みます。

##まず試してみよう
前回学んだデータ分割方法は以下の三種でした

+ **KFold**
+ **Stratified KFold**
+ **Group KFold**

下の二つは分類問題に使う物らしいので
現在取り組んでいるボストン住宅価格の予想には**KFold(Shuffle = True)**が適切かと思います

まずはバラつきが大きかった交差検証のコード

```python:boston.py
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression

lr = LinearRegression()
print(cross_val_score(lr,env_data,price_data,cv = 5)
#[ 0.63861069  0.71334432  0.58645134  0.07842495 -0.26312455]
```

`cross_val_score`は引数`cv`に整数を指定すれば、指定された数に`cross_val_score`の中で分割してくれます。
`cv`にはインデックスを返す**ジェネレータ**を渡す事も可能で、その場合は渡されたジェネレータを使ってデータ分割を行うようです。
**[cross_val_scoreのリファレンス][3]**

ではランダムにインデックスを抽出してくれるジェネレータを作り、`cross_val_score`に渡してみます

```python:boston.py
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.linear_model import LinearRegression

lr = LinearRegression()
kf = KFold(n_splits = 5,shuffle = True,random_state = 1)
splitter = kf.split(env_data,price_data)#ジェネレータ生成
print(cross_val_score(lr,env_data,price_data,cv = splitter))
#[0.76348092 0.64664899 0.79214918 0.65064254 0.73524062]

```

`KFold(random_state = 1)`は乱数のシードです、毎回抜き出すデータが変わってもいい場合は指定はいりません。

何も考えずにデータを分割した場合と比べて結果は一目瞭然ですね

KFold(shuffle = False)
**[ 0.63861069  0.71334432  0.58645134  0.07842495 -0.26312455]**
KFold(shuffle = True)
**[0.76348092 0.64664899 0.79214918 0.65064254 0.73524062]**

パッと見るとモデルが良くなったように見えますが、**評価方法が変わっただけでモデルの性能が変わったワケではありません。**

##cross_validate
ここまで交差検証には`cross_val_score`を使用してきましたが
交差検証を行うのに`cross_validate`というメソッドもあります。
このメソッドを使えば目的変数と説明変数からモデルを作る為にかかった時間が出せたり
複数の評価指標を一度に計算出来たりと、`cross_val_score`と比較して便利な部分があります。
使い方は`cross_val_score`と殆ど同じです。

```python:valid.py
from sklearn.model_selection import cross_val_score, cross_validate
from sklearn.model_selection import KFold
from sklearn.linear_model import LinearRegression

lr = LinearRegression()
kf = KFold(n_splits = 5,shuffle = True,random_state = 1)

score = cross_val_score(lr,env_data,price_data,cv = kf,scoring = "neg_mean_squared_error")
scores = cross_validate(lr,env_data,price_data,cv = kf,scoring = {"neg_mean_squared_error","neg_mean_absolute_error"})

print(score)
print(scores)
"""
[-23.37456303 -28.62770207 -15.16049987 -27.21667391 -23.37278076]

{'fit_time': array([0.05200005, 0.00099993, 0.        , 0.00099993, 0.00300026]), 
'score_time': array([0.        , 0.        , 0.00099993, 0.00099993, 0.        ]), 
'test_neg_mean_absolute_error': array([-3.74913847, -3.30699838, -3.02845012, -3.56953509, -3.29932279]), 
'train_neg_mean_absolute_error': array([-3.19838165, -3.23054675, -3.42791942, -3.22939478, -3.26295039]), 
'test_neg_mean_squared_error': array([-23.37456303, -28.62770207, -15.16049987, -27.21667391,-23.37278076]), 
'train_neg_mean_squared_error': array([-21.86800809, -20.50443823, -23.79796506,-20.81849064,-21.61049124])}
"""
```
`cross_validate`で複数の評価指標による評価を一度に行う場合、scoring引数に**dict(辞書型）**を渡します。
一度に多角的な評価が可能なので、とても便利です

##引数 "scoring" について
ここまで`cross_valid_score`を使う時には引数として

+ 説明変数
+ 目的変数
+ 分割数 or ジェネレータ

上記のみを渡してきましたが、`cross_val_score`と`cross_validate`には共に
`scoring`という引数が存在します。
これは、交差検証により、どんな指標を求めるかを指定するもので
指定無しの場合はデフォルトで**推定器（Estimator)**の持つ評価指標を採用します
今回のケースでは推定器は`LinearRegression`なので、**決定係数**が採用されます。

##その他の指標について
scikit-learnに標準で入っている評価指標は、以下の通りです。

|Scoring|Function|Comment|
|:--|:--|:--|
|Classification|	 	 
|‘accuracy’|metrics.accuracy_score||	 
|‘balanced_accuracy’|metrics.balanced_accuracy_score|for binary targets|
|‘average_precision’|metrics.average_precision_score|
|‘brier_score_loss’|metrics.brier_score_loss|	 
|‘f1’|metrics.f1_score|for binary targets|
|‘f1_micro’|metrics.f1_score|micro-averaged|
|‘f1_macro’|metrics.f1_score|macro-averaged|
|‘f1_weighted’|metrics.f1_score|weighted average|
|‘f1_samples’|metrics.f1_score|by multilabel sample|
|‘neg_log_loss’|metrics.log_loss|requires predict_proba support|
|‘precision’ etc.|metrics.precision_score	suffixes apply as with ‘f1’|
|‘recall’ etc.|metrics.recall_score|suffixes apply as with ‘f1’|
|‘roc_auc’|metrics.roc_auc_score|	 
|Clustering|	 	 
|‘adjusted_mutual_info_score’|metrics.adjusted_mutual_info_score|	 
|‘adjusted_rand_score’|metrics.adjusted_rand_score|	 
|‘completeness_score’|metrics.completeness_score|	 
|‘fowlkes_mallows_score’|metrics.fowlkes_mallows_score|	 
|‘homogeneity_score’|metrics.homogeneity_score|	 
|‘mutual_info_score’|metrics.mutual_info_score|	 
|‘normalized_mutual_info_score’|metrics.normalized_mutual_info_score|	 
|‘v_measure_score’|metrics.v_measure_score|	 
|Regression|	 	 
|‘explained_variance’|metrics.explained_variance_score|	 
|‘neg_mean_absolute_error’|metrics.mean_absolute_error|	 
|‘neg_mean_squared_error’|metrics.mean_squared_error|	 
|‘neg_mean_squared_log_error’|metrics.mean_squared_log_error|	 
|‘neg_median_absolute_error’|metrics.median_absolute_error|	 
|‘r2’|metrics.r2_score|
リファレンスは[こちら][4]
##次回へ
次回は上記スコアリング指標の内容を勉強するか、住宅価格予測モデルの精度向上のどちらかをやりたいと思います。

##お願い
機械学習の初心者が、学んだ知識の確認と備忘用に投稿しています。
間違っている部分や、何かお気づきの事がありましたらご指摘頂けますと幸いです
あと、独学者なので「私も今勉強中なんです！」みたいな人がいればコメント貰えると喜びます。

[1]:https://qiita.com/Mukomiz/items/8bbd6ababa48b79fdd60
[2]:https://qiita.com/Mukomiz/items/1156ea693dc4f077ca79
[3]:https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_score.html
[4]:https://scikit-learn.org/stable/modules/model_evaluation.html#scoring-parameter