競馬予想で当てるためのAI競馬のため、まずは過去データを学習するプログラムを作成したいと考えます。
先ずは、初期設定や、データ読み込み、そして前処理について説明します。
「GPU/CPU自動切替でどこでも動く学習環境」
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("CUDA available:", torch.cuda.is_available())
print("Torch version:", torch.__version__)
if torch.cuda.is_available() and torch.cuda.device_count() > 0:
print("GPU:", torch.cuda.get_device_name(0))
else:
print("GPU: None")
最初に torch.cuda.is_available()
を使って、CUDA(GPU)が使えるかを判定。
使えるなら GPU 名を表示し、以降のテンソル/モデルは device
に合わせて配置します。これで同じスクリプトをどの環境でも動かせます。
ポイント:GPU があれば学習/推論が爆速。なければ自動で CPU にフォールバック。
「時系列の肝は“相対化”と“欠損/型の堅牢化”」
data = pd.read_csv(
"horse_db.csv",
encoding="utf-8-sig",
index_col=False,
dtype={"レースID":str,"騎手ID": int, "調教師ID": int, "馬主ID": str}
)
このコードは pandas の read_csv()
関数を用いて、競馬データベース horse_db.csv
を DataFrame として読み込む処理です。
- ファイル指定:
"horse_db.csv"
を入力ソースとする。 - 文字コード:
encoding="utf-8-sig"
により、日本語列名やデータの文字化けを防止。 - インデックス:
index_col=False
により、すべての列を通常のデータ列として読み込む。 - データ型指定:
dtype
引数で主要キーを明示的に型付けする。レースID
→ 文字列型(str
)騎手ID
・調教師ID
→ 整数型(int
)馬主ID
→ 文字列型(str
)
これにより、ID カラムが誤って数値として扱われるのを防ぎ、データベースとしての整合性を保つことができる。
「効く派生特徴ベスト10:距離カテゴリ、斤量比、クロス特徴…」
print("✅ 過去データの前処理")
epoch_start1 = time.time()
sequence_length = 3
data["日付"] = pd.to_datetime(data["日付"])
# 日数差計算
data["日数差"] = data.groupby("馬ID")["日付"].diff().dt.days.fillna(0).astype(int)
data["日数差_norm"] = data["日数差"] / max(data["日数差"].max(), 1)
# 不要列削除
data.drop(columns=["レース名", "タイプ", "着差", "賞金", "馬主ID", "枠番", "左右", "クラス"], inplace=True)
# NaNの走破タイムを削除
data = data[data["走破タイム"].notna()]
# 数値変換(まとめて)
fill_values = {"着順": 0, "斤量": 55.0, "馬体重": 470.0, "上り": 0}
data = data.assign(**{col: pd.to_numeric(data[col], errors="coerce").fillna(val) for col, val in fill_values.items()})
data = data[data["着順"] > 0]
# 新しい特徴量
data["斤量_馬体重比"] = data["斤量"] / (data["馬体重"] + 1e-3)
data["性"] = data["性齢"].str[0]
data["年齢"] = data["性齢"].str[1:].astype(int)
# 年齢層(np.selectで高速化)
data["年齢層"] = np.select(
[data["年齢"] <= 3, data["年齢"] <= 5],
["若駒", "壮年"],
default="ベテラン"
)
# 距離カテゴリ(np.selectで高速化)
data["距離カテゴリ"] = np.select(
[data["距離"] <= 1400, data["距離"] <= 1800, data["距離"] <= 2200],
["スプリント", "マイル", "中距離"],
default="長距離"
)
# クロスカテゴリ(value_countsを1回ずつ)
def create_cross_feature(df, col1, col2, min_freq=30):
cross = df[col1].astype(str) + "_" + df[col2].astype(str)
freq = cross.value_counts()
return np.where(cross.isin(freq[freq >= min_freq].index), cross, "other")
cross_features = {
"距離Cx芝ダ": ("距離カテゴリ", "芝ダ"),
"天候x馬場": ("天候", "馬場"),
"競馬場x芝ダ": ("競馬場", "芝ダ"),
"年齢層x芝ダ": ("年齢層", "芝ダ"),
"性x距離カテゴリ": ("性", "距離カテゴリ")
}
for new_col, (c1, c2) in cross_features.items():
data[new_col] = create_cross_feature(data, c1, c2)
# 脚質(正規表現で高速化)
data["脚質"] = data["通過"].str.extract(r"^(\d+)", expand=False).astype(float)
data["脚質"] = pd.cut(data["脚質"], bins=[0, 3, 6, 10, np.inf], labels=["逃げ", "先行", "差し", "追込"]).astype(str)
data["脚質"] = data["脚質"].fillna("不明")
# 好成績
data["好成績"] = (data["着順"] <= 3).astype(int)
このコードは、競馬データの 前処理と特徴量生成 を行うものです。主な処理内容は以下の通りです。
- 日付と休養指数:
日付
を日付型に変換し、同一馬ごとの前走からの日数差を算出して正規化。 - データ整理: 不要な列を削除し、
走破タイム
が欠損している行を除外。着順・斤量・馬体重・上り
は数値化と欠損補完を実施。 - 派生特徴の作成:
斤量_馬体重比
で負荷指標を算出性齢
から性別と年齢を抽出し、年齢層
を若駒・壮年・ベテランに分類- 距離をスプリント・マイル・中距離・長距離にカテゴリ化
- 交差特徴量:
距離カテゴリ×芝ダ
や天候×馬場
などの組合せ特徴を作成し、出現頻度が少ないものは「other」に統合。 - 脚質の抽出:
通過
欄の先頭順位を基に、逃げ・先行・差し・追込の4区分に分類。欠損は「不明」とする。 - 成績指標: 3着以内を「好成績=1」とするバイナリ列を追加。
これにより、機械学習や統計解析に利用できる クリーンで説明力のあるデータセット が得られるようになります。
コメント