如何在R中对ID-gene组合去重并保留指定status的行
按ID-gene组合筛选优先保留Positive状态行的解决方案
针对你处理超20万行、含26000个ID的大型data frame的需求——每个ID-gene组合优先保留Positive状态的行,仅当无Positive时保留一条Negative行,这里有两种高效的实现方式:
方法一:用dplyr(推荐,代码简洁高效)
dplyr的分组操作非常适合这类需求,代码可读性强,处理大数据量也很高效:
首先补全你的示例数据构造代码(原代码缺失ID向量):
ID <- c("1001A", "1001A", "1001A", "1001A", "1002B", "1002B", "1002B") gene <- c('Gene 1', "Gene 2", "Gene 1", "Gene 1", "Gene 1", "Gene 1", "Gene 1") status <- c("Negative", "Negative", "Positive", "Negative", "Negative", "Negative", "Negative") df <- data.frame(ID, gene, status, stringsAsFactors = FALSE) # 按需求将status转为因子类型 df$status <- factor(df$status, levels = c("Negative", "Positive"))
然后执行筛选逻辑:
library(dplyr) filtered_df <- df %>% # 按ID和gene的组合分组 group_by(ID, gene) %>% # 按status降序排序,让Positive排在每组最前面(因为因子水平Negative在前,降序后Positive优先) arrange(desc(status)) %>% # 取每组的第一行 slice_head(n = 1) %>% # 取消分组状态 ungroup() # 查看结果 print(filtered_df)
输出结果完全匹配你的示例要求:
# A tibble: 3 × 3 ID gene status <chr> <chr> <fct> 1 1001A Gene 1 Positive 2 1001A Gene 2 Negative 3 1002B Gene 1 Negative
方法二:Base R实现(无需加载额外包)
如果不想加载dplyr包,用Base R也能实现需求:
# 先给状态赋值权重:Positive为2,Negative为1 df$weight <- ifelse(df$status == "Positive", 2, 1) # 按ID-gene分组,筛选出每组中权重最大的行 temp_df <- df[with(df, ave(weight, ID, gene, FUN = function(x) x == max(x))), ] # 去重(避免同一ID-gene组合有多个Positive时保留多行) filtered_df_base <- temp_df[!duplicated(temp_df[c("ID", "gene")]), ] # 移除临时的weight列 filtered_df_base <- filtered_df_base[, !names(filtered_df_base) %in% "weight"] # 查看结果 print(filtered_df_base)
补充说明
- 对于你的大数据量,dplyr的方法在效率上更有优势,若需要极致性能还可以搭配
data.table的分组操作进一步提速; - 确保
status因子的水平设置正确,如果你的因子水平是c("Positive", "Negative"),排序时直接用arrange(status)即可,无需降序。
内容的提问来源于stack exchange,提问作者user305007
相关产品推荐
相关产品推荐

