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

多组数据下模型性能对分组折构成的敏感性分析及SuperLearner适配问题

问题解决:多组交叉验证折生成与SuperLearner分折性能提取

一、6组情况下生成不同组占比的交叉验证折

针对6组数据,我们需要生成训练集组占比从完全均衡到极端不均衡的交叉验证折,核心是控制各组采样比例的偏离程度,同时保持训练集总大小稳定。

实现代码

library(tidyverse)
library(caret)
library(SuperLearner)

# 6组示例数据
df <- tibble(id = 1:3000,
             outcome = rnorm(3000),
             feature1 = rnorm(3000),
             feature2 = rnorm(3000),
             group = as.character(rep(1:6, each = 500)))

# 按组拆分数据索引
group_indices <- split(df$id, df$group)
n_groups <- length(group_indices)
# 均衡状态下每组的基准占比(1/6)
base_prop <- 1/n_groups
# 定义偏离均衡的程度序列:0=完全均衡,0.8=极端不均衡
deviation_seq <- seq(0, 0.8, by = 0.05)
# 每个偏离程度生成100个重复折
n_repeats <- 100

folds <- list()
fold_idx <- 1

for (dev in deviation_seq) {
  for (rep in 1:n_repeats) {
    # 随机选择一个主导组,分配更高占比
    dominant_group <- sample(n_groups, 1)
    # 初始化比例:非主导组按偏离程度降低占比
    props <- rep(base_prop * (1 - dev), n_groups)
    # 主导组占比 = 基准占比 + 其他组让渡的比例
    props[dominant_group] <- base_prop + dev * (n_groups - 1)
    
    # 修正比例总和为1(消除浮点误差)
    props <- props / sum(props)
    
    # 固定训练集总大小为2000,计算每组采样数量
    train_size_total <- 2000
    sample_sizes <- round(props * train_size_total)
    # 修正采样数量总和误差
    sample_sizes[dominant_group] <- sample_sizes[dominant_group] + (train_size_total - sum(sample_sizes))
    
    # 对每组进行无放回采样
    sampled_ids <- map2(group_indices, sample_sizes, ~sample(.x, size = .y, replace = FALSE)) %>% unlist()
    
    # 将采样结果存入折列表
    folds[[paste0("Fold_dev_", round(dev,2), "_rep_", rep)]] <- sampled_ids
    fold_idx <- fold_idx + 1
  }
}

关键说明

  • 用deviation_seq控制偏离均衡的程度,数值越大,某一组占比越高,其余组占比越低
  • 随机选择主导组,避免仅偏向单一组的偏差
  • 固定训练集总大小,排除样本量对模型性能的干扰

二、提取SuperLearner的分折性能指标

SuperLearner默认输出整体性能,可通过两种方式获取分折性能:

方法1:利用CV.SuperLearner提取结果

CV.SuperLearner会返回每个观测的预测值,结合自定义折划分计算分折性能:

# 准备特征与结果变量
X <- df %>% select(feature1, feature2)
Y <- df$outcome

# 将训练集折转换为测试集折(CV.SuperLearner要求输入测试集索引)
cv_folds <- lapply(folds, function(train_ids) setdiff(df$id, train_ids))

# 运行交叉验证SuperLearner
cv_sl <- CV.SuperLearner(Y = Y, X = X,
                         SL.library = c("SL.lm", "SL.ranger"),
                         foldList = cv_folds,
                         verbose = FALSE)

# 计算每个折的R²与组占比偏离程度
perf_sl <- map_dfr(seq_along(cv_folds), function(idx) {
  test_ids <- cv_folds[[idx]]
  y_true <- Y[test_ids]
  y_pred <- cv_sl$pred[, idx]
  
  # 计算R²
  r2 <- 1 - sum((y_true - y_pred)^2) / sum((y_true - mean(y_true))^2)
  
  # 计算训练集组占比的偏离程度(偏差平方和)
  train_ids <- folds[[idx]]
  train_props <- df %>% filter(id %in% train_ids) %>% count(group) %>% mutate(prop = n/length(train_ids)) %>% pull(prop)
  deviation <- sum((train_props - base_prop)^2)
  
  tibble(fold_name = names(folds)[idx],
         deviation = deviation,
         r2 = r2)
})

# 可视化性能与偏离程度的关系
ggplot(perf_sl, aes(deviation, r2)) + 
  labs(y = "R²", x = "组占比偏离均衡程度(偏差平方和)") +
  geom_smooth(method = "lm") +
  geom_point(alpha = .75) + 
  ggpubr::stat_cor() +
  theme_minimal()

方法2:手动循环训练并计算性能

若需更灵活的控制,可手动遍历每个折训练模型并计算性能:

perf_sl_manual <- map_dfr(seq_along(folds), function(idx) {
  train_ids <- folds[[idx]]
  test_ids <- setdiff(df$id, train_ids)
  
  # 拆分训练/测试数据
  X_train <- X[train_ids, ]
  Y_train <- Y[train_ids]
  X_test <- X[test_ids, ]
  Y_test <- Y[test_ids]
  
  # 训练SuperLearner
  sl_fit <- SuperLearner(Y = Y_train, X = X_train,
                         SL.library = c("SL.lm", "SL.ranger"))
  
  # 预测并计算R²
  y_pred <- predict(sl_fit, newdata = X_test)$pred
  r2 <- 1 - sum((Y_test - y_pred)^2) / sum((Y_test - mean(Y_test))^2)
  
  # 计算组占比偏离程度
  train_props <- df %>% filter(id %in% train_ids) %>% count(group) %>% mutate(prop = n/length(train_ids)) %>% pull(prop)
  deviation <- sum((train_props - base_prop)^2)
  
  tibble(fold_name = names(folds)[idx],
         deviation = deviation,
         r2 = r2)
})

三、补充说明

  • 组占比偏离程度的衡量可替换为基尼系数、最大组占比与基准占比的差值等,按需选择
  • CV.SuperLearner效率更高,适合大样本;手动循环更灵活,便于添加自定义逻辑
  • 始终保持训练集大小一致,确保组占比是影响模型性能的唯一变量

内容的提问来源于stack exchange,提问作者Dr. Fabian Habersack

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 23:50:29