r语言 - 删除跨几个列的重复值,但保留行



我有一个数据框架,看起来像这样:

dat <- data.frame(id=1:6,
z_1=c(100,290,38,129,0,290),
z_2=c(20,0,0,0,0,290),
z_3=c(0,0,38,0,0,98),
z_4=c(0,0,38,127,38,78),
z_5=c(23,0,25,0,0,98),
z_6=c(100,0,25,127,0,9))

dat

id z_1 z_2 z_3 z_4 z_5 z_6
1  1 100 20  0   0   23  100
2  2 290  0  0   0   0   0
3  3  38  0  38  38  25  25
4  4 129  0  0   127 0   127
5  5   0  0  0   38  0   0
6  6 290 290 98  78  98  9

我想删除每一行z_x的重复值,用0NA替换任何重复值,但留下行&列完整(即不删除任何)。这里的0不算作重复项,它们是缺失值。列中的重复值是可以的。我的理想输出是这样的:

id z_1 z_2 z_3 z_4 z_5 z_6
1  1  100 20  0   0   23  0
2  2  290 0   0   0   0   0
3  3  38  0   0   0   25  0
4  4  129 0   0   127 0   0
5  5   0  0   0   38  0   0
6  6  290 0   98  78  0   9

我真的不关心z_x中的值出现的顺序,所以如果它们被移动也没关系。是否有一种有效的方法来做到这一点,最好是用某种整洁的方式?我知道我可以更长的枢轴并删除重复的行,但我的数据集非常大,我正在寻找一种不需要枢轴的方法。

Base R way usingapply:

cols <- grep('z_\d+', names(dat))
dat[cols] <- t(apply(dat[cols], 1, function(x)  replace(x, duplicated(x), 0)))
#  id z_1 z_2 z_3 z_4 z_5 z_6
#1  1 100  20   0   0  23   0
#2  2 290   0   0   0   0   0
#3  3  38   0   0   0  25   0
#4  4 129   0   0 127   0   0
#5  5   0   0   0  38   0   0
#6  6 290   0  98  78   0   9

tidyverse方式无需重塑可以使用pmap:

library(tidyverse)
dat %>%
mutate(result = pmap(select(., matches('z_\d+')), ~{
x <- c(...)
replace(x, duplicated(x), 0)
})) %>%
select(id, result) %>%
unnest_wider(result)

由于@thelatemail执行的测试表明,重塑是比按行处理数据更好的选择,因此您可能需要考虑它。

dat %>%
pivot_longer(cols = matches('z_\d+')) %>%
group_by(id) %>%
mutate(value = replace(value, duplicated(value), 0)) %>%
pivot_wider()

这个解决方案并不完美,但希望足够简单。

duplicated()函数做你想做的。您可以使用apply()函数按行向duplicated()提供您的数据。

dat[t(apply(dat, MARGIN = 1, duplicated))] <- 0

最新更新