满足条件时计算范围内的向量元素

时间:2017-11-13 09:20:02

标签: r vector vectorization sequence

我有一个数字向量:

x <- c(0, 0, 0, 30, 60, 0, 0, 0, 0, 0, 10, 0, 0, 15, 45, 0, 0)

对于i中的每个元素x,我想执行以下操作

  1. 如果x[i] > 0,则返回0
  2. 如果x[i]之前的所有4个元素都是0,则返回NA
  3. 如果x[i]之前的4个元素不是0,请计算最后一个元素 - 0元素与x[i]
  4. 之间的元素数量

    我期待这个输出:

    #> x
    #[1]  0  0  0 30 60  0  0  0  0  0 10  0  0 15 45  0  0
    #> x_out
    #[1] NA NA NA  0  0  1  2  3  4 NA  0  1  2  0  0  1  2
    

    请注意,当向量的开头有少于4个元素时,解决方案也应该起作用(即条件2和3应该使用尽可能多的元素)。有人有解决方案吗?首选矢量化方法,因为矢量很长,数据集相当大。

2 个答案:

答案 0 :(得分:3)

这是一个简单的Rcpp解决方案。在RStudio中创建一个新的C ++文件并将代码粘贴到其中并获取文件。显然,如果您使用Windows,则需要安装Rtools。

#include <Rcpp.h>
using namespace Rcpp;    

// [[Rcpp::export]]
IntegerVector funRcpp(const IntegerVector x) {
  const double n = x.length();
  int counter = 4;
  IntegerVector y(n);

  for (double i = 0; i < n; ++i) {
    if (x(i) > 0) {
      y(i) = 0;
      counter = 0;
    }
    else {
      if (counter > 3) {
        y(i) = NA_INTEGER;
      } else {
        counter++;
        y(i) = counter;
      }
    }
  }

  return y;
}


/*** R
x <- c(0, 0, 0, 30, 60, 0, 0, 0, 0, 0, 10, 0, 0, 15, 45, 0, 0)
funRcpp(x)
*/

这将返回所需的结果:

> funRcpp(x)
 [1] NA NA NA  0  0  1  2  3  4 NA  0  1  2  0  0  1  2

答案 1 :(得分:0)

这是我目前的做法:

library(dplyr)
last_x_months <- 4
my_list       <- vector("list", 1 + last_x_months)
my_list[[1]]  <- x

# create lagged variants of vector
for (j in seq_along(1:last_x_months)) {
  my_list[[1 + j]] <- lag(my_list[[1]], n = j, default = NA)
}

# row bind it to a data.frame
i_dat <- do.call(rbind, my_list) %>% 
  as.data.frame()

# apply function to each column in dataframe
sapply(i_dat, function(x) {
  if (sum(x, na.rm = TRUE) == 0) {
    NA
  } else if (x[1] > 0) {
    0
  } else {
    rle(x)$lengths[1]
  }
})

这是我得到的输出:

#> output
#[1] NA  NA  NA   0   0   1   2   3   4  NA   0   1   2   0   0   1   2 

这是一种好的做法,还是可以通过快捷方式提高性能?在性能优化方面我很缺乏经验,这就是我提出这个问题的原因。