【Python】競馬予想で機械学習を使ったら回収率が100%を超えた話

Python

新井紀子さんの書かれた「AI vs.教科書が読めない子どもたち」という本を読みました。

  • AIとは何か
  • AIの得意なこと、苦手なことは何か
  • AIはどのようにできているのか

これらがわかりやすく書いてあり、AIに興味を持っただけでなく、AIの仕組みが知りたくて、AI開発に向いていると言われるPythonを勉強することにしました。

そしてAIの一部である機械学習にたどり着いたわけです。

「なにか自分でテーマを決めて機械学習してみよう」

そう思ったとき、競馬好きな友人のことを思い出したので機械学習のテーマを競馬予想にしました。

友人が競馬予想ツールをExcelのVBAで自作する!と言っていたので、競馬のことはよくわかりませんが、とにかく負けないよう頑張りました笑

この記事を読むメリットは次の通りです。

  • 機械学習についてざっくりと理解できる
  • 機械学習の流れをイメージできる
  • 競馬を機械学習したときにどのくらい当たるのかわかる

最後まで読んでもらえると嬉しいです。

機械学習とは?

「機械学習のことがよくわからない」という人のために、まずカンタンに機械学習について触れたいと思います。もし機械学習のことを知っている人は飛ばしてください。

機械学習とは、人間が経験を通して自然に学習することをコンピュータにさせようとするデータ解析手法のことです。

たとえば赤ちゃんがはじめて馬(競馬だけに)を見たとき、いきなり「知ってるよ!これは馬でしょ?」と言うわけないですよね?言う赤ちゃんがいたら絶対バズってます。

お父さんやお母さんから「これがお馬さんだよ」と何度も教えてもらい、何度も見ていくうちに「この見た目の生き物は馬というのか」と学んでいくんです。

同じように「コンピュータに学んでもらおう」とする取り組みのことを機械学習というわけですね。まさに「機械」に「学習」させます。

機械学習はおおきく次の3つにわけられます。

  • 教師あり学習
  • 教師なし学習
  • 強化学習

教師あり学習は、正解をあたえて学習していきます。

たくさんの馬の写真を使って「これは馬なんだよ」と教えていくものです。

もちろん馬以外の写真も見せます。そのときは「これは馬じゃないよ」という正解を教えてあげればいいでしょう。

ほかの例としては、ニンジン(馬だけに)の写真といっしょにニンジン1本の値段を正解として与えることもできます。

つまり、学習したあと、ニンジンの写真を見せれば「このニンジンは1本40円だ」と予想できるわけです。

教師あり学習には「馬か、馬じゃないか」のようにデータをラベルづけするもの(分類)と「このニンジンは何円か」と数値を予測するもの(回帰)があります。

教師なし学習は、正解をあたえない学習です。

たとえば、馬の写真を見せるとき「これは馬だよ」という正解をあたえずに学習させると、「目がクリッとしてるな」とか「毛の色が鮮やかだな」とか機械が勝手に特徴を見つけてグループわけ(クラスタリング)してくれます。

強化学習は、試行錯誤を通して何かしらの価値を最大化する行動を学習します。

2016年にDeepmind社が、この強化学習をもとに開発した「Alpha Go」が囲碁のトップ棋士に勝利したことで一気に注目を集めました。

車の自動運転や掃除ロボットなど、強化学習を使っているものは僕たちの生活にフツーに溶け込んでいますよね。

  • 教師あり学習 → 正解をあたえて学習する
  • 教師なし学習 → 正解をあたえないで学習する
  • 強化学習 → 価値を最大化する行動を学習する

今回、行った機械学習

今回は機械学習のなかで教師あり学習の分類と回帰を行いました。

正解として与えて、予想したデータは次の通りです。

  • 「分類」の正解データ → 着順
  • 「回帰」の正解データ → 走破タイム

分類は着順を1着から3着のグループと、4着以下のグループの2グループにわけます。

予想に使用するのはレース当日のデータや過去5走分のデータです。

教師あり学習において、予想する正解となるデータのことを目的変数、予想に使うデータのことを説明変数と言います。

目的変数と説明変数をあわせたものを特徴量と言い、今回のケースでは「競馬のレースの特徴を数値であらわしたもの」のことですね。

機械学習では特徴量がかなり重要です。機械学習の精度に大きく影響をあたえるからですね。

各レースのオッズデータも取得しておき、着順予想通りに馬券を購入した場合にいくら払い戻されるかも計算します。

  • 目的変数 → 教師あり学習の正解(着順や走破タイム)
  • 説明変数 → 正解を予想するのに必要なデータ(当日や過去のレースデータ)
  • 特徴量 → 目的変数と説明変数をあわせたもの(競馬のレースデータの特徴)

データセットの準備

今回、使用したデータは2015年から2022年6月現在まで名古屋競馬場で開催されたレースデータです。

競馬情報サイトnetkeiba(https://www.netkeiba.com/)の結果ページと出馬表ページからスクレイピングすることでデータセットをつくりました。

スクレイピングとはWebページからデータを取得する作業のことで、Pythonではスクレイピングに便利なライブラリがいくつもあります。

  • Requests
  • Beautiful Soup
  • pandas
  • Selenium など

ライブラリは料理における調理器具セットのようなもので、特定の処理を実行するためのプログラムのまとまりのことを指します。

今回はRequests、Beautiful Soup、pandasライブラリを使って競馬データをスクレイピングしました。

くわしい内容は別記事で『netkeibaから競馬データをスクレイピングする方法』としてまとめてあるので、もっと知りたい方はぜひどうぞ。

netkeibaから取得したデータセットには機械学習に必要ないデータや、そのままの形では機械学習に使えないデータが混ざっています。

なので機械学習する前にデータをととのえました。データの処理や分析に強いpandasライブラリを使います。

pandasライブラリで行ったデータ前処理については『競馬の機械学習のためpandasでデータ前処理』に実際のコードも載せてあります。

機械学習のまえにかならず通る道ですので、よくわからない方はぜひ読んでみてください。

モデルを作成し、回収率を計算

いよいよ機械学習のフェーズに入っていきます。

さきほど機械学習の教師あり学習で分類と回帰を行うと書きました。しかし、ひとことで「分類」と言ってもその具体的な手法はいくつも種類があります。

今回はPythonの機械学習ライブラリの中で定番とされるscikit-learnで実装できるものを中心に次の5種類で行いました。

  • 分類①:ロジスティック回帰
  • 分類②:LightGBM
  • 回帰①:線形回帰
  • 回帰②:ランダムフォレスト
  • 回帰③:LightGBM

分類、回帰ともに書いてある「LightGBM」はscikit-learnライブラリに入っているわけではありません。ですがデータサイエンティストや機械学習エンジニアが参加するコンペの上位者のなかでかなり使われているアルゴリズムらしく、初心者の僕でも使えそうなので使ってみることにしました。

分類は「3着以内に入るかどうか」を予想し、「3着以内に入る確率」が高い馬から順に1着予想、2着予想、3着予想…とします。

回帰は「走破タイム」を予想し、「予想タイム」が速い馬から順に1着予想、2着予想、3着予想…とします。

このように機械学習によって予想した着順をつかって馬券を単勝、馬単、3連単で1通りずつ買った場合のシミュレーションをしていくわけです。

すべてのレースで予想し、買ったとき的中率と回収率がどうなるかを計算しました。ここがイチバン大切な数字です。

  • 単勝 → 1着の馬を予想
  • 馬単 → 1着と2着の馬を着順通りに予想
  • 3連単 → 1着と2着と3着の馬を着順通りに予想
  • 的中率 → 的中したレース数 ÷ 買ったレース数 × 100
  • 回収率 → 払い戻された金額 ÷ 馬券を買った金額 × 100

回収率はモチロン100%を超えてくれたら嬉しいですが、JRAが出している『勝馬投票法ごとの払戻率』が以下の通りなので、それらを超えたらまずは良しとしたいところですね。

JRAが設定する勝馬投票法ごとの払戻率
引用元:『馬券のルール JRA』(https://www.jra.go.jp/kouza/baken/index.html)

てか、1番払戻率の高い単勝ですら80%…。無理ゲーじゃないですか笑

結果:多くのモデルで回収率100%を達成

機械学習した結果をズラッとならべていきます。

分類①:ロジスティック回帰

馬券の種類的中率(%)回収率(%)
単勝39.8132.5
馬単13.562.4
3連単4.654.7

分類②:LightGBM

馬券の種類的中率(%)回収率(%)
単勝38.7134.0
馬単13.072.8
3連単3.765.2

回帰①:線形回帰

馬券の種類的中率(%)回収率(%)
単勝40.6132.6
馬単14.3154.2
3連単5.173.4

回帰②:ランダムフォレスト

馬券の種類的中率(%)回収率(%)
単勝37.5129.5
馬単13.2146.5
3連単4.561.0

回帰③:LightGBM

馬券の種類的中率(%)回収率(%)
単勝37.6129.0
馬単13.4159.6
3連単4.366.3

各モデルで回収率100%超えを達成しました。

ただ「やった!これで儲けられるぜ!」って思うのは早いようです。

そのことを含めて、機械学習を通して感じたことを次でまとめたいと思います。

競馬の機械学習を通して感じたこと

機械学習して回収率を出してみて感じたこと、それは

競馬は予想より、どう買うかのほうが大切

ってことです。

どのモデルでも単勝的中率が40%くらいでした。つまり、5レース中2レースは1着予想した馬が1着でくるという計算です。

ですが、的中率が回収率に直結しないのが競馬のむずかしいところ。

どういうことかと言うと、的中したレースの払い戻しが多いか少ないか(オッズが大きいか小さいか)によって回収率が左右します。

今回の学習では馬単(1着と2着を着順通りに予想する)でそのあたりがハッキリとあらわれていますよね。

馬単の的中率はどれも13〜14%くらいです。つまり7、8レースに1レースは的中しました。

ですが回収率は1番小さいロジスティック回帰では62.4%、1番大きい線形回帰では154.2%とまったくちがう結果となりました。それこそ「大負け」と「大勝ち」くらいの差があります。

的中率がおなじ(予想精度はおなじ)にもかかわらず、回収率が倍以上ちがってしまう原因がオッズです。

オッズは人気な馬であればあるほど低くなります。たとえば単勝オッズなら「この馬が1着にくるだろう」とたくさん単勝馬券が買われた馬ほど低くなります。

逆にあまり人気のない馬を選んで馬券を買い、それが当たったときはより多く払い戻されるわけです。

イメージしやすい例で言うなら、単勝馬券を買うとき、1番人気の馬で買って当たるより、8番人気の馬で買って当たったほうが回収率がよくなります。でも的中率は同じです。

つまり、あるていど的中するのであれば、あとはオッズや人気を見て「どう買うか」が回収率を上げるためにキーになりそうってわけです。

そのあたりは機械学習の精度というより、オッズの仕組みや馬券の買い方を勉強したほうが良さそうですね。

まとめ

今回は競馬データを機械学習して、回収率を計算してみました。

結果的にはどのモデルで予想しても回収率を100%を超えたのでよかったですね。

ただ、予想はできても買い方がむずかしいのが競馬の世界でしょう。

買い方も予想(こういうレースならオッズが高いから買うべきみたいな)できたらもっと回収率を上げられる…のかな?

最後まで読んでいただきありがとうございました。ではまた。

コメント