填写两个指定值之间的所有条目

时间:2017-05-26 15:54:04

标签: r

我有一个长向量,数千个条目,其中偶尔有元素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)

谢谢

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 中的laglead函数。

如果您想评估两种方法的速度,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