【问题标题】:Count vector elements in range when condition is met满足条件时计算范围内的向量元素
【发布时间】:2018-04-25 22:10:48
【问题描述】:

我有一个数字向量:

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

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

  1. 如果x[i] &gt; 0,返回0
  2. 如果x[i]之前的4个元素都是0,返回NA
  3. 如果x[i]之前的4个元素不是0,计算最后一个not-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 应该使用尽可能多的可用元素)。有人对此有解决方案吗?首选矢量化方法,因为矢量很长且数据集相当大。

【问题讨论】:

  • 为什么前3个NA?你说如果x[i]之前的所有4个元素都是0,返回NA(我假设x[i]是最后一个非零值)
  • @Sotos vectorization 标签有什么问题?
  • 请参阅我的问题的最后第四行:对于没有 4 个元素可用的位置,该函数应使用尽可能多的可用位置。所以第一个位置只有1个,第二个位置2个,第三个位置3个,从第4个位置开始4个位置。
  • @piptoma 好的,知道了
  • 您对使用 Rcpp 有限制吗?因为,既然你还在处理这个问题,我认为你最好在 Rcpp 中编写一个简单的循环。

标签: r vector vectorization sequence


【解决方案1】:

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

【讨论】:

    【解决方案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 
    

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

    【讨论】:

      猜你喜欢
      • 2016-03-13
      • 1970-01-01
      • 2021-02-05
      • 2018-07-26
      • 2018-09-20
      • 1970-01-01
      • 2021-01-03
      • 2019-01-22
      • 2021-10-28
      相关资源
      最近更新 更多