【问题标题】:How to find the min of the previous n values for every element of a vector?如何为向量的每个元素找到前 n 个值的最小值?
【发布时间】:2014-11-21 16:11:25
【问题描述】:

到目前为止,我在这样的函数中使用循环:

# x is a vector of numbers
# [1] 0 1 -1 -5 100 20 15

function(x,n){

  results <- numeric(length(x)-n+1)

  for(i in 1:(length(x)+1-n)){
    results[i] <- min(x[i:(i+n-1)])
  }

  return(results)
}

## outputs this for x and n = 3
# [1] -1 -5 -5 -5 15

我想知道是否有可能不需要循环的更有效的解决方案。

编辑::

我在具有 6019 个观察值的向量上运行了两个带有微基准的解决方案。当我有时间(/弄清楚如何)时,我可以尝试具有各种观察大小的每个解决方案,以查看每个解决方案的有效性。但现在:

Rcpp 解决方案:

> microbenchmark(nmin(x,3))
Unit: microseconds
       expr    min     lq     mean  median     uq    max neval
 nmin(x, 3) 53.885 54.313 57.01953 54.7405 56.023 93.656   100

caTools 解决方案:

microbenchmark(runmin(x[[1]],3,endrule='trim'))
Unit: microseconds
                                expr     min       lq     mean  median       uq     max neval
 runmin(x[[1]], 3, endrule = "trim") 231.788 241.8385 262.6348 249.964 262.5795 833.923   100

动物园解决方案:

> microbenchmark(rollapply(x[[1]],3,min))
Unit: milliseconds
                      expr     min      lq     mean   median       uq      max neval
 rollapply(x[[1]], 3, min) 42.2123 47.2926 50.40772 50.33941 52.50033 98.46828   100

我的解决方案:

  > microbenchmark(nDayLow(x[[1]],3))
Unit: milliseconds
                 expr      min       lq     mean   median       uq      max neval
 nDayLow(x[[1]], 3) 13.64597 14.51581 15.67343 15.33006 15.71324 63.68687   100

【问题讨论】:

  • runmin 似乎给出了迄今为止最快的结果
  • @road_to_quantdom 您没有测试Rcpp 解决方案?
  • 抱歉耽搁了,我现在才运行解决方案。你的似乎是最有效的!

标签: r loops min


【解决方案1】:

听起来是 Rcpp 的一个很好的用例。复制粘贴它并像任何其他功能一样使用它。我相信有很多方法可以让这更加高效(我的意思是我不是特别擅长 c++,我很确定你可以在这里使用一些不错的 STL):

require(Rcpp)
Rcpp::cppFunction( 'IntegerVector nmin( NumericVector x , int n ){
  int N = x.size();
  IntegerVector out(N-n+1);
    for( int i = 0; i < out.size(); ++i){
        int nmin=x[i];
        for( int j = 0; j < n; ++j){
          int tmp=x[j+i];
          if( tmp < nmin ){
            nmin=tmp;
          }
        }
        out[i]=nmin;
    }
  return out;
}')

nmin(x,3)
#[1] -1 -5 -5 -5 15
nmin(x,7)
#[1] -5

runmin快30倍左右:

print( microbenchmark(runmin(x,3,endrule='trim'),nmin(x,3),unit="relative") , digits = 1 )
#Unit: relative
#                           expr min lq median uq max neval
# runmin(x, 3, endrule = "trim")  55 41     36 34  19   100
#                     nmin(x, 3)   1  1      1  1   1   100

【讨论】:

  • 如果向量是“double”类型,你会怎么做
【解决方案2】:

使用来自动物园rollapply

library("zoo")
rollapply(x, 3, min)
# [1] -1 -5 -5 -5 15

【讨论】:

  • 谢谢。我刚刚运行了两个微基准来查看性能差异。似乎 for-loop 方法实际上可能更快。我很震惊,但这可能吗?
  • @road_to_quantdom 在几乎所有情况下,*apply 函数只是 for 循环周围的语法糖。
【解决方案3】:

您也可以使用caTools中的runmin

library(caTools)
runmin(x,3,endrule='trim')
#[1] -1 -5 -5 -5 15

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-01
    • 2012-12-17
    • 2012-12-27
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 2020-03-11
    相关资源
    最近更新 更多