Section 01-02で作成したanalysis_data01_with_strength.pklをそれぞれの馬、騎手ごとに分割して保存します。
それぞれ分けて保存する理由は、あとの並列処理でファイルが分かれていたほうが読み込み速度が早いからです。
馬ごとのレースデータをまとめる
上のデータフレームを読み込んで馬の名前で分類し、分けて保存するコードです。
pandasにはgroupbyというメソッドがあり、分類が分かりやすいのですが、グループ数とデータ数が多くなり、マスク処理に時間がかかるため、ソート関数を利用して分類をしました。
やっていることは馬の名前でソートし、1行づつとりだし、名前が変わるタイミングでまとめて出力。
import warnings
warnings.simplefilter('ignore', FutureWarning)
import pandas as pd
import pickle
import os
import tqdm
def process(df, save_dir):
df = df.sort_values('name').reset_index(drop=True)
with open('formatted_source_data/horse_name2id_dict.pkl', 'rb') as f:
name_to_id_dict = pickle.load(f)
target_name = df.at[0, 'name']
arr = []
for row in tqdm.tqdm(df.itertuples(), total=len(df)):
if row.name == target_name:
arr.append(row)
else:
name_df = pd.DataFrame(arr)
name_df.to_pickle(f'{save_dir}/{name_to_id_dict[target_name]}.pkl')
arr = [row]
target_name = row.name
name_df = pd.DataFrame(arr)
name_df.to_pickle(f'{save_dir}/{name_to_id_dict[target_name]}.pkl')
if __name__ == '__main__':
analysis_df = pd.read_pickle('formatted_source_data/analysis_data01_with_strength.pkl')
names = analysis_df['name'].unique()
name_to_id_dict = {name:i for i, name in enumerate(names)}
with open('formatted_source_data/horse_name2id_dict.pkl', 'wb') as f:
pickle.dump(name_to_id_dict, f)
save_dir = 'formatted_source_data/horse_info'
os.makedirs(save_dir, exist_ok=True)
process(analysis_df, save_dir)
一応並列処理しやすいようにprocessで区切ったけど、実行速度が数分程度だったので、並列処理はしませんでした。
ちなみに、groupbyメソッドでデータフレームを分割すると、分割するだけでメモリをめちゃくちゃ消費して、時間がかかります。
実行すると、fomatted_source_dataディレクトリに、horse_infoというディレクトリとhorse_name2id_dict.pklというファイルが生成されます。
馬の名前がファイル名として利用できるか一応心配だったので、一度int型のIDへと変換しました(もしかしたら必要ないかも)
騎手ごとのレースデータをまとめる
上のデータフレームを読み込んで騎手の名前で分類し、分けて保存するコードです。
馬データど同様にソート関数を利用して分類をしました。
import warnings
warnings.simplefilter('ignore', FutureWarning)
import pandas as pd
import pickle
import os
import tqdm
def process(df, save_dir):
df = df.sort_values('jocky_name').reset_index(drop=True)
with open('formatted_source_data/jocky_name2id_dict.pkl', 'rb') as f:
name_to_id_dict = pickle.load(f)
target_name = df.at[0, 'jocky_name']
arr = []
for row in tqdm.tqdm(df.itertuples(), total=len(df)):
if row.jocky_name == target_name:
arr.append(row)
else:
name_df = pd.DataFrame(arr)
name_df.to_pickle(f'{save_dir}/{name_to_id_dict[target_name]}.pkl')
arr = [row]
target_name = row.jocky_name
name_df = pd.DataFrame(arr)
name_df.to_pickle(f'{save_dir}/{name_to_id_dict[target_name]}.pkl')
if __name__ == '__main__':
analysis_df = pd.read_pickle('formatted_source_data/analysis_data01_with_strength.pkl')
names = analysis_df['jocky_name'].unique()
name_to_id_dict = {name:i for i, name in enumerate(names)}
with open('formatted_source_data/jocky_name2id_dict.pkl', 'wb') as f:
pickle.dump(name_to_id_dict, f)
save_dir = 'formatted_source_data/jocky_info'
os.makedirs(save_dir, exist_ok=True)
process(analysis_df, save_dir)
実行すると、fomatted_source_dataディレクトリに、jocky_infoというディレクトリとjocky_name2id_dict.pklというファイルが生成されます。
血統データをカテゴリー変数へ変換する
血統データは各レースの馬の情報に付随しているデータです。
このデータは自分の血統を62の馬の名前で表したリストデータです。
とうぜん、このままlightGBMへと馬の名前を入れるわけにはいかないので、出現する馬の名前をリストアップし、int型のカテゴリー変数データへと変換します。
そのための変換辞書を作成するプログラムです。
オリジナルデータを読んで、血統の名前をリストアップし、結合して辞書へと登録するだけです。
import warnings
warnings.simplefilter('ignore', FutureWarning)
import pandas as pd
import numpy as np
import pickle
import joblib
import tqdm
def race_data_to_df(race_data):
horses_data = race_data['race_horses_data']
ret = set()
for i,horse_data_dict in enumerate(horses_data):
ped_data = horse_data_dict['ped_data']
for name in ped_data:
ret.add(name)
return ret
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 += 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 for race_data in database]
parallel_ret = joblib.Parallel(n_jobs=-1, verbose=1)([joblib.delayed(race_data_to_df)(arg) for arg in args])
print('parallel result concat')
ped_name_to_id_dict = {}
count = 0
for ret in tqdm.tqdm(parallel_ret):
for name in ret:
if name not in ped_name_to_id_dict:
ped_name_to_id_dict[name] = count
count += 1
print(f'unique ped name num : {len(ped_name_to_id_dict)}')
save_name = f'formatted_source_data/ped_name2id_dict.pkl'
with open(save_name, 'wb') as f:
pickle.dump(ped_name_to_id_dict, f)
実行すると、fomatted_source_dataディレクトリに、ped_name2id_dict.pklが生成されます。