在R语言中基于多列条件(重复值、最值)删除行
R语言按分组保留最大范围行的解决方案
问题说明
需要从数据框中按id和key分组,每个分组内再识别独立的连续/重叠范围,保留每个子范围中start最小、end最大的行(即覆盖范围最长的行)。
预处理:修复数据类型
原数据中end列混合了数值和字符类型,无法直接进行大小比较,首先转换为数值型:
df$end <- as.numeric(df$end)
方法1:使用dplyr包(推荐)
通过分组、排序、标记独立范围组,最终筛选目标行:
library(dplyr) df_result <- df %>% # 转换end列为数值型 mutate(end = as.numeric(end)) %>% # 按id、key分组后按start排序 group_by(id, key) %>% arrange(start, .by_group = TRUE) %>% # 标记独立的范围组:当前start超过前一行end时,开启新组 mutate(range_group = cumsum(start > lag(end, default = first(end)))) %>% # 在每个细分组中筛选start最小且end最大的行 group_by(id, key, range_group) %>% filter(start == min(start) & end == max(end)) %>% ungroup() %>% # 移除临时分组列 select(-range_group) # 查看结果 print(df_result)
方法2:使用Base R
无需额外依赖包,通过排序、循环标记分组、再聚合筛选:
# 转换end列为数值型 df$end <- as.numeric(df$end) # 按id、key、start排序 df_sorted <- df[order(df$id, df$key, df$start), ] # 生成独立范围组标记 range_group <- numeric(nrow(df_sorted)) current_group <- 1 range_group[1] <- current_group for(i in 2:nrow(df_sorted)){ # 同一id和key下,当前start未超过前一行end则属于同一组 if(df_sorted$id[i] == df_sorted$id[i-1] && df_sorted$key[i] == df_sorted$key[i-1] && df_sorted$start[i] <= df_sorted$end[i-1]){ range_group[i] <- current_group } else { current_group <- current_group + 1 range_group[i] <- current_group } } df_sorted$range_group <- range_group # 按分组提取目标行 df_result <- do.call(rbind, by(df_sorted, list(df_sorted$id, df_sorted$key, df_sorted$range_group), function(sub_df){ sub_df[sub_df$start == min(sub_df$start) & sub_df$end == max(sub_df$end), ] })) # 移除临时分组列 df_result <- df_result[, !names(df_result) %in% "range_group"] # 查看结果 print(df_result)
最终结果
两种方法均可得到预期输出:
id key start end 1 id1 a 161 228 2 id1 b 353 408 3 id2 a 823 837 4 id2 a 1170 1194
内容的提问来源于stack exchange,提问作者xidelos
相关产品推荐
相关产品推荐

