如何使用tidyverse风格方法按行移除数据框重复值并替换为NA
问题描述
我已经了解过多种使用base R实现按行处理、将行内重复值替换为NA的解决方案,可参考相关讨论:R - find all duplicates in row and replace。
但我想找到更符合tidy风格的实现方式。之前尝试了多种across用法,以及rowwise搭配c_across的组合方案,都没有得到正确结果。
使用的测试示例数据如下:
df <- data.frame(x = c(1, 2, 3, 4), y = c(1, 3, 4, 5), z = c(2, 3, 5, 6))
预期输出结果:
x y z 1 1 NA 2 2 2 3 NA 3 3 4 5 4 4 5 6
之前尝试的无效代码:
df |> mutate(apply(across(everything()), 1, function(x) replace(x, duplicated(x), NA))) df |> mutate(apply(across(everything()), 1, function(x) {x[duplicated(x)] <- NA}))
我还尝试过创建存储重复值列位置的列表列,取得了部分进展,但该方法会触发“新名称”问题相关的冗余警告,不确定后续如何推进,也不确定这个思路是否可行,猜测可能需要借助purrr相关功能实现:
df |> rowwise() |> mutate(test = list(duplicated(c_across(everything())))) |> unnest_wider(test) # A tibble: 4 × 6 x y z ...1 ...2 ...3 <dbl> <dbl> <dbl> <lgl> <lgl> <lgl> 1 1 1 2 FALSE TRUE FALSE 2 2 3 3 FALSE FALSE TRUE 3 3 4 5 FALSE FALSE FALSE 4 4 5 6 FALSE FALSE FALSE
解决方案
以下两种均为标准tidy风格实现,无冗余警告,运行后直接输出预期结果:
- 方案1适配常规dplyr操作链,可直接嵌入现有mutate流程
- 方案2逻辑更直观,后续扩展自定义行处理规则更方便
方案1:rowwise + across 逐列判断
利用cur_column()匹配当前列在整行中的位置,直接判断当前值是否为行内重复值,是则替换为NA:
library(tidyverse) df |> rowwise() |> mutate( across( everything(), ~{ row_val <- c_across(everything()) ifelse(duplicated(row_val)[which(names(row_val) == cur_column())], NA, .x) } ) ) |> ungroup()
方案2:purrr::pmap 按行遍历处理
直接对数据框按行映射,每一行传入后将重复值替换为NA,再按行绑定为结果数据框:
df |> pmap_dfr( ~{ row <- c(...) row[duplicated(row)] <- NA row } )
内容的提问来源于stack exchange,提问作者deschen
相关产品推荐
相关产品推荐

