派遣で働くエンジニアのスキルアップを応援するサイト

PRODUCED BY RECRUIT

【第9話】ロジスティック回帰で、翌月の購買実績を予測してみよう!クロスバリデーション編【漫画】未経験なのに、機械学習の仕事始めました

f:id:itstaffing:20211129120554j:plain
f:id:itstaffing:20211129120605j:plain
f:id:itstaffing:20211129120612j:plain

クロスバリデーションとは?

前回は予測モデルを構築しました。しかし、モデルを作るのに利用したデータと、精度を計測するデータが同じになってしまうため、「予測がどのくらい正確にできているか」がわからないのが問題でした。

本番における精度がどの程度であるか、手元にあるデータだけで確認する方法を考えないといけません。

そこで役立つのが、クロスバリデーションという方法です!

・クロスバリデーション 3セットに分割した例

まず、全部で10レコードのデータを3分割に分けるとします。

*何セットに分割するかはデータ量や予測モデルの学習に必要な時間によって異なりますが、3、5、10分割のいずれかであることが多いです。ここでは3セットに分割したとして説明をします。

それぞれのグループは3レコード、3レコード、4レコードとなります。これらのセットにグループ1、グループ2,グループ3と名前をつけます。

次に、これらのグループの組み合わせを変えながら、モデルの学習と精度の計測をします。

・学習に使うデータを、学習データ(または訓練データ)
・計測に使うデータを、検証データ

と呼びます。
グループの組み合わせとしては、次のようになります。

f:id:itstaffing:20211129120619j:plain

このように、グループの組み合わせを3通り作成します。つまり、学習と精度計測を3回行います。3回の精度計測の平均を、予測モデルが持つ予測の精度として扱います。

組み合わせを変えながら学習と検証を実施できるので、全てのデータに対して学習と検証をすることができ、無駄なくデータを使うことができます。

f:id:itstaffing:20210113102524j:plain
なるほど!もともと1つだったデータを分けて、入れ替えて使うのか。こうすれば、問題だった「学習データ=検証データ」の状態にはならない。現実世界のデータで試しているような、本番っぽい状態を作れるってことね!

10セットのグループに分けた場合は、学習を10回することになるので、予測精度の計測に時間がかかってしまいますが、学習データに使えるデータ量が増えるという利点があります。

また、それぞれの予測精度のバラツキを確認するとモデルの安定性を知ることができます。極端に精度が異なる場合は、データの分割数を増やしたり、異なるモデルで予測したりする必要があるでしょう。

scikit-learnでクロスバリデーションを実装してみよう

scikit-learnでは以下のようにしてクロスバリデーションを実装できます。

特徴量Xと教師ラベルyを用意しました。この記事の実行を再現するために必要なサンプルコードは、こちらで確認できます。

```
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
model = LogisticRegression()
parameters = {} # デフォルトパラメータを利用
clf = GridSearchCV(model, parameters, cv=3, scoring="accuracy")
clf.fit(X, y)
```

結果の確認は`clf.cv_results_`で表示されて、以下のようになります。

```
{'mean_fit_time': array([0.01321475]),
'std_fit_time': array([0.00103848]),
'mean_score_time': array([0.0019633]),
'std_score_time': array([0.00012035]),
'params': [{}],
'split0_test_score': array([0.71849057]),
'split1_test_score': array([0.70415094]),
'split2_test_score': array([0.70015106]),
'mean_test_score': array([0.70759752]),
'std_test_score': array([0.00787374]),
'rank_test_score': array([1], dtype=int32)}
```

情報量が多いので最初は戸惑いますが、最初にみるべきはmean_test_scoreの値です。これが全組み合わせにおける予測精度の平均値になります。

ここでは0.707...となっています。十分な精度が出ている場合は、split0_test_score、 split1_test_score、split2_test_scoreの結果を見ます。

これらの数値が平均値を求める元になっています。ここでは大きなバラツキは無いようです。モデルやデータに問題がある場合はこれらの数値が大きくなります。

クロスバリデーションを実施する際に、予測モデルが持つパラメータを変えて比較することもできます。上記との違いはparametersのみです。

```
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
model = LogisticRegression()
parameters = {"penalty": ["l1", "l2"], "solver":["liblinear"]}
clf = GridSearchCV(model, parameters, cv=3, scoring="accuracy")
clf.fit(X, y)
```

クロスバリデーションの結果は、以下のようになります。

```
{'mean_fit_time': array([0.00588147, 0.00651034]),
'std_fit_time': array([0.00076274, 0.00138428]),
'mean_score_time': array([0.00222834, 0.00160066]),
'std_score_time': array([0.00013087, 0.00026224]),
'param_penalty': masked_array(data=['l1', 'l2'],
     mask=[False, False],
   fill_value='?',
     dtype=object),
'param_solver': masked_array(data=['liblinear', 'liblinear'],
     mask=[False, False],
   fill_value='?',
     dtype=object),
'params': [{'penalty': 'l1', 'solver': 'liblinear'},
{'penalty': 'l2', 'solver': 'liblinear'}],
'split0_test_score': array([0.73509434, 0.71698113]),
'split1_test_score': array([0.70339623, 0.70415094]),
'split2_test_score': array([0.72432024, 0.70015106]),
'mean_test_score': array([0.72093694, 0.70709438]),
'std_test_score': array([0.01315998, 0.00717917]),
'rank_test_score': array([1, 2], dtype=int32)}
```

先程との結果の違いはmean_test_scoreなどの値が2つになっていることです。パラメータの組み合わせごとにクロスバリデーションの結果が保存されています。また、最も精度の高いパラメータでのモデルはclf.predictで呼び出せます。

f:id:itstaffing:20210113102532j:plain
今回は、モデルの精度を検証するための方法「クロスバリデーション」を紹介しました。
クロスバリデーションは、複数のモデルを作ったうち、どれが最も優れているかを比較するときにも役立ちますよ
f:id:itstaffing:20210113102524j:plain
手持ちのデータが少ないときに、ありがたい方法ですね。モデルの精度はこれで検証できたから、もう完璧ですね!?
f:id:itstaffing:20210113102532j:plain
はい、精度についてはクロスバリデーションで検証できました。しかし、実はもうひとつ考えるべきポイントがあるんです。
f:id:itstaffing:20210113102524j:plain
あれ、まだ足りないんですか!?
f:id:itstaffing:20210113102532j:plain
予測結果をどちらに属するかの閾値(しきいち)です。
f:id:itstaffing:20210113102524j:plain
し、しきいち・・・
f:id:itstaffing:20210113102532j:plain
これまでは「予測結果が0.5以上か未満か」で区別していました。この閾値を最適なものに調整することで、モデルの実用性を増すことができます。次回は、調整における考え方を紹介します。
f:id:itstaffing:20210113102524j:plain
ヒョエ~!私は「ネットショッピングの利用者が翌月に購入するか否か」を予測したいだけなのに……考えることがいっぱいだ~!

第1話 機械学習の仕事内容って?実はコードを書くだけじゃない!
第2話 人工知能、機械学習、ディープラーニングの違いとは?
第3話 機械学習の活用事例!建設機械や回転寿司屋でも活用されている!?
第4話 機械学習したいのにデータがない!?
第5話 集計と可視化:pandasでデータの加工をしてみよう
第6話 続!集計と可視化:Plotlyでデータをグラフ化して傾向をとらえよう
第7話 ロジスティック回帰ってなあに?紹介編
第8話 ロジスティック回帰で、翌月の購買実績を予測してみよう!実践編

【筆者】
早川 敦士さん
株式会社FORCASの分析チームにてリーダーを務める傍らで、株式会社ホクソエムで執行役員として従事。新卒でリクルートコミュニケーションズに入社しWeb広告やマーケティングオートメーションなどのB2Cマーケティングを経験し、FORCASではB2Bマーケティングプラットフォームのデータ分析および開発を担当している。大学在学中に『データサイエンティスト養成読本』(技術評論社刊)を共著にて執筆。その後も『機械学習のための特徴量エンジニアリング』(オライリー・ジャパン刊)や『Pythonによるはじめての機械学習プログラミング』(技術評論社刊)などで執筆活動を続けている。国内最大級のR言語コミュニティであるJapan.Rを主催。Youtubeチャンネル『データサイエンティストgepuro』で動画を投稿。
・Twitterアカウント

湊川 あいさん
フリーランスのWebデザイナー・漫画家・イラストレーター。マンガと図解で、技術をわかりやすく伝えることが好き。 著書『わかばちゃんと学ぶ Git使い方入門』『わかばちゃんと学ぶ Googleアナリティクス』『わかばちゃんと学ぶ Webサイト制作の基本』『運用ちゃんと学ぶ システム運用の基本』『わかばちゃんと学ぶ サーバー監視』が発売中のほか、マンガでわかるGit・マンガでわかるDocker・マンガでわかるRuby・マンガでわかるScrapbox・マンガでわかるLINE Clova開発・マンガでわかる衛星データ活用といった分野横断的なコンテンツを展開している。
・Amazon著者ページ
・Twitterアカウント

わかばちゃんが登場する書籍いろいろ

イメージ イメージ
イメージ イメージ

わかばちゃんと学ぶシリーズ(Amazonページ)