【问题标题】:Remove consecutive duplicates from a vector, only if more than 5 consecutive从向量中删除连续重复,仅当超过 5 个连续
【发布时间】:2017-06-27 09:53:47
【问题描述】:

使用 R,我有以下向量:

x <- c(1,1,2,1,3,-99,-99,3,rep(-99,9),1,2,2,0,1,-99)
x
[1]   1   1   2   1   3 -99 -99 3 -99 -99 -99 -99 -99 -99 -99 -99 -99   1   2   2   0   1 -99

我想删除连续值,但前提是连续值大于阈值,例如 5。所以在这种情况下,输出结果应该是:

[1]   1   1   2   1   3 -99 -99 3  1   2   2   0   1 -99

我知道我必须使用rle 或者diff 来执行此操作,但我不知道如何有效地执行此操作。

我不认为建议的重复问题实际上是重复的,因为在这种情况下,仅查找和删除值的子集是问题的主要部分。如果不是这样,使用rleduplicates 确实足够了。

我想出了这个,但我确定有更好的方法,特别是因为这仅适用于 cuplicated 值的第一个实例:

r <- rle(x)
toRemove <- which(r$lengths > 5)
startdupl <- sum(r$lengths[1:(toRemove-1)])+1
x[-(startdupl:(startdupl+r$lengths[toRemove]-1))]

该过程当然应该适用于长度 >5 的多个重复项。

如果我可以用 NA 替换值而不是删除它们,则可以加分! 使用dplyr 和/或制作比以下功能更快的东西的额外奖励积分!

经过几个很好的建议,这里有一些我正在考虑的选项和一个包含 30000 个元素的向量的小基准:

f1 <- function(x) { inverse.rle(within.list(rle(x), values[lengths>5] <- NA))}
f2 <- function(x) {
  r <- rle(x)
  r$values[which(r$lengths>5)] <- NA
  with(r, rep(values, lengths))
}
f3 <- function(x) {as.vector(unlist(sapply(split(x, cumsum(c(1, 
diff(x) != 0))), function(i) replace(i, length(i) >= 5, NA))))}
f4 <- function(x) {do.call(c, sapply(split(x, cumsum(c(1, diff(x) != 0))), function(i) replace(i, length(i) >= 5, NA)))}

结果:

library(microbenchmark)
microbenchmark(f1(x), f2(x), f3(x), f4(x))
Unit: microseconds
  expr       min         lq       mean    median         uq       max neval
 f1(x)   559.445   602.3215   770.5779   652.395   660.6705  13108.82   100
 f2(x)   542.203   560.0705   882.0940   611.087   618.6395  14982.19   100
 f3(x) 50513.630 55523.6960 59338.0722 57408.724 60003.0870 145707.49   100
 f4(x) 52599.398 57648.0445 60722.3351 60098.227 62113.3655 124074.32   100

【问题讨论】:

  • @akrun 这里的主要问题是找到连续值。过滤 5 个或更多并不是真正的问题。我本来打算发as.vector(unlist(sapply(split(x, cumsum(c(1, diff(x) != 0))), function(i) replace(i, length(i) &gt;= 5, NA)))),但发现了骗子,所以我没有
  • @AF7 所以你不能从骗子那里推断出你的问题的答案?您可以在我没有发布的 cmets 中看到我的建议,因为我发现它与 1 个骗子相同(减去替换部分)。如果您不这么认为,我将删除欺骗并添加答案
  • @Sotos,我做不到,也许是因为我的智力有限 :) 无论如何我添加了基准,它们非常有趣。

标签: r vector


【解决方案1】:

我们可以创建一个逻辑索引来子集valueslengths

with(rle(x), rep(values[lengths<=5], lengths[lengths<=5]))
#[1]   1   1   2   1   3 -99 -99   3   1   2   2   0   1 -99

如果我们要将长度大于5的元素替换为NA

 inverse.rle(within.list(rle(x), values[lengths>5] <- NA))
 #[1]   1   1   2   1   3 -99 -99   3  NA  NA  NA  NA  NA  NA  NA  NA  NA   1   2   2   0   1 -99

【讨论】:

  • 太棒了!如果我不想删除数据,而是想用 NA 替换它怎么办?我不习惯使用with,所以我很难理解这是怎么回事。
  • @AF7 更新帖子
  • 谢谢。我编辑了我的问题以添加一个微基准。你的函数和我设计的另一个函数(从你的开始)在速​​度上或多或少相当。
【解决方案2】:

这是另一种方法,

do.call(c, lapply(split(x, cumsum(c(1, diff(x) != 0))), function(i) 
                                                        replace(i, length(i) >= 5, NA)))

# 11  12   2   3   4  51  52   6  71  72  73  74  75  76  77  78  79   8  91  92  10  11  12 
#  1   1   2   1   3 -99 -99   3  NA  NA  NA  NA  NA  NA  NA  NA  NA   1   2   2   0   1 -99 

【讨论】:

  • 谢谢,我也在基准测试中添加了这个功能。
猜你喜欢
  • 1970-01-01
  • 2021-10-04
  • 1970-01-01
  • 2020-03-30
  • 2013-10-28
  • 2018-12-01
  • 1970-01-01
  • 2018-08-11
  • 2012-10-09
相关资源
最近更新 更多