修士論文の執筆が忙しくだいぶ間が空いてしまいましたが、第4回の記事では各ソースから収集してきたデータを整理する方法について書いていきます。
まずは馬柱をつくる
競馬の1レースが持つ情報には、競馬場や距離などのレースに関する情報、また出走する各馬の馬番、負担重量、騎手、プロフィール、過去戦績などがあります。さらに各戦績はレース情報、負担重量、騎手、着順・タイムなどの結果を持っており、非常に複雑です。
機械学習アルゴリズムの入力となる特徴量を作成するためには、それら複雑なデータを整形していく必要があります。例えば、分+秒形式のタイムを秒に変換したり、走破タイムをレース内で標準化したり、過去の着順から勝率を計算するなどです。それらの泥臭いデータ整形をスクリプトやSQLのクエリとしてベタ書きをしていくと、保守性が失われ、後々手の施しようがないプログラムになってしまいます(経験談)。
そこでAlphaImpactでは収集してきたデータから『馬柱』を作ることでデータの管理や生成の効率化を実現しています。馬柱とは競馬新聞1に載っているレースに必要な情報がまとまっている表のことです。『馬柱』をつくるといっても実際に競馬新聞をつくるのではなく、馬柱を模倣したデータ構造をプログラムで再現します。煩雑な生データを馬柱で包むことによって、予測やデータ成形のインターフェースを統一することができるので、プログラムの見通しも良くなります。例えばAlphaImpactでは、レースの予測を出すときは predict(horse_table)
、特徴ベクトルを生成する場合はcreate_data(horse_table)
のように簡潔なコードで記述できています。
馬柱を要素に分解
馬柱は以下の図のように要素を分解できます。
次に各データ種別ごとのデータの例を紹介します。
開催情報
レースが行われる開催における情報です。
データ名 | 備考 |
---|---|
競馬場 | 函館・札幌・福島・新潟・東京・中山・中京・京都・阪神・小倉 |
年月日 | |
開催回 | 第N回 |
開催日 | N日目 |
曜日 | |
天候 | |
馬場状態 | 良・稍重・重・不良 |
番組情報
レースに関する情報です。
データ名 | 備考 |
---|---|
レース名 | 例)日本ダービー |
トラック | 芝・ダート・障害 |
コース距離 | |
右左 | コーナーの回り向き |
内外 | コースの内外 |
クラス条件 | 新馬・未勝利・500万下・1000万下・1600万下・OP |
グレード | GI・GII・GIII |
本賞金 | 1着~5着まで |
年齢条件 | 2歳・3歳・3歳以上・4歳以上 |
競走記号 | 牡馬・牝馬限定など |
出走頭数 |
払戻情報
レースの払戻に関する情報です。
データ名 | 備考 |
---|---|
払戻金 | 単勝・複勝・枠連・馬連・ワイド・馬単・3連複・3連単・Win5 |
的中組番 | 単勝・複勝・枠連・馬連・ワイド・馬単・3連複・3連単・Win5 |
馬属性情報
馬固有のプロフィールです。
データ名 | 備考 |
---|---|
馬名 | 例) ディープインパクト |
生年月日 | |
性別 | |
毛色 | |
血統 | 父・母・父母など |
馬主 | |
生産者 | |
所属厩舎 |
馬毎レース情報
出走レースにおける出走馬の状態に関する情報です。
データ名 | 備考 |
---|---|
馬番 | |
枠番 | |
負担重量 | |
騎手名 | 例)横山典弘 |
馬体重 | |
馬体重増減 |
過去戦績
出走時点における過去の出走レースの条件や結果に関する情報です。
データ名 | 備考 |
---|---|
競馬場 | 函館・札幌・福島・新潟・東京・中山・中京・京都・阪神・小倉 |
年月日 | |
天候 | |
馬場状態 | 良・稍重・重・不良 |
レース名 | 例)日本ダービー |
トラック | 芝・ダート・障害 |
コース距離 | |
右左 | コーナーの回り向き |
内外 | コースの内外 |
クラス条件 | 新馬・未勝利・500万下・1000万下・1600万下・OP |
グレード | GI・GII・GIII |
本賞金 | 1着~5着まで |
年齢条件 | 2歳・3歳・3歳以上・4歳以上 |
競走記号 | 牡馬・牝馬限定など |
出走頭数 | |
馬番 | |
負担重量 | |
騎手名 | 例)横山典弘 |
馬体重 | |
馬体重増減 | |
着順 | |
走破タイム | |
前後3Fタイム | 前半・後半600mのタイム |
コーナー通過順位 | 1~4コーナーにおける通過順位 |
獲得本賞金 | |
1着タイム差 | |
着差 | |
単勝オッズ | |
単勝人気順位 |
プログラムで馬柱を再現
最後に馬柱データ構造のPython 3での実装例を紹介します。以下のコードはAlphaImpactで実際に使っているコードの一部抜粋です。このHorseTableクラスでは馬柱の表示しか実装していないので実質データ格納しかできませんが、AlphaImpactでは着順や走破タイム、払戻を扱いやすいデータ形式にして取得するメソッドなどが実装されており、開発の生産性向上に貢献しています。
class HorseTable(object):
"""
馬柱クラス
"""
def __init__(self, race, horses):
"""
:param race: Raceクラス
:type race: Race
:param horses: Horseクラスのリスト. 馬番順に格納
:type horses: list of Horse
"""
self.race = race
self.horse = horses
def print_table(self):
"""
簡易馬柱を表示する
"""
# レース名の表示
print(self.race.get_race_title())
# 馬番+馬名の表示
for i, horse in enumerate(self.horses):
horse_no = i + 1
print("{}. {}".format(horse_no, horse.get_name()))
class Race(object):
"""
レースクラス
"""
def __init__(self, race_key, program, holding, payback=None):
"""
:param race_key: レースキー
:param program: レース情報
:param holding: 開催情報
:param payback: 払戻情報
"""
self.race_key = race_key
self.program = program
self.holding = holding
self.payback = payback
def get_race_title(self):
"""
レース名を取得する
"""
return self.program["レース名"]
class Horse(object):
"""
馬クラス
"""
def __init__(self, horse_id, horse_profile, horse_race, race_results):
"""
:param horse_id: 血統登録番号
:param horse_profile: 馬属性情報
:param horse_race: 馬毎レース情報
:param race_results: 過去戦績のリスト
"""
self.horse_id = horse_id
self.horse_profile = horse_profile
self.horse_race = horse_race
self.race_results = race_results
def get_name(self):
"""
馬名を取得する
"""
return self.horse_profile["馬名"]
おわりに
今回はプログラム上で競馬データを見通しよく扱うための馬柱データ構造を紹介しました。本記事で紹介したのはあくまで一例ですので、ご自身の持っているデータに合わせたオリジナルの馬柱を作成してみて下さい。この地道な作業が良い予測モデルへの近道となるでしょう。
次回はHorseTableを使って特徴量の作成方法について説明していきます。
-
単位面積当たりに含まれる情報量が最も多い紙媒体の1つ ↩︎