我有一个长向量,数千个条目,其中偶尔有元素0,1,2。 0表示"没有信号",1表示"信号打开",2表示"信号关闭"。我试图找到从1到下一次出现2的运行并用1s填充空格。我还需要在2和下一次出现1之间做同样的事情,但用0填充空格。
我目前使用循环解决了这个问题,但速度慢,效率极低:
示例向量:
kind
期望的结果:
exp = c(1,1,1,0,0,1,2,0,2,0,1,0,2)
谢谢
答案 0 :(得分:6)
您可以使用rle
&来自 data.table -package的shift
,方式如下:
library(data.table)
# create the run-length object
rl <- rle(x)
# create indexes of the spots in the run-length object that need to be replaced
idx1 <- rl$values == 0 & shift(rl$values, fill = 0) == 1 & shift(rl$values, fill = 0, type = 'lead') %in% 1:2
idx0 <- rl$values == 2 & shift(rl$values, fill = 0) == 0 & shift(rl$values, fill = 2, type = 'lead') %in% 0:1
# replace these values
rl$values[idx1] <- 1
rl$values[idx0] <- 0
现在,您将使用inverse.rle
:
> inverse.rle(rl)
[1] 1 1 1 1 1 1 2 0 0 0 1 1 2
作为shift
- 函数的替代方法,您还可以使用 dplyr 中的lag
和lead
函数。
如果您想评估两种方法的速度,microbenchmark
- 包是一个有用的工具。您可以在下面找到3个基准,每个基准用于不同的矢量大小:
# create functions for both approaches
jaap <- function(x) {
rl <- rle(x)
idx1 <- rl$values == 0 & shift(rl$values, fill = 0) == 1 & shift(rl$values, fill = 0, type = 'lead') %in% 1:2
idx0 <- rl$values == 2 & shift(rl$values, fill = 0) == 0 & shift(rl$values, fill = 2, type = 'lead') %in% 0:1
rl$values[idx1] <- 1
rl$values[idx0] <- 0
inverse.rle(rl)
}
john <- function(x) {
Reduce(f, x, 0, accumulate = TRUE)[-1]
}
执行基准测试:
# benchmark on the original data
> microbenchmark(jaap(x), john(x), times = 100)
Unit: microseconds
expr min lq mean median uq max neval cld
jaap(x) 58.766 61.2355 67.99861 63.8755 72.147 143.841 100 b
john(x) 13.684 14.3175 18.71585 15.7580 23.902 50.705 100 a
# benchmark on a somewhat larger vector
> x2 <- rep(x, 10)
> microbenchmark(jaap(x2), john(x2), times = 100)
Unit: microseconds
expr min lq mean median uq max neval cld
jaap(x2) 69.778 72.802 84.46945 76.9675 87.3015 184.666 100 a
john(x2) 116.858 121.058 127.64275 126.1615 130.4515 223.303 100 b
# benchmark on a very larger vector
> x3 <- rep(x, 1e6)
> microbenchmark(jaap(x3), john(x3), times = 20)
Unit: seconds
expr min lq mean median uq max neval cld
jaap(x3) 1.30326 1.337878 1.389187 1.391279 1.425186 1.556887 20 a
john(x3) 10.51349 10.616632 10.689535 10.670808 10.761191 10.918953 20 b
由此可以得出结论,rle
- 方法在应用于大于100个元素的向量(可能几乎总是如此)时具有优势。
答案 1 :(得分:3)
您还可以使用以下功能Reduce
:
f <- function(x,y){
if(x == 1){
if(y == 2) 2 else 1
}else{
if(y == 1) 1 else 0
}
}
然后:
> x <- c(1,1,1,0,0,1,2,0,2,0,1,0,2)
> Reduce(f, x, 0, accumulate = TRUE)[-1]
[1] 1 1 1 1 1 1 2 0 0 0 1 1 2