如何基于数量未知的多列排除数据框中的重复行?
动态列去重:用
distinct()处理除固定列外的所有列 问题背景
我有根据用户输入动态生成的数据框,示例如下:
df1 <- data.frame(A=c(1,2,1,4), B=c(4,3,4,1), C=c(3,2,3,4), Y=c(2,7,6,3), Z=c(5,8,9,10)) df2 <- data.frame(A=c(1,2,1,4), B=c(4,3,4,1), C=c(3,2,3,4), D=c(2,1,2,3), Y=c(2,7,6,3), Z=c(5,8,9,10))
df2里第3行的A、B、C、D列和第1行完全重复。常规去重写法需要手动指定列:
library(dplyr) df1 |> distinct(A,B,C, .keep_all=TRUE) df2 |> distinct(A,B,C,D, .keep_all=TRUE)
但问题是,除了固定的Y、Z列,其余列的数量和名称不固定(可能是A、B两列,也可能是A到F列)。我尝试过先提取列名再传入distinct(),但程序会把列名向量当成列名本身,导致报错:
names <- colnames(df2) names <- names[names != c("Y", "Z")] df2 |> distinct(names, .keep_all=TRUE) # 错误:找不到名为"names"的列
解决方法
这里有两种简洁的方式实现针对Y、Z之外所有列的动态去重:
方法1:用all_of()解析列名向量
先通过setdiff()获取除Y、Z外的列名(比直接用!=更稳妥,避免多列排除时的匹配问题),再用all_of()把字符向量解析为数据框的列:
library(dplyr) # 获取目标列名 target_cols <- setdiff(colnames(df2), c("Y", "Z")) # 动态去重 df2 |> distinct(all_of(target_cols), .keep_all = TRUE)
方法2:用across()直接排除固定列
无需手动生成列名向量,直接用across(-c(Y, Z))选择除Y、Z外的所有列:
df2 |> distinct(across(-c(Y, Z)), .keep_all = TRUE)
这种写法更简洁,适合快速实现需求。
效果验证
执行上述代码后,df2会被去重,移除重复的第3行,结果如下:
A B C D Y Z 1 1 4 3 2 2 5 2 2 3 2 1 7 8 4 4 1 4 3 3 10
内容的提问来源于stack exchange,提问作者tlmoore
相关产品推荐
相关产品推荐

