按分组变量实现数据集变数量抽样的报错问题求助
按分组变量动态抽样的问题及解决方案
需求:根据数据集分组内的指定变量,对每个组抽取对应数量的样本。
原始代码与报错
最初使用的代码在旧版本dplyr中可运行,但当前版本报错:
data <- data.frame(id = seq(1, 10000), group = sample(c(1:3), 100, replace = TRUE)) data <- data %>% mutate(n = group*2) data <- data %>% group_by(group) %>% do(sample_n(., n))
报错信息:
Error in `sample_n()`: ! Can't compute indices. Caused by error in `size <= n || replace`: ! 'length = 3800' in coercion to 'logical(1)' Run `rlang::last_trace()` to see where the error occurred.
尝试的替代方法及新问题
尝试使用slice_sample替代sample_n,在小数据集(甚至200万行)中可行:
data <- data.frame(id = seq(1, 2000000), group = sample(c(1:10000), 2000000, replace = TRUE)) data <- data %>% mutate(n = group*2) data <- data %>% group_by(group) %>% do(slice_sample(., n=unique(.$n)))
但处理实际大数据集(行数超过223000)时触发新错误:
test <- bano_tirage[c(100000:3240000),] bano_sample <- test %>% group_by(nom_commune) %>% group_modify(~ slice_sample(.x, n = unique(.x$pop_contact)))
报错信息:
Error in `slice_sample()`: ! `n` must be a round number, not an integer vector. Run `rlang::last_trace()` to see where the error occurred.
有效解决方案
方案1:dplyr优化版(处理向量与边界问题)
问题根源是部分分组内的pop_contact并非单一值,导致unique(.x$pop_contact)返回向量,同时未处理抽样数量超过组内行数的情况。优化代码如下:
bano_sample <- test %>% group_by(nom_commune) %>% group_modify(~ { # 取组内第一个pop_contact值作为抽样数量,确保为单值 sample_size <- first(.x$pop_contact) # 避免抽样数量超过组内实际行数,可选replace=TRUE允许重复抽样 slice_sample(.x, n = min(sample_size, nrow(.x)), replace = FALSE) }) %>% ungroup()
方案2:data.table高效版(适合超大数据集)
data.table的分组操作效率远高于dplyr::group_modify,更适合百万级以上数据集:
library(data.table) setDT(test) bano_sample <- test[, .SD[sample(.N, min(first(pop_contact), .N))], by = nom_commune]
关键说明:
first(pop_contact):确保每个分组仅取一个抽样数量,避免向量输入报错min(sample_size, .N):当抽样数量大于组内行数时,自动取组内所有样本,也可根据需求设置replace=TRUE启用重复抽样data.table的.SD代表当前分组的子数据集,sample(.N, ...)直接对子集行号抽样,性能更优
内容的提问来源于stack exchange,提问作者user22071494
相关产品推荐
相关产品推荐

