You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在RStan中实现贝叶斯足球模型?RJAGS可行但RStan报错

贝叶斯足球进球模型的RStan实现修正

原代码核心问题总结

  • Stan不允许变量名包含.,需替换为下划线(如att.star→att_star)
  • att、def为球队级参数,需声明为向量而非单个实数
  • for循环缺少大括号,导致部分代码未纳入循环范围
  • Stan正态分布参数为均值+标准差,而非JAGS的均值+精度,需做转换
  • 参数中心化逻辑需放在transformed parameters块实现,不能直接在model块赋值
  • 未提前声明lambda_home、lambda_away的变量类型

修正后的完整RStan代码(保存为football_model.stan)

// 数据块
data {
  int<lower=1> n_games;
  int<lower=1> n_teams;
  int<lower=0> FTHG[n_games]; // 主场进球数
  int<lower=0> FTAG[n_games]; // 客场进球数
  int<lower=1, upper=n_teams> HomeTeam[n_games]; // 主场球队索引
  int<lower=1, upper=n_teams> AwayTeam[n_games]; // 客场球队索引
}

// 参数块:声明原始参数
parameters {
  real home_adv; // 主场优势
  real mu; // 进攻/防守参数的先验均值
  real<lower=0> tau; // 进攻/防守参数的先验精度(转换为标准差使用)
  vector[n_teams] att_star; // 未中心化的进攻参数
  vector[n_teams] def_star; // 未中心化的防守参数
}

// 转换参数块:实现中心化约束与进球率计算
transformed parameters {
  vector[n_teams] att; // 中心化后的进攻参数
  vector[n_teams] def; // 中心化后的防守参数
  matrix[n_teams, n_teams] lambda_home; // 主场进球率矩阵
  matrix[n_teams, n_teams] lambda_away; // 客场进球率矩阵
  
  // 中心化:让所有球队的进攻/防守参数均值为0
  att = att_star - mean(att_star);
  def = def_star - mean(def_star);
  
  // 计算每场比赛的进球率
  for (home_i in 1:n_teams) {
    for (away_i in 1:n_teams) {
      lambda_home[home_i, away_i] = exp(home_adv + att[home_i] - def[away_i]);
      lambda_away[home_i, away_i] = exp(att[away_i] - def[home_i]);
    }
  }
}

// 模型块:定义似然和先验
model {
  // 似然:进球数服从泊松分布
  for (i in 1:n_games) {
    FTHG[i] ~ poisson(lambda_home[HomeTeam[i], AwayTeam[i]]);
    FTAG[i] ~ poisson(lambda_away[HomeTeam[i], AwayTeam[i]]);
  }
  
  // 先验分布:转换JAGS的精度为Stan的标准差
  home_adv ~ normal(0.2, sqrt(1/0.0625));
  mu ~ normal(0, sqrt(1/0.0625));
  tau ~ gamma(0.01, 0.01);
  att_star ~ normal(mu, sqrt(1/tau));
  def_star ~ normal(mu, sqrt(1/tau));
}

对应的R预处理与运行代码

# 1. 获取并整理数据
data_set = read.csv('https://www.football-data.co.uk/mmz4281/2223/E0.csv')
data_set = data_set[, c('HomeTeam', 'AwayTeam', 'FTHG', 'FTAG')]

# 2. 预处理为Stan输入格式
teams = unique(c(data_set$HomeTeam, data_set$AwayTeam))
stan_data = list(
  n_games = nrow(data_set),
  n_teams = length(teams),
  FTHG = data_set$FTHG,
  FTAG = data_set$FTAG,
  HomeTeam = as.numeric(factor(data_set$HomeTeam, levels = teams)),
  AwayTeam = as.numeric(factor(data_set$AwayTeam, levels = teams))
)

# 3. 编译并运行Stan模型
library(rstan)
rstan_options(auto_write = TRUE)
options(mc.cores = parallel::detectCores())

model = stan_model("football_model.stan")
fit = sampling(model, data = stan_data, chains = 3, warmup = 1000, iter = 2000, thin = 10)

# 查看模型结果
print(fit, pars = c("home_adv", "att", "def", "mu", "tau"))

关键修正说明

  1. 命名规范:严格遵循Stan变量命名规则,替换所有.为_
  2. 维度匹配:将球队级参数声明为vector[n_teams],匹配球队数量
  3. 分布转换:JAGS的dnorm(均值, 精度)对应Stan的normal(均值, 1/sqrt(精度))
  4. 逻辑拆分:将参数中心化、进球率计算移到transformed parameters块,确保Stan正确识别计算逻辑
  5. 语法严谨:给for循环添加大括号,避免代码执行范围错误
  6. 变量声明:提前声明矩阵类型的进球率变量,消除编译时的未定义错误

内容的提问来源于stack exchange,提问作者Juan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:49:54