序列发生时反向计数向量元素

时间:2017-11-10 08:32:50

标签: r vector vectorization sequence

我有一个值为NA01的向量:

x <- c(NA, 0, 0, 1, 1, 1, 1, NA, 0, 0, 0, 0, NA, NA, 1, 1, 1, NA)
#> x
#[1] NA  0  0  1  1  1  1 NA  0  0  0  0 NA NA  1  1  1 NA

每当序列从1切换到NA时,我想在该事件之前计算非NAs的位置,并用该数字替换元素。我期待这个输出:

#> x_output
#[1] NA  6  5  4  3  2  1 NA  0  0  0  0 NA NA  3  2  1 NA

有人有解决方案吗?首选矢量化方法,因为矢量很长,数据集相当大。

3 个答案:

答案 0 :(得分:8)

使用rle定义运行长度,使用ave创建序列:

x <- c(NA, 0, 0, 1, 1, 1, 1, NA, 0, 0, 0, 0, NA, NA, 1, 1, 1, NA)

fun <- function(x) {
  x <- rev(x)
  y <- rle(!is.na(x))
  y$values[y$values] <- seq_along(y$values[y$values])
  y <- inverse.rle(y)

  x[!is.na(x)] <- ave(x[!is.na(x)], y[!is.na(x)], FUN = function(x) {
    if (x[1] == 0L) return(x)
    seq_along(x)
  })
  rev(x)
}

fun(x)
#[1] NA  6  5  4  3  2  1 NA  0  0  0  0 NA NA  3  2  1 NA

答案 1 :(得分:4)

以下是data.table的选项。创建一个TRUE / FALSE列的&lt; indx&#39;来标识1到NA的切换。然后,按照逻辑向量(rleid(is.na(x)))的运行长度id分组,if在&#39; indx&#39;中有any TRUE,然后得到与序列相反的顺序行或else返回&#39; x&#39;并提取列&#39; V1&#39;

library(data.table)
data.table(x)[, indx := shift(shift(x,  fill = 0) %in% 1 & is.na(x), 
   type = 'lead', fill = FALSE)][, if(any(indx)) rev(seq_len(.N)) else 
             as.integer(x) ,rleid(is.na(x))]$V1
#[1] NA  6  5  4  3  2  1 NA  0  0  0  0 NA NA  3  2  1 NA

答案 2 :(得分:3)

另一种方法

library(dplyr)
start_inds <- which(x == 1 & is.na(lead(x)))
na_inds <- which(is.na(x))
sapply(start_inds, function(x) {
   sub_ind = x - na_inds
   end_inds = (x - min(sub_ind[sub_ind > 0]) + 1) : x
   x[end_inds] <<- rev(seq_along(end_inds))
})

x
#[1] NA  6  5  4  3  2  1 NA  0  0  0  0 NA NA  3  2  1 NA

我们使用来自x的{​​{1}}找出NA等于1且下一个元素为lead的交叉点,它为我们提供了我们需要的指数向后改变价值。 (dplyr)。我们计算start_indsNA出现的向量中的所有索引,以便我们可以使用它来获得最接近的na_inds值。现在,对于每个NA,我们使用start_inds减去它的值并计算最接近的na_inds值,直到我们需要更改值(NA)。要选择end_indsend_indsstart_ind之间的差异必须大于0,因为我们需要na_inds之前的NA值,我们使用{{ 1}}获取最近的start_ind值索引。通过使用全局赋值运算符(min)生成序列NA来更新值。