Help us understand the problem. What is going on with this article?

【Python & SQLite】単勝1倍台の馬がいるレースの期待値分析してみた①

概要

競馬 × AIの話題を見かけることがここ数年で増えましたが、全レースを対象としたものも多く、
個人的に気になる事例に絞って分析してみたい!と思い、今回netkeiba-scraperを使用していじってみました。

今回絞るテーマは「単勝1倍台の馬が出走するレースの買い方」です。
2019年は日本ダービーや阪神JF、有馬記念など、単勝1倍台の馬が馬券外に沈むケースも多く見られました。
あくまで単勝馬券で分析は進めました。

※SQLをPythonでいじる練習も兼ねていますので、コードの書き方ご指導いただけると嬉しいです!

netkeiba-scraperでデータ取得

競馬データのスクレイピングについては、偉大なる先人のコードを使用させていただきました。
gitHubはこちら

過去10年分のデータを取得しました。
特徴量抽出のためのgenfeatureは、処理に40日くらいかかりそうだったため使用しませんでした。
またJRAのクラス呼称が変更された(ex. 500万下→1勝クラス)ため、Scalaコードを直さないと適切にgenfeatureできなさそうです。

DLしたrace.dbファイルをPythonで読み込み、データ分析を開始します。

Jupyter NotebookでSQLiteを読み込む

dbconnect
import sqlite3 as sq

conn = sq.connect('race.db')
cur = conn.cursor()

cur.execute("SELECT r.race_id, i.race_name, r.order_of_finish, r.odds \
             FROM race_result r INNER JOIN race_info i on r.race_id=i.id \
             WHERE r.odds<2.0")

rows = cur.fetchall()
for row in rows:
    print(row)

Jupyter Notebookのipynbファイルと同じ階層にrace.dbファイルを移し、読み込みます。
race.dbのうちレースのデータがrace_infoテーブル、race_resultテーブルに格納されているので、
欲しい情報を各テーブルから取得します。

※race_infoテーブル レースごとの情報が載っています
image.png

※race_resultテーブル 馬ごとの戦績が載っています
image.png

1倍台の人気で勝利した馬の期待値

オッズ別期待値(全クラス)
# 勝ち数
cur.execute("SELECT r.odds, count(r.race_id) \
             FROM race_result r \
             WHERE r.odds<2.0 AND r.order_of_finish='1' \
             GROUP BY r.odds ORDER BY r.odds ASC")
rows = cur.fetchall()
# 全レース 
cur.execute("SELECT r.odds, count(r.race_id) \
             FROM race_result r \
             WHERE r.odds<2.0 \
             GROUP BY r.odds ORDER BY r.odds")
rows2 = cur.fetchall()

# 期待値計算 もっと他に書きようありそう
try:
    t11 = rows[0][0] * rows[0][1] / (rows2[0][0] * rows2[0][1]) * 100
    t12 = rows[1][0] * rows[1][1] / (rows2[1][0] * rows2[1][1]) * 100
    t13 = rows[2][0] * rows[2][1] / (rows2[2][0] * rows2[2][1]) * 100
    t14 = rows[3][0] * rows[3][1] / (rows2[3][0] * rows2[3][1]) * 100
    t15 = rows[4][0] * rows[4][1] / (rows2[4][0] * rows2[4][1]) * 100
    t16 = rows[5][0] * rows[5][1] / (rows2[5][0] * rows2[5][1]) * 100
    t17 = rows[6][0] * rows[6][1] / (rows2[6][0] * rows2[6][1]) * 100
    t18 = rows[7][0] * rows[7][1] / (rows2[7][0] * rows2[7][1]) * 100
    t19 = rows[8][0] * rows[8][1] / (rows2[8][0] * rows2[8][1]) * 100
except:
    None

print('単勝1.1倍の馬券期待値は %d' %t11)
print('単勝1.2倍の馬券期待値は %d' %t12)
print('単勝1.3倍の馬券期待値は %d' %t13)
print('単勝1.4倍の馬券期待値は %d' %t14)
print('単勝1.5倍の馬券期待値は %d' %t15)
print('単勝1.6倍の馬券期待値は %d' %t16)
print('単勝1.7倍の馬券期待値は %d' %t17)
print('単勝1.8倍の馬券期待値は %d' %t18)
print('単勝1.9倍の馬券期待値は %d' %t19)

image.png
面白いことに、オッズが低いほど単勝期待値が高い(=1着になる可能性が高い)ことが分かりました。
やはり1.1倍ともなると歴史的名馬も多いからでしょうか。

似た条件で【オープンクラス以上(重賞含む)】に絞ると、1.1倍の期待値がさらに上昇しました。

OnlyOpenClass
cur.execute("SELECT r.odds, count(r.race_id) \
             FROM race_result r INNER JOIN race_info i on r.race_id=i.id \
             WHERE r.odds<2.0 AND r.order_of_finish='1' AND i.race_class like '%オープン%' \
             GROUP BY r.odds ORDER BY r.odds ASC")

image.png

人気別の成績を調べる

単勝1倍台の馬が出走するレースでは、どの馬が勝利することが多いのでしょうか?
2番人気や3番人気に妙味はあるのでしょうか?

上までの分析と違い、【単勝1倍台の馬がいるレースに限定】しなければ計算できないため、
WHERE ~ IN (SELECT ~~)の記法でサブクエリを使用しました。

ResultByPopularity
# 単勝1倍台の馬がいるレースのうち人気別勝ち数
cur.execute("SELECT r.popularity, count(r.race_id) \
             FROM race_result r \
             WHERE r.order_of_finish='1' AND r.race_id IN (SELECT race_id from race_result WHERE odds<2.0 AND popularity='1') \
             GROUP BY r.popularity ORDER BY r.popularity ASC")
rows = cur.fetchall()
# 単勝1倍台の馬がいる全レース 
cur.execute("SELECT count(r.race_id) FROM race_result r WHERE r.odds<2.0 AND r.popularity='1'")
rows2 = cur.fetchall()

for row in rows:
    print(row)
print(rows2[0][0])

image.png
全7,619レース中、約半数を1番人気が勝利しています。
2番人気は単勝6倍以上、3番人気は10倍近くつかないと期待値100を超えません。

image.png
オッズに頭数を掛け、レース数で割る形で期待値を計算しましたが、32と酷い有様でした。

まとめ

競馬場やダート/芝、馬齢、馬番、馬の脚質を細分化しなければ、オッズを見ても儲からない、というのが今回の結果でした。
また競馬には多様な馬券の種類があるため、【単勝1倍台の馬が出走するレースで最も期待値の高い馬券種はどれか?】など、
もっと深く分析できそうです。

Python(Jupiter Notebook)でSQLを抽出する要領はつかめたので、引き続き分析してみようと思います。

参考記事

netkeiba-scraperが2019年6月現在動くかの話(Ubuntu 18.04.2 LTS)

gmnori
元経理社員 / Pythonでデータ分析はじめました https://github.com/gmnori
https://twitter.com/gmnoir
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした