r语言 - 满足条件时对范围内的向量元素进行计数



我有一个数字向量:

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

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

  1. 如果x[i] > 0,则返回 0
  2. 如果x[i]前面的所有 4 个元素都0,则返回 NA
  3. 如果x[i]前面的 4 个元素没有0,则计算最后一个非0元素和x[i]

我希望这个输出:

#> 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 应使用尽可能多的可用元素(。有人对此有解决方案吗?矢量化方法是首选,因为矢量很长,数据集相当大。

这是一个简单的 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

这是我目前的方法:

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 

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

最新更新