収集したデータですが、各レースのデータは次のような形式を持っています
{
'race_place_data':dict, #レース固有のデータ。日時、場所、グレード、 距離、馬場、天気など
'race_horses_data':list,#出場する馬の情報リスト
'race_payout_data':dict #支払い情報
}
となっており、さらにrace_hose_data
は次のdictのリストになっています
{
'rank':int,
'horse_number':int,
'jocky_name':str,
...
'ped_data':list, #62の親類のリスト
}
さて、単純にlightGBMなどの機械学習へと競馬データを入力するなら、このrace_hose_data
のリストを整形し、2次元配列へと並び替え、rank
などの順位データを予想するのが良いでしょう。
しかし、このrace_hose_data
データだけでは、予測するための特徴量が足りない気がします。
このrace_hose_data
に含まれるデータは名前や体重、ジョッキーの名前等しか書かれておらず、それだけで順位が決まるとは到底考えられないからです。
一般に、その馬が上位に入るかというのは、過去の戦績や、血統、ジョッキーの戦績などの要因が考えられます。血統データは既に持っていますが、過去の戦績やジョッキーの戦績などは確保していないので、レースデータを処理して計算する必要があります。
ですから、一度レースデータを2次元のテーブルデータへと変換し、後々処理しやすい形へと変換します。
テーブルデータへの変換
webから収集したデータを2次元データへと変換するコードです。
天気や、競技タイプ、競馬場の状態、性別はこの時点で整数型へと変換しました。
import warnings
warnings.simplefilter('ignore', FutureWarning)
import pandas as pd
import numpy as np
import pickle
import joblib
import json
def weather_pre_process(value):
if value == '晴':
return 0
elif value == '曇':
return 1
elif value == '小雨':
return 2
elif value == '雨':
return 3
else:
return 4
def race_type_pre_process(value):
if value == '芝':
return 0
elif value == 'ダ':
return 1
else:
return 2
def race_condition_pre_process(value):
if value == '良':
return 0
elif value == '稍':
return 1
elif value == '重':
return 2
elif value == '不':
return 3
else:
return 4
def string_to_number(str):
number = [f'{n}' for n in range(10)] + ['.', '-']
number_str = ''
for s in str:
if s in number:
number_str += s
if number_str == '':
return None
else:
return float(number_str)
def race_data_to_df(race_data, race_id, place_id):
race_info = race_data['race_place_data']
horses_data = race_data['race_horses_data']
race_payout_data = race_data['race_payout_data']
# 1st step: calc statistics data of previous race infomation
ret = []
race_total_prize = sum([data['prize'] for data in horses_data if data['prize'] != None])
for i,horse_data_dict in enumerate(horses_data):
data = {
'race_date':race_info['race_date'],
'race_id':race_id,
'place_id':place_id,
'race_grade':race_info['race_grade'],
'race_distance':race_info['race_distance'],
'race_type':race_type_pre_process(race_info['race_type']),
'race_total_prize':race_total_prize,
'weather':weather_pre_process(race_info['weather']),
'race_condition':race_condition_pre_process(race_info['race_condition']),
'horse_count':len(horses_data),
'waku':horse_data_dict['waku'],
'horse_number':horse_data_dict['horse_number'],
'name':horse_data_dict['name'],
'sex':horse_data_dict['sex'],
'age':horse_data_dict['age'],
'jocky_weight':horse_data_dict['jocky_weight'],
'jocky_name':horse_data_dict['jocky_name'],
'odds':horse_data_dict['odds'],
'popular':horse_data_dict['popular'],
'weight':horse_data_dict['weight'],
'weight_sub':horse_data_dict['weight_sub'],
'rank':horse_data_dict['rank'],
'time':horse_data_dict['time'],
'prize':horse_data_dict['prize'],
'tansyo_hit':0,
'tansyo_payout':0,
'hukusyo_hit':0,
'hukusyo_payout':0
}
if int(race_payout_data['tansyo_ret']) == data['horse_number']:
data['tansyo_hit'] = 1
data['tansyo_payout'] = string_to_number(race_payout_data['tansyo_payout'])/100
for j, hit_horse_number in enumerate(race_payout_data['hukusyo_ret']):
if int(hit_horse_number) == data['horse_number']:
data['hukusyo_hit'] = 1
data['hukusyo_payout'] = string_to_number(race_payout_data['hukusyo_payout'][j])/100
ret.append(data)
df = pd.DataFrame(ret)
return df
if __name__ == '__main__':
print('load database')
database = []
race_id = 0
for place_id in range(1,11):
for year in range(25):
database_path = f'keiba_source_data/20{year:02}_{place_id:02}.data'
with open(database_path, 'rb') as f:
#print(database_path)
for data in pickle.load(f):
if data != {} and len(data['race_horses_data']) >= 5:
database.append([data, race_id, place_id])
race_id += 1
if len(database) == 0:
print('database load error : size 0')
exit()
print(f'database num : {len(database)}')
print('race_data to learning_data')
args = [(race_data, race_id, place_id) for race_data, race_id, place_id in database]
ret_dfs = joblib.Parallel(n_jobs=-1, verbose=1)([joblib.delayed(race_data_to_df)(*arg) for arg in args])
df = pd.concat(ret_dfs, axis=0)
save_name = f'formatted_source_data/analysis_data01.pkl'
df.to_pickle(save_name)
実行すると、formatted_source_data/analysis_data01.pkl
が生成されます。pd.read_pickle
などで読み込めば、pandasのデータフレームでレースデータが読み込めます。
次は、このデータを弄って必要な加工をします。