仅当连续超过5

时间:2017-06-27 09:53:48

标签: r vector

使用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

我知道我必须使用rlediff才能做到这一点,但我无法弄清楚如何有效地做到这一点。

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

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

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

2 个答案:

答案 0 :(得分:2)

我们可以创建一个逻辑索引来对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

答案 1 :(得分: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