在R中删除每行连续重复的值

5

我正在使用R处理一个数据集,我想按行删除连续重复的值。例如,行(19,15,19,19)应该变成行(19,15,19)。

我尝试使用duplicated(df),但这会删除所有重复项,导致结果为(19,15),而不仅仅是连续的重复项。

可重现的示例:

a <- c(19,18,19,9,9,19,19)
b <- c(15,0,19,9,19,19,13)
c <- c(19,0,13,19,19,19,0)
d <- c(19,0,0,19,19,0,0)

trajectories <- cbind(a,b,c,d)

你的数据集有多大(nrow * ncol)?是否真的需要删除或替换重复值? - alexis_laz
2个回答

6
我们可以遍历行并基于运行长度编码获取唯一元素,以创建一个向量列表。
lst <- apply(trajectories, 1, FUN = function(x) rle(x)$values)
lst
#[[1]]
# a  b  d 
#19 15 19 

#[[2]]
# a  d 
#18  0 

#[[3]]
# b  c  d 
#19 13  0 

#[[4]]
# b  d 
# 9 19 

#[[5]]
# a  d 
# 9 19 

#[[6]]
# c  d 
#19  0 

#[[7]]
# a  b  d 
#19 13  0 

我们可以在末尾添加NA,使元素数量保持一致。
do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))

更新

正如 @Sotos 所提到的,如果我们需要列名称与原始数据一致,那么

do.call(rbind, lapply(lst, function(x) {
            x[setdiff(colnames(trajectories), names(x))] <- NA
            x[colnames(trajectories)]}))

另一种选项是获取每行相邻元素之间的diff(差异),基于差异不为零创建逻辑向量来对元素进行子集筛选。

apply(trajectories, 1, FUN = function(x) x[c(TRUE, diff(x)!=0)])

另一种可行的选项是在示例中工作。
 i1 <- which(cbind(1, trajectories[,-1] -
         trajectories[,-ncol(trajectories)])!=0, arr.ind=TRUE)
 lapply(split(1:nrow(i1), i1[,1]), function(i) trajectories[i1[i,, drop = FALSE]])

它完美地工作了,谢谢!只有一个问题:这个列表必须转换为数据框,但我无法做到这一点,因为每行需要具有相同数量的值。少于4个值的行可以用0填充。 - olive
@CharlotteDeVlieghere 你可以将元素paste在一起创建列,或者另一个选项是在data.frame中使用list列。 - akrun
1
rbind 的绑定似乎有误。例如,元素 4 是 b = 9d = 19,但是当 rbind 处于 ab 列下时。我喜欢你的最后一个选项(任何不具有边距 1 和 apply 的选项)。 - Sotos

0
a <- c(19,18,19,9,9,19,19)
b <- c(15,0,19,9,19,19,13)
c <- c(19,0,13,19,19,19,0)
d <- c(19,0,0,19,19,0,0)

trajectories <- cbind(a,b,c,d)
trajectories

t(apply(trajectories, 1, function(x) { x[c(F, diff(x) == 0)] <- 0; x } ))

您可以通过更改<- 0部分将连续重复设置为其他内容,例如将它们设置为NA...

t(apply(trajectories, 1, function(x) { x[c(F, diff(x) == 0)] <- NA; x } ))

是否有可能修改这个程序,将重复的值改为NA,无论它们是否连续? - Carrol
1
t(apply(trajectories, 1, function(x) { x[duplicated(x)] <- NA; x })) - CJ Yetman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接