如何为向量中的每个元素查找前n个值的最小值?

3

到目前为止,我在函数内部使用循环的方式如下:

# 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
@road_to_quantdom 你没有测试过Rcpp的解决方案吗? - Simon O'Hanlon
抱歉回复晚了,我刚才才运行了解决方案。你的确似乎是最高效的! - road_to_quantdom
3个回答

4
使用 zoo 中的 rollapply 函数:
library("zoo")
rollapply(x, 3, min)
# [1] -1 -5 -5 -5 15

谢谢。我刚刚运行了两个微基准测试来查看性能差异。似乎for循环方法可能实际上更快。我很震惊,但这可能是可能的吗? - road_to_quantdom
@road_to_quantdom 在几乎所有情况下,*apply函数只是一个for循环的语法糖。 - Thomas

4

看起来这是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”,您会如何做到这一点? - road_to_quantdom

2
您也可以使用来自 caToolsrunmin
library(caTools)
runmin(x,3,endrule='trim')
#[1] -1 -5 -5 -5 15

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接