今回は取得したデータから、modelを作っていきます。
前回の記事はこちらから。
モデルの作成方法と特徴量の選定
lightGBMは『教師あり学習』に分類される、決定木をベースとしているアルゴリズムのため、目的変数と、説明変数(特徴量)を定義する必要があります。
まずは、モデルの作成方法ですが、前回作成した”personal_data.csv”と”data_result_csv”のデータを1行を1レースとしてデータフレームを作っていきます。
def make_data_for_ai():
import pandas as pd
import os
import numpy as np
from sklearn.metrics import confusion_matrix
df_personal = pd.read_csv('/users/tom/boat_pred/data_csv/personal_data.csv')
csv_rsult_dir = '/Users/tom/boat_pred/data_csv/data_result_csv'
csv_result_file = os.listdir(csv_rsult_dir)
csv_result_file.sort()
csv_result_file.remove('.ipynb_checkpoints')
df_r = []
for i in csv_result_file[-8:]:
d = pd.read_csv(f'/Users/tom/boat_pred/data_csv/data_result_csv/{i}')
df_r.append(d)
df_results = pd.concat(df_r)
df_results = df_results.reset_index(drop=True)
df_results['1着'] = df_results['着順'].apply(lambda x : 1 if x == 1 else 0)
df_results['2連対'] = df_results['着順'].apply(lambda x : 1 if x <= 2 else 0)
df_results['3連対'] = df_results['着順'].apply(lambda x : 1 if x <= 3 else 0)
mix_data = pd.merge(df_results,df_personal, on='選手登番')
id = df_results['id'].unique()
one_race = []
jyogai = []
for i in id:
w = mix_data[mix_data['id'] == i]
if len(w) == 6:
w.sort_values('艇番',inplace=True)
one_race.append(w)
else:
jyogai.append(w)
white = mix_data.columns+'1号艇'
black = mix_data.columns+'2号艇'
red = mix_data.columns+'3号艇'
blue = mix_data.columns+'4号艇'
yello = mix_data.columns+'5号艇'
green = mix_data.columns+'6号艇'
teiban = np.concatenate([white,black,red,blue,yello,green])
one_race_list = []
for i in one_race:
no1 = i[:1].values
no2 = i[1:2].values
no3 = i[2:3].values
no4 = i[3:4].values
no5 = i[4:5].values
no6 = i[5:6].values
one = np.concatenate([no1,no2,no3,no4,no5,no6])
one_array = one.flatten()
df = pd.DataFrame([one_array])
one_race_list.append(df)
axis1_data = pd.concat(one_race_list)
axis1_data = axis1_data.reset_index(drop=True)
axis1_data.columns = teiban
axis1_data.to_csv('/users/tom/boat_pred/ai_predict/data_for_ai.csv', index=False)
print('ai用csv完了')
if __name__ == '__main__':
make_data_for_ai()
これで1レースを、1行にすることができました。
今回は二値分類でのモデルづくりをしていくので、22行目で1着を”1”、それ以外を”0”として新しいカラムを作っています。これを今回は目的変数としています。特徴量に関しては、明らかに影響のなさそうな、選手の登録番号や支部などを除外しています。また、展示タイムは直前にならないと分からないことから、運用する上で好ましくないのでこれも対象外としました。実際に使った特徴量は次の項目の”train_df”になります。
学習開始
def make_model():
import pandas as pd
import numpy as np
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
import lightgbm as lgb
from sklearn.metrics import accuracy_score
import seaborn as sns
import japanize_matplotlib
import pickle
df = pd.read_csv('/users/tom/boat_pred/ai_predict/data_for_ai.csv')
t_list = ['1着1号艇','1着2号艇','1着3号艇','1着4号艇','1着5号艇','1着6号艇',
'2連対1号艇','2連対2号艇','2連対3号艇','2連対4号艇','2連対5号艇','2連対6号艇',
'3連対1号艇','3連対2号艇','3連対3号艇','3連対4号艇','3連対5号艇','3連対6号艇']
for i in t_list:
#予測ターゲットの格納
target_df = df[[i]]
#特徴量の格納
train_df = df[['艇番1号艇','全国勝率1号艇','1枠1着率1号艇', '1枠2連対率1号艇','1枠3連対率1号艇','平均ST順位1号艇', '1枠ST順位1号艇',
'モーター2連率1号艇',
'艇番2号艇','全国勝率2号艇','2枠1着率2号艇', '2枠2連対率2号艇','2枠3連対率2号艇','平均ST順位2号艇', '2枠ST順位2号艇',
'モーター2連率2号艇',
'艇番3号艇','全国勝率3号艇','3枠1着率3号艇', '3枠2連対率3号艇','3枠3連対率3号艇','平均ST順位3号艇', '3枠ST順位3号艇',
'モーター2連率3号艇',
'艇番4号艇','全国勝率4号艇','4枠1着率4号艇', '4枠2連対率4号艇','4枠3連対率4号艇','平均ST順位4号艇', '4枠ST順位4号艇',
'モーター2連率4号艇',
'艇番5号艇','全国勝率5号艇','5枠1着率5号艇', '5枠2連対率5号艇','5枠3連対率5号艇','平均ST順位5号艇', '5枠ST順位5号艇',
'モーター2連率5号艇',
'艇番6号艇','全国勝率6号艇','6枠1着率6号艇', '6枠2連対率6号艇','6枠3連対率6号艇','平均ST順位6号艇', '6枠ST順位6号艇',
'モーター2連率6号艇']]
# trainとtestに分割
X_train, X_test, y_train, y_test = train_test_split(train_df, target_df, test_size=0.3,random_state=0)
# trainをtrainとvalに分割
X_train, X_eval, y_train, y_eval = train_test_split(X_train, y_train,test_size=0.2,random_state=1,stratify=y_train)
# データを格納する
# 学習用
lgb_train = lgb.Dataset(X_train, y_train)
# 検証用
lgb_eval = lgb.Dataset(X_eval, y_eval)
params = {'objective':'multiclass',
'num_class': 2, # クラスの数
'metric':'multi_logloss',
'verbose': -1,
'learning_rate': 0.05, # 学習率
'num_leaves': 21
}
verbose_eval = 0
model = lgb.train(params, # 設定したパラメータ
lgb_train, # 使用するデータセット
valid_names=['train', 'valid'], # 学習経過で表示する名称
valid_sets=[lgb_train, lgb_eval], # モデル検証のデータセット
num_boost_round=1000,
callbacks=[lgb.early_stopping(stopping_rounds=20,
verbose=True), # early_stopping用コールバック関数
lgb.log_evaluation(verbose_eval)]
)
with open(f'/users/tom/boat_pred/ai_predict/model/model{i}.pickle', mode='wb') as f:
pickle.dump(model, f)
if __name__== '__main__':
make_model()
とりあえずこんな感じで学習させました。
ここが、本題でありゴールであるはずなのに割とあっさりmodelが完成しました。
2連対率、3連対率ものちのち使えるかもと、forループでモデルとして残しています。
今回のやり方(1レース1行にまとめる)で実装しようと思った理由が、実際のレースでは相手関係によってに1着率が変わるのは当然で、『1号艇の勝率教えて、他の選手はこんな選手ですけど』と言う対比をはっきりさせたかったからです。
兎にも角にもこれで1号艇から6号艇の、それぞれの1着率を計算するmodelが出来上がりました。
次回modelの検証編に続く。