データ分析入門
JRDB-APIで取得したデータを使って、Pythonで基本的なデータ分析を行います。
必要なライブラリ
pip install pandas numpy matplotlib seaborn requests
Step 1: データの取得と整形
過去1ヶ月分の成績データ(/dse)と 番組データ(/dra)を取得し、 レースキーで結合して pandas の DataFrame にまとめます。 着順・IDM・人気は成績データ側、距離・トラック種別は番組データ側にあります。
import pandas as pd
import requests
from datetime import datetime, timedelta
# ダッシュボードで取得した値をそれぞれ貼り付け
API_KEY = "API_KEY" # APIキー(アプリ共通)
AUTH_KEY = "YOUR_AUTH_KEY" # 認証キー (x-user-key)
def fetch(endpoint, start_date, end_date):
"""過去データを期間指定で取得して DataFrame にする"""
url = f"https://dev.api.bigtime.world/v1/{endpoint}?api_key={API_KEY}"
headers = {
"Content-Type": "application/json",
"x-user-key": AUTH_KEY
}
payload = {
"start_racedate": start_date,
"end_racedate": end_date
}
response = requests.post(url, json=payload, headers=headers)
data = response.json()
# status は "success" / "error" の文字列
# 成功時は result.status == 200。エラー時はトップレベルに error/message が返る
if data.get("error") or data["result"]["status"] != 200:
raise Exception(data.get("message", "Unknown error"))
return pd.DataFrame(data["result"]["data"])
# 過去1ヶ月のデータを取得
end_date = datetime.now().strftime("%Y%m%d")
start_date = (datetime.now() - timedelta(days=30)).strftime("%Y%m%d")
se = fetch("dse", start_date, end_date) # 成績(着順・IDM・確定人気)
ra = fetch("dra", start_date, end_date) # 番組(距離・トラック種別・クラス)
# レース単位の条件を1頭ごとの成績に付ける
df = se.merge(
ra[['racekey', 'distance', 'track_type', 'racecourse_cd', 'class_cd']],
on='racekey',
how='left'
)
print(f"取得件数: {len(df)}件")
print(f"カラム数: {len(df.columns)}個")
print(df.head())Step 2: 基本統計量の確認
データの基本的な統計量を確認します。
# 数値カラムの基本統計量
print(df.describe())
# IDM(能力指数)の分布
print("\nIDM統計:")
print(f" 平均: {df['idm'].mean():.2f}")
print(f" 標準偏差: {df['idm'].std():.2f}")
print(f" 最小: {df['idm'].min()}")
print(f" 最大: {df['idm'].max()}")
# 着順分布
print("\n着順分布:")
print(df['order_of_finish'].value_counts().sort_index().head(10))Step 3: データの可視化
matplotlibとseabornを使ってデータを可視化します。
import matplotlib.pyplot as plt
import seaborn as sns
# 日本語フォント設定(環境に応じて変更)
plt.rcParams['font.family'] = 'MS Gothic'
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 1. IDMの分布
axes[0, 0].hist(df['idm'].dropna(), bins=30, edgecolor='black')
axes[0, 0].set_title('IDM分布')
axes[0, 0].set_xlabel('IDM')
axes[0, 0].set_ylabel('件数')
# 2. IDMと着順の関係
df_top5 = df[df['order_of_finish'] <= 5]
axes[0, 1].boxplot([
df[df['order_of_finish'] == i]['idm'].dropna()
for i in range(1, 6)
])
axes[0, 1].set_title('着順別IDM分布')
axes[0, 1].set_xlabel('着順')
axes[0, 1].set_ylabel('IDM')
# 3. 馬体重の分布
axes[1, 0].hist(df['horse_weight'].dropna(), bins=30, edgecolor='black')
axes[1, 0].set_title('馬体重分布')
axes[1, 0].set_xlabel('馬体重 (kg)')
axes[1, 0].set_ylabel('件数')
# 4. 人気と着順の関係
win_rate = df.groupby('confirmed_win_popularity').apply(
lambda x: (x['order_of_finish'] == 1).sum() / len(x) * 100
).head(10)
axes[1, 1].bar(win_rate.index, win_rate.values)
axes[1, 1].set_title('人気別勝率')
axes[1, 1].set_xlabel('人気')
axes[1, 1].set_ylabel('勝率 (%)')
plt.tight_layout()
plt.savefig('analysis_result.png', dpi=150)
plt.show()Step 4: 相関分析
各指標と着順の相関を分析します。
# 分析対象のカラム
target_columns = [
'idm', 'horse_weight', 'confirmed_win_popularity',
'confirmed_win_odds', 'order_of_finish'
]
# 相関行列の計算
correlation = df[target_columns].corr()
# ヒートマップで可視化
plt.figure(figsize=(8, 6))
sns.heatmap(
correlation,
annot=True,
cmap='coolwarm',
center=0,
fmt='.2f'
)
plt.title('相関行列')
plt.tight_layout()
plt.savefig('correlation_heatmap.png', dpi=150)
plt.show()
# 着順との相関(絶対値でソート)
print("\n着順との相関係数:")
correlations = correlation['order_of_finish'].drop('order_of_finish')
print(correlations.abs().sort_values(ascending=False))分析のポイント
- • IDMが高い馬は着順が良い傾向がある(負の相関)
- • 人気と着順には強い相関がある
- • オッズが低い(人気がある)馬ほど着順が良い
Step 5: 条件別分析
芝・ダート、距離などの条件別に分析します。
# トラック種別(芝/ダート)で分析
def analyze_by_track(df):
# track_type: 1=芝, 2=ダート, 3=障害(/dra の番組データ)
df['track_label'] = df['track_type'].astype(str).map(
{'1': '芝', '2': 'ダート', '3': '障害'}
)
result = df.groupby('track_label').agg({
'idm': 'mean',
'horse_weight': 'mean',
'order_of_finish': lambda x: (x == 1).sum() / len(x) * 100
}).rename(columns={'order_of_finish': 'win_rate'})
return result
track_analysis = analyze_by_track(df)
print("トラック別分析:")
print(track_analysis)
# 距離別分析
def analyze_by_distance(df):
# 距離カテゴリを作成
df['distance_category'] = pd.cut(
df['distance'].astype(int),
bins=[0, 1400, 1800, 2200, 4000],
labels=['短距離', 'マイル', '中距離', '長距離']
)
result = df.groupby('distance_category').agg({
'idm': 'mean',
'horse_weight': 'mean',
'order_of_finish': lambda x: (x == 1).sum() / len(x)
})
return result
distance_analysis = analyze_by_distance(df)
print("\n距離別分析:")
print(distance_analysis)