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

nest+rsample::bootstraps+unnest与rsample::group_bootstraps是否等价?

group_bootstraps与nest+bootstraps替代方案的等价性验证

问题背景

发现rsample包的group_bootstraps()函数运行速度远慢于bootstraps(),因此采用tidyr的nest()+unnest()组合作为替代方案,现验证两种实现是否等价,以及是否存在遗漏细节。

代码示例

library(tidyr)
library(rsample)

dat <- tibble(x = rep(1:1000, 2), y = 1:2000) 

f <- function(df, column){
  tibble(
    "estimate" = mean(pull(df, {{column}})),
    "term" = "mean"
  )
}

# 版本1:使用rsample::group_bootstraps
start_time <- Sys.time()

dat %>%
  group_bootstraps(group = x, times = 10) %>%
  mutate(mean_stats = purrr::map(splits, ~ f(analysis(.), y))) %>% 
  int_pctl(mean_stats)

print(difftime(Sys.time(), start_time, units = "secs"))

# 版本2:使用tidyr nest + unnest替代
start_time <- Sys.time()

dat %>%
  nest(.by = x) %>%
  bootstraps(times = 10) %>%
  mutate(mean_stats = purrr::map(splits, ~ f(unnest(analysis(.), data), y))) %>% 
  int_pctl(mean_stats)

print(difftime(Sys.time(), start_time, units = "secs"))

运行时间对比

  • 版本1耗时:超过9秒
  • 版本2耗时:不足0.5秒

等价性分析

两种实现在抽样逻辑和统计结果上完全等价:

  • group_bootstraps(group = x)的核心逻辑是:以x对应的分组为单位进行有放回抽样,每个bootstrap样本由若干完整分组的观测组成。
  • 版本2的逻辑是:先通过nest(.by = x)将每个x分组的数据嵌套为单独行,再用bootstraps()对这些分组行进行有放回抽样,最后通过unnest()展开为完整观测集。本质上同样是基于分组的有放回抽样,和group_bootstraps()的抽样规则完全一致。

后续对每个bootstrap样本计算y的均值、生成置信区间的流程也完全相同,因此最终的统计结果(均值估计值、置信区间)会完全一致。

潜在遗漏细节

  1. 抽样索引的记录方式:
    • group_bootstraps()生成的splits对象中,记录的是原始数据中每个观测是否被选中;
    • 版本2的splits记录的是嵌套后分组行的选中状态,再通过unnest()展开为观测集。但两种方式最终生成的分析数据集完全一致,不影响统计结果。
  2. 分组异常情况的处理:
    • 如果原始数据中存在空分组、观测数为0的分组,两种方式都会自动忽略这类无效分组,不影响抽样逻辑;
    • 若分组内观测数不一致,两种方式均以分组为单位抽样,不会改变分组内的观测构成,结果仍等价。
  3. 性能差异的根源:
    • group_bootstraps()内部可能针对每个分组单独处理抽样逻辑,带来了额外的循环开销;
    • 版本2通过nest()将分组转换为行级数据,一次性完成抽样,避免了分组级别的循环,因此效率大幅提升。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:36:12