どうも、ねへほもんです。
2月にPythonで競馬予想AI制作~準備編~という記事を投稿してから3ヶ月放置していましたが、GWを機にチビチビ作業を再開したので途中経過報告です。
本来ならダービーを当てに行きたいところですが、日曜午後は所用で競馬を観られないため、明日の葵ステークスの分析をしてみました。
1.スクレイピング
まず、本プロジェクトの全体像をおさらいすると、
①スクレイピング
②データ加工
③機械学習
の3段階に分けられます。
前回記事でも書きましたが、③機械学習が一番楽です。
出来たデータを読み込ませて、
たった3行のプログラムを実行するだけなので。
(※一番下の行は準備がまだなので#を付けて実行対象から外しています)
①スクレイピングは前回記事で詳細を書きましたが、
netkeibaのサイトから過去5年分全てのレース情報を拾ってcsvファイルに書き込む作業を指します。
手作業でWebページを開くのは無理がありますが、
Pythonを使えばプログラムを実行して放置すればデータを収集できます。(1年分当たり約1時間放置)
ざっくりプログラムの流れを説明すると、
①URLを指定する (url = "https://・・・という部分)
②指定したURLからデータをHTML形式で取得 (race_soup=BeautifulSoup・・・という部分)
③HTML形式のデータをcsvに書き込める形式に変換 (re.sub(・・・という部分で、HTMLタグ</td>等の余計な部分を削除)
以上①~③の流れをfor文で全レースに対し繰り返す
というものです。
データ量は239592行になりました。うん、手作業では無理だな。
スクレイピング作業の結果、
という2種類のデータを取得できました。
上はどの馬が何番人気で何着になったか等のレース結果、下はそのレースは芝なのかダートなのか、全長何メートルか等のレース情報に関するものです。
レース結果とレース情報を一括で取得できれば作業が楽なのですが、netkeibaのサイトのHTML情報で取得場所が異なるため、別々に取得し、右の5列(2017年、競馬場コード1、第1回開催、1日目の第1レース)の情報を使って後で結合しました。
2.データ加工
横幅が広くてすみませんが、元データは汚い状態でcsvファイルに書き込まれます。
「1月2日」とか謎の記載が時々見られます。
そこで、下図のような加工を行い、機械学習で読み込める形式にします。
これをデータクレンジングと言います。
・緑:走破タイム
01:50:1は単なる文字列として扱われるため、110.1のように「数値情報」「秒単位」へ変換します。
・青:着差情報
一番加工に苦労した部分です。まずは表記を統一しました。
3 1/2→3.5馬身差(小数に変換)
1月2日→0.5馬身(2分の1がExcel表記でバグったので、小数に変換)
クビ→0.25馬身差(クビ差、アタマ差、ハナ差を小数に変換)
次に、1着との差に変換しました。
例えば、1着と2着との差が3馬身差、2着と3着との差が0.5馬身差の場合、3着の着差を0.5馬身差ではなく、3+0.5=3.5馬身差に変換しました。
こうすると、1着と2着の差は3馬身、1着と3着の差は3.5馬身だから2着の方が優秀という傾向を示せます。
・橙:コーナー通過順位
9-7-5-3のような文字列表記を、1コーナー9位、2コーナー7位、3コーナー5位、最終コーナー3位と4列に区分し数値へ変換しました。
短距離戦では2コーナーしか無い場合がありますが、2月1日のような表記を1コーナー2位、2・3コーナーはゼロ、最終コーナー1位といった形で間にゼロを挟みました。
・赤:馬体重
406(-4)という文字列表記を、馬体重406㎏と前走比-4kgに区分し数値へ変換しました。
このようにレース結果を加工した後、レース情報のデータと結合することで、機械学習に読み込ませることが可能となります。
ちなみに、このデータクレンジングまでプログラムで完結できることが望ましいのですが、今回は完全手作業で実施しました。
簡単な加工ならすぐプログラムを書けるのですが、なかなか加工が複雑なので、一旦は僕の社会人8年分のExcelスキルをフル稼働させました。
Pythonの勉強のためにも、後日プログラムで自動化させたいと思っています。(やるとは言ってない)
3.レース傾向分析
続いて機械学習のプログラムを実行しました。
結果得られたのがこちら。
これは何かというと、どの変数が着順に大きく影響しているかというものです。
ninki→人気
ground→芝かダートか
corner4→最終コーナーでの順位
3F→上がり3ハロン(最後の600m)のタイム
圧倒的に人気の影響が大きく、1番人気が強いのはそりゃそうだという結果が得られました。
ちなみに、この重要度の算出方法ですが、
1番人気、ビターグラッセ、最終コーナー3位、上がり3ハロン34秒→結果2着
10番人気、ハッピーミーク、最終コーナー10位、上がり3ハロン36秒→結果15着
というデータがあった時に、各データを入れ替えた時に、機械学習による予測にどう影響するかで算定されます。
例えば、
10番人気、ビターグラッセ、最終コーナー3位、上がり3ハロン34秒→結果2着
1番人気、ハッピーミーク、最終コーナー10位、上がり3ハロン36秒→結果15着
というデータに入れ替えると、「あれっ、1番人気が強いんじゃないんだっけ???」と予測パターンに狂いが生じるため、人気は重要度の高い変数ということになります。
一方で、
1番人気、ハッピーミーク、最終コーナー3位、上がり3ハロン34秒→結果2着
10番人気、ビターグラッセ、最終コーナー10位、上がり3ハロン36秒→結果15着
というデータに入れ替えても、「馬の名前だけ変えた所で、1番人気が強いとか、上がり3ハロンが速い馬が強いとか、想定通りの傾向は変わらんよな」と流されるため、馬の名前は重要度の低い変数ということになります。
(馬の名前を3文字から2文字に削っただけで勝率が大幅アップするとか、そんなオカルト要素があればビックリですよね)
こんな感じで、機械学習は単に「〇〇の馬が本命!」と結果を示すだけではなく、「〇〇の要素を持つ馬が強い!」という傾向を分析することもできます。
機械学習による予想は、
①〇〇の要素を持つ馬が強い、という傾向を掴む
②出走馬のそれぞれが〇〇の要素を持つか、というデータをインプットさせる
という2段階で行われますが、まだ②の準備が出来ていないので、現状は①のみという状況です。
②に進むには、「今回の出走馬は過去にどのレースに出走して、どういう血統で・・・」とか追加のデータが必要なので、どうデータ収集しようか考え中です。
Pythonの作業はここで切り上げ、最後に社会人8年分のExcelスキルを駆使した分析を行いました。
Excelに手作業で数式を入力する形で、芝の全レースの傾向と明日の葵ステークス(中京芝1200m)の傾向を比較し、葵ステークスで重視すべきポイントをまとめました。
ここも本当はプログラムで自動化したい・・・
葵ステークスは一昨年まで京都開催で、中京開催は昨年のみでデータ不足なので、過去5年、計108レースの傾向を分析することは有用だと思いました。
見えた傾向は以下の通りです。
・人気
芝レース全体では平均3.31番人気が勝利している一方、中京芝1200mは平均3.72番人気が勝利しており、やや荒れる傾向にある。馬券内(3着以内)や単勝オッズも同様の傾向。
・3F(上がり3ハロン)
芝レース全体では平均2.87位が勝利している一方、中京芝1200mは平均4.59位が勝利している。
後半600mのタイムが遅めでも勝利できるということは、前半に前目のポジションを取ることが重要(逃げ・先行が強い)ということ。
・4コーナー順位
芝レース全体と中京芝1200mで大きな差はない。
(中京1200mの方が若干値が大きいが、全体も大きいので、出走馬数が大きいことが原因と思われる)
上がり3ハロンが遅めでも勝てるという傾向を見ると、4コーナー順位が上位の方が有利な気がしたが、ここは要確認。
・枠
中京芝1200mでは全体の馬番号が平均8.73に対し、勝ち馬の馬番号は平均6.75なので内枠有利の傾向が読み取れる。
芝レースでは全体平均7.73に対し、勝ち馬平均7.24なので少し内枠有利という程度。
以上をまとめると、
・穴馬歓迎
・逃げ、先行
・内枠
という傾向が見られました。
中京芝1200mの形状を見れば、
・短距離でレースが速く終わる分、人気馬が実力を発揮しきれない可能性がある
・スタート直後に上り坂→スローペースで前脚質が脚を温存しやすい
・3,4コーナーが急カーブ→外枠は遠心力でより外に振られやすい
ということから、上記の傾向だろうと予測は付いたのですが、データで裏付けられて良かったです。
以上、競馬のAI予想の経過報告でした。
今後の課題は、
・AI本命馬〇〇まで予想させる
・手作業のデータ加工を自動化する
・血統とか騎手とか、まだ未使用の情報を加工してデータに含める
の3点です。
先は長いながら、徐々に形になってきてはいます。
また進捗あればご報告しますのでお待ちください。
では(^^)/