本文目录导读:

这是一个关于利用历史同赔数据进行预测的Python案例教程,我会提供一个完整的、可运行的示例,涵盖数据获取、特征工程、模型训练和预测。
核心思路:什么是同赔数据预测?
同赔数据是指不同博彩公司(如威廉希尔、立博、Bet365等)对同一场比赛开出的赔率组合,核心逻辑是:
- 如果当前比赛的赔率组合与历史某些比赛的赔率高度相似,那么历史比赛的结果分布可作为预测参考。
- 通过统计相似赔率组合下的历史胜平负概率,来预测当前比赛。
完整Python案例
下面是一个完整的预测流程,以足球比赛预测为例:
import pandas as pd
import numpy as np
from sklearn.neighbors import NearestNeighbors
from sklearn.preprocessing import StandardScaler
from collections import Counter
import warnings
warnings.filterwarnings('ignore')
# =====================================================
# 第一部分:模拟历史赔率数据(实际使用时替换为真实数据)
# =====================================================
np.random.seed(42)
def generate_historical_data(n_samples=5000):
"""生成模拟历史比赛数据"""
historical_data = []
for _ in range(n_samples):
# 模拟三条主赔率(如威廉希尔、立博、Bet365)
# 主胜、平局、客胜赔率
home_win = np.random.uniform(1.1, 5.0)
# 平局赔率通常介于主胜和客胜之间
draw = np.random.uniform(2.5, 4.5)
away_win = np.random.uniform(1.5, 6.0)
# 根据赔率计算隐含概率(归一化)
probs = [1/home_win, 1/draw, 1/away_win]
probs = np.array(probs) / sum(probs)
# 根据概率随机生成比赛结果:0=主胜, 1=平局, 2=客胜
outcome = np.random.choice([0, 1, 2], p=probs)
historical_data.append({
'home_win_odds_EU': home_win,
'draw_odds_EU': draw,
'away_win_odds_EU': away_win,
'outcome': outcome
})
return pd.DataFrame(historical_data)
# =====================================================
# 第二部分:同赔匹配与预测核心类
# =====================================================
class SameOddsPredictor:
"""
同赔预测模型:
1. 使用KNN寻找最相似的K场比赛
2. 统计这些比赛的胜负平概率
3. 输出预测概率
"""
def __init__(self, k=20, similarity_threshold=0.0001):
self.k = k
self.scaler = StandardScaler()
self.knn = None
self.historical_data = None
def prepare_features(self, df):
"""标准化赔率特征"""
feature_cols = ['home_win_odds_EU', 'draw_odds_EU', 'away_win_odds_EU']
features = df[feature_cols].values
return self.scaler.transform(features)
def fit(self, historical_df):
"""训练模型:拟合KNN"""
self.historical_data = historical_df.copy()
features = self.prepare_features(historical_df)
self.knn = NearestNeighbors(n_neighbors=self.k, metric='euclidean')
self.knn.fit(features)
return self
def predict(self, current_odds, return_top=True):
"""
预测当前比赛结果概率
参数:
- current_odds: 当前赔率,格式为 [主胜, 平局, 客胜]
- return_top: 是否返回最相似的前几场比赛详情
返回:
- 预测概率字典
"""
# 转换输入为DataFrame
current_df = pd.DataFrame([current_odds],
columns=['home_win_odds_EU', 'draw_odds_EU', 'away_win_odds_EU'])
# 标准化当前赔率
current_features = self.scaler.transform(current_df.values)
# 找出K个最近邻
distances, indices = self.knn.kneighbors(current_features)
indices = indices[0]
distances = distances[0]
# 提取最近邻的比赛结果
nearest_outcomes = self.historical_data.iloc[indices]['outcome'].values
# 统计频率作为概率
counts = Counter(nearest_outcomes)
total = len(nearest_outcomes)
probs = {
'home_win': counts.get(0, 0) / total,
'draw': counts.get(1, 0) / total,
'away_win': counts.get(2, 0) / total,
'most_likely': np.argmax([counts.get(0,0), counts.get(1,0), counts.get(2,0)])
}
# 附加相似度信息
probs['similarity'] = {
'max_similarity': 1 - max(distances),
'avg_similarity': 1 - np.mean(distances),
'similar_targets': len(indices)
}
if return_top:
# 返回最相似的几场比赛详细信息
top_matches = self.historical_data.iloc[indices].copy()
top_matches['distance'] = distances
top_matches = top_matches.sort_values('distance').head(self.k)
probs['top_matches'] = top_matches
return probs
# =====================================================
# 第三部分:执行预测
# =====================================================
if __name__ == "__main__":
# 1. 生成模拟历史数据 (5000场历史比赛)
print("生成模拟历史数据中...")
historical_df = generate_historical_data(5000)
print(f"历史数据形状: {historical_df.shape}")
print(f"历史结果分布:\n{historical_df['outcome'].value_counts(normalize=True)}")
# 2. 训练模型
print("\n训练同赔预测模型...")
predictor = SameOddsPredictor(k=30) # 取30场最相似的比赛
predictor.fit(historical_df)
print("模型训练完成!")
# 3. 模拟一场当前比赛(需要预测的比赛)
current_match_odds = [1.75, 3.40, 4.80] # 主胜1.75,平局3.40,客胜4.80
print(f"\n当前比赛赔率: 主胜={current_match_odds[0]},平局={current_match_odds[1]},客胜={current_match_odds[2]}")
# 4. 进行预测
prediction = predictor.predict(current_match_odds, return_top=True)
print("\n===== 预测结果 =====")
print(f"主胜概率: {prediction['home_win']:.2%}")
print(f"平局概率: {prediction['draw']:.2%}")
print(f"客胜概率: {prediction['away_win']:.2%}")
# 解读最有倾向的结果
outcome_labels = ['主胜', '平局', '客胜']
predicted_outcome = outcome_labels[prediction['most_likely']]
print(f"\n最可能的结果: {predicted_outcome}")
print(f"\n相似度信息:")
print(f" - 平均相似度: {prediction['similarity']['avg_similarity']:.4f}")
print(f" - 最相似匹配度: {prediction['similarity']['max_similarity']:.4f}")
# 5. 查看最相似的历史比赛
print("\n===== 最相似的10场比赛 =====")
top_10 = prediction['top_matches'].head(10)
for i, row in top_10.iterrows():
result_labels = ['主胜', '平局', '客胜']
print(f"赔率[{row['home_win_odds_EU']:.2f}, {row['draw_odds_EU']:.2f}, "
f"{row['away_win_odds_EU']:.2f}] -> 实际结果: {result_labels[row['outcome']]} "
f"(相似度: {1-row['distance']:.3f})")
扩展:从真实数据源获取赔率
import requests
import time
def fetch_real_odds_from_api(start_date, end_date):
"""
从公开API获取历史赔率数据
例如使用 football-data 或 odds-api 等免费接口
"""
# 这里以the-odds-api为例(需要注册获取API key)
API_KEY = "YOUR_API_KEY_HERE"
base_url = "https://api.the-odds-api.com/v4/sports/soccer/odds/"
params = {
'apiKey': API_KEY,
'regions': 'eu',
'markets': 'h2h',
'oddsFormat': 'decimal',
'dateFormat': 'iso'
}
all_data = []
# 示例:获取最近30天的数据
for i in range(30):
date = (pd.Timestamp.today() - pd.Timedelta(days=i+1)).strftime('%Y-%m-%d')
params['commenceTimeFrom'] = f"{date}T00:00:00Z"
params['commenceTimeTo'] = f"{date}T23:59:59Z"
try:
response = requests.get(base_url, params=params)
if response.status_code == 200:
games = response.json()
for game in games:
if 'bookmakers' in game:
for bookmaker in game['bookmakers']:
for market in bookmaker['markets']:
if market['key'] == 'h2h':
outcomes = {outcome['name']: outcome['price']
for outcome in market['outcomes']}
all_data.append({
'home_win_odds': outcomes.get('Home', None),
'draw_odds': outcomes.get('Draw', None),
'away_win_odds': outcomes.get('Away', None),
'bookmaker': bookmaker['key'],
'game_id': game['id']
})
except Exception as e:
print(f"获取日期 {date} 数据失败: {e}")
time.sleep(1) # 避免API限流
return pd.DataFrame(all_data)
实际应用建议
- 数据清洗:真实数据通常需要处理赔率波动(取平均值或中位数)、缺失值填充
- 特征工程:
- 增加变量:欧赔、初盘/终盘差异、多家公司赔率差值
- 增加历史战绩特征
- 模型优化:
- 调整K值(用交叉验证寻找最优K)
- 使用加权投票(距离越近权重越高)
- 验证方法:用时间序列交叉验证(前70%训练,后30%验证)
# 加权投票改进示例
def weighted_prediction(self, current_odds, k=20, power=2):
"""使用距离倒数作为权重的加权预测"""
features = self.scaler.transform(pd.DataFrame([current_odds]).values)
distances, indices = self.knn.kneighbors(features, n_neighbors=k)
outcomes = self.historical_data.iloc[indices[0]]['outcome'].values
weights = 1 / (distances[0] ** power + 1e-10) # 距离越近权重越大
# 加权概率计算
prob_home = np.sum(weights[outcomes == 0]) / np.sum(weights)
prob_draw = np.sum(weights[outcomes == 1]) / np.sum(weights)
prob_away = np.sum(weights[outcomes == 2]) / np.sum(weights)
return {'home_win': prob_home, 'draw': prob_draw, 'away_win': prob_away}
注意事项
- 样本量:同赔数据预测效果依赖历史样本,一般建议至少500-1000场有效记录
- 赔率时效性:赔率会随时间变化,建议使用开赛前最终赔率或平均值
- 市场差异:不同联赛/赛事特征不同,建议区分比赛级别建模
- 风险提示:任何预测模型都有局限性,建议设置止损,切不可盲目重注
这个案例是一个完整的基础框架,你可以根据自己的数据格式调整特征列名和结果编码,真实应用时建议用历史数据进行回测,验证模型的稳定性和有效性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播