如何修改for循环实现每次随机移除完整Transect并计算类别频率?
问题
我有一个较大的数据集,当前用for循环每次移除每个Transect的一行,并计算Category的频率。现在想改成每次迭代随机移除整个Transect(比如第一次移除所有Transect 3,第二次移除所有Transect 1)。以下是示例数据集和现有代码,请问怎么实现?
示例数据集
Transect <- c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3) Category <- c("S","S","S","C","T","S","SP","T", "C", "T","S","SP","T","S","C") dat <- data.frame(Transect,Category)
现有代码
for (q in 1:2) { for ( i in 0:5){ #if (i>0) df <- dat2 %>% group_by(Transect) %>% sample_n(n() - i, replace = TRUE) %>% ungroup() c <- df %>% group_by(Category) %>% summarise(n = n(), replace=TRUE) %>% mutate(freq = n / sum(n), total=55-i) if (i==0){ tot_1=c } else { tot_1=bind_rows(tot_1,c) } } tot_1$rep = q if (q==1){ dftot = tot_1 } else { dftot=bind_rows(dftot, tot_1) } }
解决方案
要实现每次迭代随机移除整个Transect,核心是随机选定要移除的Transect组,保留剩余数据后计算频率。以下是两种适配需求的修改方案:
方案1:遍历移除0到多个Transect的情况
该方案保留原代码的迭代逻辑,将“按行移除”改为“按Transect组移除”,可灵活控制每次移除的Transect数量:
library(dplyr) # 配置参数:重复次数、每次最多移除的Transect数量 n_reps <- 2 max_remove <- length(unique(dat$Transect)) - 1 # 至少保留1个Transect all_transects <- unique(dat$Transect) # 初始化结果集 dftot <- data.frame() for (q in 1:n_reps) { tot_1 <- data.frame() # 遍历移除0个(全保留)到max_remove个Transect的情况 for (i in 0:max_remove) { if (i == 0) { df <- dat } else { # 随机选择i个要移除的Transect removed <- sample(all_transects, size = i, replace = FALSE) df <- dat %>% filter(!Transect %in% removed) } # 计算Category频率 freq_df <- df %>% group_by(Category) %>% summarise(n = n()) %>% mutate(freq = n / sum(n), total_rows = nrow(df), removed_transect_num = i) tot_1 <- bind_rows(tot_1, freq_df) } # 添加重复次数标记 tot_1$rep <- q dftot <- bind_rows(dftot, tot_1) } # 查看最终结果 print(dftot)
方案2:每次固定移除1个Transect(贴合需求描述)
该方案更贴合你提到的“第一次移除Transect3,第二次移除Transect1”的场景,每次重复中依次随机移除单个Transect:
library(dplyr) n_reps <- 2 all_transects <- unique(dat$Transect) dftot <- data.frame() for (q in 1:n_reps) { # 先记录全保留的情况 tot_1 <- dat %>% group_by(Category) %>% summarise(n = n()) %>% mutate(freq = n / sum(n), total_rows = nrow(dat), removed_transect = "None", removed_count = 0) # 随机打乱Transect顺序,依次移除每个 shuffled_transects <- sample(all_transects) for (transect in shuffled_transects) { df <- dat %>% filter(Transect != transect) freq_df <- df %>% group_by(Category) %>% summarise(n = n()) %>% mutate(freq = n / sum(n), total_rows = nrow(df), removed_transect = as.character(transect), removed_count = 1) tot_1 <- bind_rows(tot_1, freq_df) } tot_1$rep <- q dftot <- bind_rows(dftot, tot_1) } print(dftot)
代码说明
- 核心逻辑:用
sample()随机选定要移除的Transect组,通过filter()筛选剩余数据,替代原代码按行移除的逻辑。 - 结果标记:新增
removed_transect(被移除的Transect编号)、removed_count(移除数量)等字段,方便后续区分不同迭代的结果。 - 重复处理:保留原代码的重复次数逻辑,将多次重复的结果合并到总数据集。
内容的提问来源于stack exchange,提问作者Nico
相关产品推荐
相关产品推荐

