[儲からない競馬予想AI] Section 01-04 : データ整形④ 学習データの作成

では、Section01-01で作ったテーブルデータへ、馬の戦績、騎手の戦績、血統のデータを追加していきます。また、同じレースの強い馬の戦績も追加することにします。

ベースとなるプログラムはSection01-01で書いたコードです。

馬の戦績の追加

追加するデータは次の統計値としました

  • pre_race_count : 過去にレースに出た回数
  • pre_race_rankin1_rate : 1位になった割合
  • pre_race_rankin3_rate : 3位以内になった割合
  • pre_race_mean_rank : 過去の平均順位
  • pre_race_weight_mean_rank : 過去の加重平均順位(重みは最近になるほど重い)
  • pre_race_mean_strength : 平均の強さ(タイムから算出)
  • pre_race_weight_mean_strength : 加重平均の強さ(タイムから算出)
  • pre_race_total_prize : 過去の賞金総額
  • pre_race_mean_prize : 賞金の平均額
  • pre_race_weight_mean_prize : 賞金の加重平均額

このとき、加重平均は次のコードで算出することにしました。

def least_weight_mean(arr):
    w = np.arange(len(arr), 0, -1)
    return sum(arr * w)/sum(w)

以下、馬のIDが渡されたら、horse_infoディレクトリから読み込んでくる関数です。

def get_horse_pre_info(horse_id, date):
    horse_races_df = pd.read_pickle(f'formatted_source_data/horse_info/{horse_id}.pkl')
    pre_race_df = horse_races_df.loc[horse_races_df['race_date'] < date, :]
    race_count = len(pre_race_df)
    if race_count == 0:
        ret_data = {
            'pre_race_count': 0,
            'pre_race_rankin1_rate': 0.0,
            'pre_race_rankin3_rate': 0.0,
            'pre_race_mean_rank': None,
            'pre_race_weight_mean_rank': None,
            'pre_race_mean_strength':None,
            'pre_race_weight_mean_strength':None,
            'pre_race_total_prize':0,
            'pre_race_mean_prize':0,
            'pre_race_weight_mean_prize':0,
        }

    else:
        ret_data = {
            'pre_race_count': race_count,
            'pre_race_rankin1_rate': sum((pre_race_df['rank'] == 1).astype('int64')) / race_count,
            'pre_race_rankin3_rate': sum((pre_race_df['rank'] <= 3).astype('int64')) / race_count,
            'pre_race_mean_rank': np.mean(pre_race_df['rank']),
            'pre_race_weight_mean_rank': least_weight_mean(pre_race_df['rank']),
            'pre_race_mean_strength': np.mean(pre_race_df['strength']),
            'pre_race_weight_mean_strength':least_weight_mean(pre_race_df['strength']),
            'pre_race_total_prize':np.sum(pre_race_df['prize']),
            'pre_race_mean_prize':np.mean(pre_race_df['prize']),
            'pre_race_weight_mean_prize':least_weight_mean(pre_race_df['prize']),
        }

    return ret_data

騎手の戦績の追加

基本的に馬の戦績と同じことをします

def get_jocky_pre_info(jocky_id, date):
    jocky_races_df = pd.read_pickle(f'formatted_source_data/jocky_info/{jocky_id}.pkl')
    pre_race_df = jocky_races_df.loc[jocky_races_df['race_date'] < date, :]
    race_count = len(pre_race_df)
    if race_count == 0:
        ret_data = {
            'pre_race_jocky_count': 0,
            'pre_race_jocky_rankin1_rate': 0.0,
            'pre_race_jocky_rankin3_rate': 0.0,
            'pre_race_jocky_mean_rank': None,
            'pre_race_jocky_weight_mean_rank': None,
            'pre_race_jocky_mean_strength':None,
            'pre_race_jocky_weight_mean_strength':None,
            'pre_race_jocky_total_prize':0,
            'pre_race_jocky_mean_prize':0,
            'pre_race_jocky_weight_mean_prize':0,
        }

    else:
        ret_data = {
            'pre_race_jocky_count': race_count,
            'pre_race_jocky_rankin1_rate': sum((pre_race_df['rank'] == 1).astype('int64')) / race_count,
            'pre_race_jocky_rankin3_rate': sum((pre_race_df['rank'] <= 3).astype('int64')) / race_count,
            'pre_race_jocky_mean_rank': np.mean(pre_race_df['rank']),
            'pre_race_jocky_weight_mean_rank': least_weight_mean(pre_race_df['rank']),
            'pre_race_jocky_mean_strength': np.mean(pre_race_df['strength']),
            'pre_race_jocky_weight_mean_strength':least_weight_mean(pre_race_df['strength']),
            'pre_race_jocky_total_prize':np.sum(pre_race_df['prize']),
            'pre_race_jocky_mean_prize':np.mean(pre_race_df['prize']),
            'pre_race_jocky_weight_mean_prize':least_weight_mean(pre_race_df['prize']),
        }

    return ret_data

レースデータをテーブルデータへと変換

Section01-01で書いたコードの関数を書き直します。

def race_data_to_df(race_data, race_id, place_id):
    with open('formatted_source_data/horse_name2id_dict.pkl', 'rb') as f:
        horse_name_to_id_dict = pickle.load(f)
    with open('formatted_source_data/jocky_name2id_dict.pkl', 'rb') as f:
        jocky_name_to_id_dict = pickle.load(f)
    with open('formatted_source_data/ped_name2id_dict.pkl', 'rb') as f:
        ped_name_to_id_dict = pickle.load(f)

    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

        # add pre_race_info
        horse_name = data['name']
        horse_id = horse_name_to_id_dict[horse_name]

        pre_horse_data = get_horse_pre_info(horse_id, data['race_date'])
        for key, value in pre_horse_data.items():
            data[key] = value

        # add pre_race_jocky_info
        jocky_name = data['jocky_name']
        jocky_id = jocky_name_to_id_dict[jocky_name]

        pre_jocky_data = get_jocky_pre_info(jocky_id, data['race_date'])
        for key, value in pre_jocky_data.items():
            data[key] = value


        #add ped name info
        for i, ped_name in enumerate(horse_data_dict['ped_data']):
            data[f'ped_{i}'] = ped_name_to_id_dict[ped_name]

        ret.append(data)
    df = pd.DataFrame(ret)

    other_horse_data = get_race_other_horse_info(df)

    for key, value in other_horse_data.items():
        df[key] = value

    return df

また、全馬のデータを作成したあとに、get_race_other_horse_info関数を使って、レース内の強い戦績の馬のデータを追加します。これにより、その馬が出馬する馬の中で強いか弱いかを判断できるようにします。

同じレースの強い馬の戦績を追加

いつくかの項目に沿って、出馬データをソートし、上位3つの馬のデータを記録します。
これを、上のプログラム内で全馬のテーブルデータへと追加しました。

def get_race_other_horse_info(race_df):
    target_columns = [
        'pre_race_rankin1_rate', 'pre_race_rankin3_rate', 'pre_race_mean_rank', 'pre_race_weight_mean_rank' ,'pre_race_mean_strength', 'pre_race_weight_mean_strength',
        'pre_race_total_prize', 'pre_race_mean_prize', 'pre_race_weight_mean_prize'
    ]

    top_n = 3
    ret_data = {}
    for col in target_columns:
        top_df = race_df.sort_values(col, ascending=False).head(top_n)
        for value in top_df[col]:
            ret_data[f'race_top_{top_n}_{col}'] = value

    target_columns = [
        'pre_race_mean_rank', 'pre_race_weight_mean_rank'
    ]
    for col in target_columns:
        top_df = race_df.sort_values(col, ascending=True).head(top_n)
        for value in top_df[col]:
            ret_data[f'race_top_{top_n}_{col}'] = value

    return ret_data

main

メイン関数もほとんど書き換えてません。出力するファイル名をanalysis_data02.pklとしました。

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])
                        #print(race_data_to_df(data, race_id, place_id))
                        #exit()
                        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_data02.pkl'
    df.to_pickle(save_name)

実行するとformatted_source_dataディレクトリにanalysis_data02.pklファイルが生成されます。あとはこのデータから機械学習をするだけです。

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