R语言无需多重for循环按行间条件筛选data.frame数据
解决方案
方法1:使用dplyr实现(简洁高效,无循环)
首先构造示例数据:
df=data.frame(Abs=c("At1", "At1", "At1", "At2", "At2", "At3", "At4", "At4", "At4", "At4", "At5", "At5", "At6", "At6", "At6"), vid=c("id1", "id2", "id3", "id4", "id5", "id1", "id1", "id2", "id5", "id6", "id7", "id8", "id8", "id9", "id12"), ert=c(1,1,2,7,8,4,5,5,5,9,6,5,2,2,2), Tre= c(1256, 1260, 854, 147,8962, 87452, 1452, 1500, 1502, 147, 210, 258,1400,1850,1865))
筛选代码如下:
library(dplyr) df2 <- df %>% # 按Abs和ert分组,满足「同一Abs分组、ert值相同」的前提条件 group_by(Abs, ert) %>% # 组内判断当前行是否满足:存在至少1个其他行,vid不同且Tre绝对差<300 filter(any(abs(Tre - cur_data()$Tre[vid != cur_data()$vid[cur_group_rows()]]) < 300)) %>% ungroup()
运行后得到的结果和预期完全一致:
> df2 # A tibble: 7 × 4 Abs vid ert Tre <chr> <chr> <dbl> <dbl> 1 At1 id1 1 1256 2 At1 id2 1 1260 3 At4 id1 5 1452 4 At4 id2 5 1500 5 At4 id5 5 1502 6 At6 id9 2 1850 7 At6 id12 2 1865
方法2:base R实现(无需额外安装包)
如果不想依赖第三方包,可以用单层循环实现,效率远高于多重for循环:
# 按Abs+ert拆分数据 split_df <- split(df, interaction(df$Abs, df$ert)) # 对每个子集筛选符合条件的行 filtered_list <- lapply(split_df, function(sub_df) { n <- nrow(sub_df) if (n < 2) return(NULL) keep <- logical(n) for (i in seq_len(n)) { keep[i] <- any(abs(sub_df$Tre[i] - sub_df$Tre[-i]) < 300 & sub_df$vid[i] != sub_df$vid[-i]) } sub_df[keep, ] }) # 合并结果 df2 <- do.call(rbind, filtered_list) rownames(df2) <- NULL
内容的提问来源于stack exchange,提问作者Patrick Parts
相关产品推荐
相关产品推荐

