LoginSignup
1
1

LightGBMによるAI競馬予想(ランキング学習)

Posted at

ランキング学習(lambdarank)

この記事を読む前に「LightGBMによるAI競馬予想(準備編)」の記事を先に読んでください。その中には、機械学習の基礎知識や、学習データで使う説明変数の内容など、他のデータ分析方法と共通する説明が含まれています。

二値分類や回帰分析が絶対的な「値」を求めるのに対して、ランキング学習はデータを相対的な順位に基づいて評価します。具体的な数値ではなく、順位情報を活用する特長があり、これが競馬予想などでの適用に向いている理由の一つです。

ここに公開するPythonのソースコードは「特徴量重要度」の可視化を実装しています。学習データを作るSQLで目的変数の項目名を「target」にすれば、オリジナルの学習データで分析する場合でもそのまま使えます。

ソースコードは学習用と予測用に分けてます。

欠損値(null)は、SQLで何らかの値(0など)に変換しておくことを前提にしてます。欠損値についてPythonでは何もしてないってことです。

学習用ソースコード

以下が「ランキング学習」で学習するPythonのソースコードです。この学習用ソースコードのファイル名は「lambdarank_train.py」とします。

PythonのソースコードはUTF-8で保存する必要があります。

lambdarank_train.py
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つのレースを表す、学習データ内で一意なレース番号みたいなもんです。

PC-KEIBAのWebサイトで、サンプルのSQLを公開しています。ユーザーがカスタマイズして利用することも可能ですし、SQLを学習したい方の参考にもなります。
https://pc-keiba.com/wp/lambdarank/

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で保存する必要があります。

lambdarank_pred.py
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)

# モデル読み込み
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つです。

  1. SQLで目的変数「target」の項目を消す。
  2. SQLで「query_id」の項目を消す。
  3. SQLで予想するレースでレコードの抽出条件を設定する。

出馬表データのファイル名は何でも良いですが、ここでは「レースID(※1).csv」とします。
今回のサンプルでは「2023/02/04(土)小倉12R」を予想してみます。

(※1)レースID
年月日場R
yyyymmddjjrr(12桁)

PC-KEIBAのWebサイトで、サンプルのSQLを公開しています。ユーザーがカスタマイズして利用することも可能ですし、SQLを学習したい方の参考にもなります。
https://pc-keiba.com/wp/lambdarank/

予測(予想)させる

先ほどと同じ「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つの「サンプル」でしかありません。完成させるのはユーザーのあなたです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1