[儲からない競馬予想AI] Section 01-01 : データ整形①

収集したデータですが、各レースのデータは次のような形式を持っています

{
    '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のデータフレームでレースデータが読み込めます。

次は、このデータを弄って必要な加工をします。

タイトルとURLをコピーしました