利用友谊赛数据做预测的完整案例
下面我用一个足球比赛预测的案例,展示从数据到模型的完整流程,友谊赛数据的特点是:噪声大、动机弱、参考价值低,所以关键是要"数据清洗 + 特征工程 + 合理建模"。

项目背景与思路
目标:用历史友谊赛数据,预测某场比赛的胜平负(或比分)。
难点:
- 友谊赛球队可能不派主力、试阵容
- 球员动机弱,结果随机性大
- 不同时期球队实力变化大
思路:不能单纯用友谊赛当"真实实力",要构造加权特征 + 状态特征。
数据准备
假设 CSV 格式如下(matches.csv):
date,home_team,away_team,home_goals,away_goals,is_friendly,competition 2023-03-20,巴西,阿根廷,1,2,1,友谊赛 2023-06-15,法国,德国,3,0,1,友谊赛 2023-09-10,西班牙,意大利,2,1,0,欧国联 ...
Java 实现:从数据到预测
数据模型
public class Match {
public LocalDate date;
public String homeTeam;
public String awayTeam;
public int homeGoals;
public int awayGoals;
public boolean isFriendly;
public Match(LocalDate d, String h, String a, int hg, int ag, boolean f) {
this.date = d; this.homeTeam = h; this.awayTeam = a;
this.homeGoals = hg; this.awayGoals = ag; this.isFriendly = f;
}
}
加载 CSV
import java.io.*;
import java.nio.file.*;
import java.time.LocalDate;
import java.util.*;
public class DataLoader {
public static List<Match> load(String path) throws IOException {
List<Match> list = new ArrayList<>();
List<String> lines = Files.readAllLines(Paths.get(path));
for (int i = 1; i < lines.size(); i++) {
String[] p = lines.get(i).split(",");
if (p.length < 6) continue;
list.add(new Match(
LocalDate.parse(p[0]),
p[1], p[2],
Integer.parseInt(p[3]),
Integer.parseInt(p[4]),
p[5].equals("1")
));
}
list.sort(Comparator.comparing(m -> m.date));
return list;
}
}
特征工程(核心!)
关键思想:友谊赛权重低,近期比赛权重高。
public class FeatureExtractor {
// 计算球队在指定日期前的"实力分"
// 公式:加权进球差 - 加权失球差,权重 = 时间衰减 × 赛事权重
public static double teamStrength(String team, LocalDate before,
List<Match> history) {
double score = 0, weightSum = 0;
LocalDate now = before;
for (Match m : history) {
if (!m.date.isBefore(before)) break;
if (!m.homeTeam.equals(team) && !m.awayTeam.equals(team)) continue;
// 时间衰减:越近权重越高(半衰期 180 天)
long days = java.time.temporal.ChronoUnit.DAYS.between(m.date, now);
double timeW = Math.exp(-days / 180.0);
// 赛事权重:友谊赛低
double compW = m.isFriendly ? 0.4 : 1.0;
int gf = m.homeTeam.equals(team) ? m.homeGoals : m.awayGoals;
int ga = m.homeTeam.equals(team) ? m.awayGoals : m.homeGoals;
double diff = gf - ga;
score += timeW * compW * diff;
weightSum += timeW * compW;
}
return weightSum > 0 ? score / weightSum : 0;
}
// 构造 X 特征向量
public static double[] buildFeatures(Match m, List<Match> history) {
double homeStr = teamStrength(m.homeTeam, m.date, history);
double awayStr = teamStrength(m.awayTeam, m.date, history);
double strengthDiff = homeStr - awayStr;
// 近5场友谊赛胜率(同队)
double homeForm = recentForm(m.homeTeam, m.date, history, 5);
double awayForm = recentForm(m.awayTeam, m.date, history, 5);
return new double[]{
1.0, // bias
strengthDiff, // 实力差
homeStr, // 主队实力
awayStr, // 客队实力
homeForm - awayForm,// 近期状态差
1.0 // 主场优势常量
};
}
private static double recentForm(String team, LocalDate before,
List<Match> history, int k) {
List<Match> recent = new ArrayList<>();
for (Match m : history) {
if (!m.date.isBefore(before)) break;
if (m.homeTeam.equals(team) || m.awayTeam.equals(team)) recent.add(m);
}
int n = Math.min(k, recent.size());
if (n == 0) return 0;
int win = 0;
for (int i = recent.size() - n; i < recent.size(); i++) {
Match m = recent.get(i);
int gf = m.homeTeam.equals(team) ? m.homeGoals : m.awayGoals;
int ga = m.homeTeam.equals(team) ? m.awayGoals : m.homeGoals;
if (gf > ga) win++;
else if (gf == ga) win += 0;
}
return (double) win / n;
}
}
逻辑回归模型(手写梯度下降)
public class LogisticRegression {
private double[] w;
private final double lr;
private final int epochs;
public LogisticRegression(int dim, double lr, int epochs) {
this.w = new double[dim];
this.lr = lr;
this.epochs = epochs;
}
private static double sigmoid(double z) {
return 1.0 / (1.0 + Math.exp(-z));
}
public void fit(List<double[]> X, List<Integer> y) {
int n = X.size();
for (int e = 0; e < epochs; e++) {
double[] grad = new double[w.length];
for (int i = 0; i < n; i++) {
double[] xi = X.get(i);
double pred = sigmoid(dot(w, xi));
double err = pred - y.get(i);
for (int j = 0; j < w.length; j++) {
grad[j] += err * xi[j];
}
}
for (int j = 0; j < w.length; j++) {
w[j] -= lr * grad[j] / n;
}
if (e % 50 == 0) {
System.out.printf("Epoch %d loss=%.4f%n", e, logLoss(X, y));
}
}
}
public double predictProba(double[] x) {
return sigmoid(dot(w, x));
}
private double dot(double[] a, double[] b) {
double s = 0;
for (int i = 0; i < a.length; i++) s += a[i] * b[i];
return s;
}
private double logLoss(List<double[]> X, List<Integer> y) {
double loss = 0;
for (int i = 0; i < X.size(); i++) {
double p = predictProba(X.get(i));
p = Math.max(1e-9, Math.min(1 - 1e-9, p));
loss -= y.get(i) * Math.log(p) + (1 - y.get(i)) * Math.log(1 - p);
}
return loss / X.size();
}
}
训练 + 预测主流程
public class Predictor {
public static void main(String[] args) throws Exception {
List<Match> all = DataLoader.load("matches.csv");
List<double[]> X = new ArrayList<>();
List<Integer> Y = new ArrayList<>();
// 只训练"友谊赛",二分类:1=主队胜,0=客队不败
for (Match m : all) {
if (m.isFriendly) {
double[] f = FeatureExtractor.buildFeatures(m, all);
X.add(f);
Y.add(m.homeGoals > m.awayGoals ? 1 : 0);
}
}
System.out.println("训练样本数: " + X.size());
LogisticRegression model = new LogisticRegression(X.get(0).length, 0.05, 500);
model.fit(X, Y);
// 预测新比赛
Match test = new Match(LocalDate.now(), "巴西", "德国", 0, 0, true);
double p = model.predictProba(FeatureExtractor.buildFeatures(test, all));
System.out.printf("巴西 vs 德国 主胜概率: %.2f%%%n", p * 100);
}
}
进阶方案(三分类 / 比分预测)
| 目标 | 方法 |
|---|---|
| 胜平负 | Softmax 回归 / 随机森林 |
| 进球数 | 泊松回归(Poisson Regression),主客各建模 λ |
| 比分 | 双泊松模型 + Dixon-Coles 修正 |
| 概率校准 | Isotonic Regression / Platt Scaling |
泊松模型提示(Java 可用 Apache Commons Math 的 PoissonDistribution):
double lambdaHome = 1.2 + 0.3 * strengthDiff; double lambdaAway = 1.0 - 0.25 * strengthDiff; PoissonDistribution ph = new PoissonDistribution(lambdaHome); PoissonDistribution pa = new PoissonDistribution(lambdaAway); // P(2:1) = ph.probability(2) * pa.probability(1)
工程上的关键经验
- 友谊赛必须降权 —— 直接混用会严重污染模型(我用
4权重效果不错)。 - 时间衰减 —— 半衰期 90~180 天效果好;球队实力非线性变化。
- 主场优势 —— 独立特征,不要只靠实力差。
- 别过拟合友谊赛 —— 用真实赛事(世预赛、欧洲杯)做验证集。
- 概率校准 —— 输出概率时用 Brier Score 评估,而非只用准确率。
- 可尝试:XGBoost4J、Smile 库、DL4J(深度网络),但对小数据不如逻辑回归。
完整依赖建议
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
<!-- 可选:机器学习库 -->
<dependency>
<groupId>com.github.haifengl</groupId>
<artifactId>smile-core</artifactId>
<version>3.0.0</version>
</dependency>
总结一句话:友谊赛数据不能当"真实实力"用,必须通过时间衰减 + 赛事权重转化成"状态特征",再用逻辑回归或泊松模型做预测,最后用真实赛事做校验。
需要我给出完整的可编译 Maven 工程 或 Dixon-Coles 比分预测的实现吗?
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播