この記事を読む前に「LightGBMによるAI競馬予想(準備編)」の記事を先に読んでください。その中には、機械学習の基礎知識や、学習データで使う説明変数の内容など、他のデータ分析方法と共通する説明が含まれています。
ランキング学習(lambdarank)
二値分類や回帰分析が絶対的な「値」を求めるのに対して、ランキング学習はデータを相対的な順位に基づいて評価します。具体的な数値ではなく、順位情報を活用する特長があり、これが競馬予想などでの適用に向いている理由の一つです。
ここに公開するPythonのソースコードは「特徴量重要度」の可視化を実装しています。学習データを作るSQLで目的変数の項目名を「target」にすれば、オリジナルの学習データで分析する場合でもそのまま使えます。
ソースコードは学習用と予測用に分けてます。
欠損値(null)は、SQLで何らかの値(0など)に変換しておくことを前提にしてます。欠損値についてPythonでは何もしてないってことです。
学習用ソースコード
以下が「ランキング学習」で学習するPythonのソースコードです。この学習用ソースコードのファイル名は「lambdarank_train.py」とします。
PythonのソースコードはUTF-8で保存する必要があります。何のこっちゃ分からん場合は、このページの最後の、有料会員限定のダウンロードリンクからもファイルをダウンロードできます。
ソースコードはQiitaの記事から簡単にコピーできます。
※ソースコードの右上にあるアイコンをクリックしてください。
https://qiita.com/PC-KEIBA/items/14741a6caf6110c03df7
import pandas as pd
import numpy as np
import lightgbm as lgb
import matplotlib.pyplot as plt
# CSVファイル読み込み
in_file_name = 'lambdarank_train.csv'
df = pd.read_csv(in_file_name, encoding='SHIFT_JIS')
# 説明変数(x)と目的変数(y)を設定
x = df.drop(columns=['query_id', 'target']) # query_idとy以外の特徴量
y = df['target']
# LightGBM ハイパーパラメータ
params = {
'objective':'lambdarank', # 目的 :ランキング学習
'metric':'ndcg', # 評価指標 :ndcg
'force_row_wise':True # 行単位の処理を強制
}
# モデルの学習
group = df['query_id'].value_counts().sort_index().tolist() # 各クエリに対するサンプル数
train_set = lgb.Dataset(x, label=y, group=group)
model = lgb.train(params, train_set)
# モデルをファイルに保存
model.save_model('lambdarank_model.txt')
# 特徴量重要度
feature = list(df.drop(columns=['target', 'query_id']).columns)
importance = np.array(model.feature_importance())
df = pd.DataFrame({'feature':feature, 'importance':importance})
df = df.sort_values('importance', ascending=True)
n = len(df) # 説明変数の項目数を取得
values = df['importance'].values
plt.barh(range(n), values)
values = df['feature'].values
plt.yticks(np.arange(n), values) # x, y軸の設定
plt.savefig('lambdarank_train.png', bbox_inches='tight', dpi=500)
plt.show()
学習データを作る
説明変数は他の分析方法と共通にしました。内容は「LightGBMによるAI競馬予想(準備編)」の記事を見てください。学習データのファイル名は「lambdarank_train.csv」とします。
今回のサンプルでは目的変数の「確定着順」を、次のように分類してみます。
- 1着→3
- 2〜3着→2
- 4〜5着→1
- 上記以外→0
ランキング学習の学習データには目的変数以外に「ラベル」と呼ばれる項目が必要です。ラベルの項目名は「query_id」にしてます。競馬予想におけるラベルとは1つのレースを表す、学習データ内で一意なレース番号みたいなもんです。
このページの最後に、サンプルのSQLを有料会員に公開しています。ユーザーがカスタマイズして利用することも可能ですし、SQLを学習したい方の参考にもなります。
LightGBMに学習させる
今回の例では、Cドライブの直下に「pckeiba」というフォルダを作って、
- 学習データ(lambdarank_train.csv)
- 学習用ソースコード(lambdarank_train.py)
2つのファイルを置きます。こういう状態です。
そして、コマンドプロンプトを起動し、次の2つのコマンドを「1行ずつ」実行してください。
cd C:\pckeiba
python lambdarank_train.py
LightGBMが学習を開始します。処理が終わると「特徴量重要度」を表示します。
モデルを評価する
今回のサンプルに評価指標はありません。
このモデルを「lambdarank_model.txt」に保存しています。このファイルは予想するとき使います。
特徴量重要度
参考として「特徴量重要度」の可視化を実装してます。特徴量重要度をざっくり言うと、重要度が高い説明変数ほど、目的変数である確定着順に対して影響力が強いということです。
これを見ながら説明変数を取捨選択したり、LightGBMパラメータをチューニングしたりします。
今回のモデルによる結果であるため、この結果がすべてのレースに当てはまると言うわけじゃないです。
いろいろ試してモデルの精度に納得したら、これを使って明日のレースを予想させます。
予測用ソースコード
以下が「ランキング学習」で予想するPythonのソースコードです。
PythonのソースコードはUTF-8で保存する必要があります。何のこっちゃ分からん場合は、このページの最後の、有料会員限定のダウンロードリンクからもファイルをダウンロードできます。
ソースコードはQiitaの記事から簡単にコピーできます。
※ソースコードの右上にあるアイコンをクリックしてください。
https://qiita.com/PC-KEIBA/items/14741a6caf6110c03df7
import pandas as pd
import numpy as np
import lightgbm as lgb
import os
import sys
# 出馬表ファイル読み込み
fname = sys.argv[1]
x_test = np.loadtxt(fname, delimiter=',', skiprows=1)
# 1行だけの場合でも2次元配列に変換
if x_test.ndim == 1:
x_test = x_test.reshape(1, -1)
# モデル読み込み
bst = lgb.Booster(model_file='lambdarank_model.txt')
# テストデータの予測
y_pred = bst.predict(x_test, num_iteration=bst.best_iteration)
# 拡張子を除いたファイル名を取得
fname = os.path.splitext(os.path.basename(fname))[0]
# 予測値を出力
df = pd.DataFrame({'予測値':y_pred})
df.to_csv(fname + '_pred.csv', encoding='SHIFT_JIS', index=False)
出馬表データを作る
予測させる出馬表データは、学習データ作成のSQLと出力後のファイルを少し改造すれば作れます。学習データとの違いは次の3つです。
- SQLで目的変数「target」の項目を消す。
- SQLで「query_id」の項目を消す。
- SQLで予想するレースでレコードの抽出条件を設定する。
出馬表データのファイル名は何でも良いですが、ここでは「レースID(※1).csv」とします。
今回のサンプルでは「2023/02/04(土)小倉12R」を予想してみます。
(※1)レースID | 年月日場R yyyymmddjjrr(12桁) |
---|
このページの最後に、サンプルのSQLを有料会員に公開しています。ユーザーがカスタマイズして利用することも可能ですし、SQLを学習したい方の参考にもなります。
予測(予想)させる
先ほどと同じ「pckeiba」というフォルダに、
- 出馬表(レースID(※1).csv)
- モデル(lambdarank_model.txt)
- 予測用ソースコード(lambdarank_pred.py)
3つのファイルを置きます。こういう状態です。
そして、コマンドプロンプトを起動し、次の2つのコマンドを「1行ずつ」実行してください。2番目は、予測用ソースコードの後に、半角スペースと出馬表のファイル名です。
cd C:\pckeiba
python lambdarank_pred.py 202302041012.csv
処理が終わると1つのファイルが出力されます。「予測値」のファイルです。
- レースID(※1)_pred.csv (予測値)
このファイルには数値データしか含まれていないので、分かりにくいかもしれませんが、出馬表データと同じ馬番の昇順で出力されます。馬券を買うときは、SQLで馬番と馬名だけの出馬表をCSVに出力して、そこへ貼り付けて予測値で並べ替えると便利です。例えば、こんな感じです。
予測値の上位3頭で、レース結果は3連複の払戻金が16,430円となりました。単勝の人気順は、③⑥⑩の組み合わせでした。
「ランキング学習」による競馬予想AIの話は以上です。
今回のサンプルはあくまで1つの「サンプル」でしかありません。完成させるのはユーザーのあなたです。