JvLink To Importer

過去N走の集計を特徴量にする — ローリング集計の書き方

過去N走の集計を特徴量にする — ローリング集計の書き方

「直近5走の平均着順」「過去3走の上がり3F平均」のように、各馬の過去成績をローリング集計して特徴量にするのは、競馬予測モデルの基本テクニックです。この記事では SQL のウィンドウ関数と Python (pandas) で実装する具体例を紹介します。


なぜローリング集計が効くのか

馬の能力は単発のレース結果ではなく、過去の積み重ねで判断するのが自然です。

  • 直近の好調・不調を反映できる
  • 1走分のノイズ(不利な進路、極端な馬場)を平均で打ち消せる
  • 距離やコース別の集計に分けると適性が見える

LightGBM や XGBoost は「素の着順」よりも「過去N走の集計値」の方が遥かに強い特徴量になります。


SQL でやる: ウィンドウ関数

PostgreSQL のウィンドウ関数 OVER (PARTITION BY ... ORDER BY ...) を使うと、馬ごとに過去 N 走を集計できます。

SELECT
race_id,
horse_id,
finish_position,
-- 直近5走の平均着順(自レースは含まない)
AVG(finish_position) OVER (
PARTITION BY horse_id
ORDER BY race_date
ROWS BETWEEN 5 PRECEDING AND 1 PRECEDING
) AS avg_finish_last5,
-- 直近3走の上がり3F平均
AVG(last_3f) OVER (
PARTITION BY horse_id
ORDER BY race_date
ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING
) AS avg_last3f_last3
FROM race_results
ORDER BY horse_id, race_date;

ポイントは ROWS BETWEEN N PRECEDING AND 1 PRECEDING自レースを除外すること。自レースを含めると未来情報がリークします。


コース別・距離別に分ける

ただ平均するより、条件を絞った集計の方が予測精度が上がります。

-- 同じコース・同じ距離での過去成績
SELECT
race_id,
horse_id,
AVG(finish_position) OVER (
PARTITION BY horse_id, course, distance
ORDER BY race_date
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
) AS avg_finish_same_course_distance,
COUNT(*) OVER (
PARTITION BY horse_id, course, distance
ORDER BY race_date
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
) AS races_same_course_distance
FROM race_results;

「東京2400m での過去成績」「中山ダート1200m での連対率」など、適性を直接表す特徴量になります。


Python (pandas) でやる場合

データフレームで管理しているなら groupby().rolling() が便利です。

import pandas as pd

# race_date でソートしておく
df = df.sort_values(['horse_id', 'race_date']).reset_index(drop=True)

# 直近5走の平均着順 (自レース除外: shift(1))
df['avg_finish_last5'] = (
df.groupby('horse_id')['finish_position']
.shift(1)
.rolling(5, min_periods=1)
.mean()
.reset_index(level=0, drop=True)
)

# 過去3走の連対率 (1着 or 2着の割合)
df['top2'] = (df['finish_position'] <= 2).astype(int)
df['rentai_rate_last3'] = (
df.groupby('horse_id')['top2']
.shift(1)
.rolling(3, min_periods=1)
.mean()
.reset_index(level=0, drop=True)
)

shift(1) を入れることで自レースを除外できる点に注意。これを忘れるとリークします。


よく使う集計テンプレ

実戦で効くものをいくつか挙げると:

  • 直近5走の 平均着順 / 連対率 / 複勝率
  • 直近3走の 上がり3F 平均 / 最速タイム
  • 同距離・同コースでの 過去成績 (件数 + 連対率)
  • 同クラス(OP・3勝・2勝...)での 連対率
  • 過去の 斤量変化と着順の相関
  • 騎手×馬の タッグ成績 (同じ騎手で過去何回連対したか)

まとめ

ローリング集計は「過去N走をどう要約するか」のテクニックですが、自レース除外と**条件絞り(コース・距離・クラス)**が肝です。素の特徴量を放り込むより、丁寧に集計した数値を投入した方が、LightGBM のスコアは目に見えて上がります。

JV-Link 取り込みデータをこの形に整形しておけば、予想モデルへの投入が一気に楽になります。

この記事をシェア

Post