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

caret包train()与RMSE()计算泊松模型交叉验证RMSE差异疑问

差异原因
  • 预测值尺度不匹配:泊松回归属于广义线性模型,glm()默认调用predict()返回的是对数连接函数转换后的线性预测量(对数尺度),而caret的train()函数计算RMSE时,会自动将广义线性模型的预测值转换为原始响应尺度。你手动计算时没有添加type = "response"参数,相当于用对数尺度的预测值和原始尺度的观测值计算RMSE,数值自然差异极大。而普通线性回归没有连接函数转换,predict()默认返回的就是原始响应尺度的结果,所以不会出现差异。
  • 折划分逻辑不符合标准k折规则:你使用sample(1:10, nrow(exd), replace = TRUE)生成折标签,属于有放回抽样,会导致部分样本不会出现在测试集、部分样本多次出现在测试集,和caret的repeatedcv采用的无放回划分(每轮重复中所有样本恰好属于1个测试集)逻辑不一致,也会带来结果偏差。
手动交叉验证方法的修正方案

原手动实现思路可用,修改两处问题即可正常使用:

  1. 计算测试集预测值时添加type = "response"参数,确保预测值和观测值尺度一致
  2. 替换折标签生成逻辑,使用无放回抽样生成标准k折划分

修正后参考代码如下:

library(caret)
library(datasets)

exd <- warpbreaks

##k-fold cross validation
Repeats <- 100
cv_repeat_num <- Repeats / 10

# 固定随机种子方便复现
set.seed(123)
the_control <- trainControl(method = "repeatedcv", number = 10, repeats = cv_repeat_num)
cv_ex <- train(breaks~wool+tension, data = exd, method = "glm",family= "poisson", trControl = the_control)

m_ex <- glm(data = exd, breaks~wool+tension, family = "poisson")
results <- numeric(10 * cv_repeat_num)

set.seed(123)
for(j in 0:(cv_repeat_num - 1)){
  # 改为无放回划分,每轮重复每个样本恰好属于1个折
  cv_group <- sample(rep(1:10, length.out = nrow(exd)))
  for(i in 1:10){
    train_data <- exd[cv_group != i, ]
    test_data <- exd[cv_group == i, ]
    m_ex <- update(m_ex, data = train_data)
    results[j * 10 + i] <- RMSE(
      # 添加type参数获取原始响应尺度预测值
      predict(m_ex, newdata = test_data, type = "response"),
      test_data$breaks)
  }
}
#RMSE from manual cross validation
mean(results)
#RMSE from train function
mean(cv_ex$resample$RMSE)

修正后两者的RMSE结果会基本一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 22:27:05