指数加权移动平均值的快速R实现? [英] Fast R implementation of an Exponentially Weighted Moving Average?

查看:70
本文介绍了指数加权移动平均值的快速R实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想执行指数加权移动平均值(在此处中定义参数设置>)在R中的向量上.有没有比我下面的第一次尝试更好的实现?

I'd like to perform an exponentially weighted moving average (with parameterization defined here) on a vector in R. Is there a better implementation than my first attempt below?

我的第一次尝试是:

ewma <- function(x, a) {
  n <- length(x)
  s <- rep(NA,n)
  s[1] <- x[1]
  if (n > 1) {
    for (i in 2:n) {
      s[i] <- a * x[i] + (1 - a) * s[i-1]
    }
  }
  return(s)
}

y <- 1:1e7
system.time(s <- ewma(y,0.5))
#user  system elapsed 
#   2.48    0.00    2.50 

在第二次尝试中,我认为可以通过向量化来做得更好:

In my second attempt, I thought I could do better by vectorizing:

ewma_vectorized <- function(x,a) {
  a <- 0.1
  n <- length(x)
  w <- cumprod(c(1, rep(1-a, n-1)))
  x1_contribution <- w * x[1]
  w <- a * w
  x <- x[-1]
  s <- apply(as.array(1:(n-1)), 1, function(i,x,w){sum(w[i:1] * x[1:i])}, x=x, w=w)
  s <- x1_contribution + c(0,s)
  return(s)
}

system.time(s <- ewma_vectorized(y,0.5))
# I stopped the program after it continued to run for 4min

我想我应该不会对第二次尝试的结果感到惊讶.在矢量化方面,这是一个非常丑陋的尝试.但是必须有 like 这样的东西,在我的第一次尝试时会有所改善...对吗?

I guess I shouldn't have been too surprised by the results in my second attempt. It was a pretty ugly attempt at vectorization. But there has to be something like this that improves on my first attempt...right?

更新:

我确实在此处找到了更好的实现,并对其进行了如下修改:

I did find a better implementation here and adapted it as follows:

ewma_vectorized_v2 <- function(x, a) {
  s1 <- x[1]
  sk <- s1
  s <- vapply(x[-1], function(x) sk <<- (1 - a) * x + a * sk, 0)
  s <- c(s1, s)
  return(s)
}

system.time(s <- ewma_vectorized_v2(y,0.5))
# user  system elapsed 
#   1.74    0.01    1.76 

推荐答案

您可以使用 stats :: filter :

ewma.filter <- function (x, ratio) {
  c(filter(x * ratio, 1 - ratio, "recursive", init = x[1]))
}
set.seed(21)
x <- rnorm(1e4)
all.equal(ewma.filter(x, 0.9), ewma(x, 0.9))
# [1] TRUE

这比您初次尝试的编译版本要快一点:

This is a bit faster than the compiled version of your first attempt:

ewma <- compiler::cmpfun(function(x, a) {
  n <- length(x)
  s <- rep(NA,n)
  s[1] <- x[1]
  if (n > 1) {
    for (i in 2:n) {
      s[i] <- a * x[i] + (1 - a) * s[i-1]
    }
  }
  return(s)
})
microbenchmark(ewma.filter(x,0.9), ewma(x, 0.9))
Unit: microseconds
                expr      min        lq   median       uq      max neval
 ewma.filter(x, 0.9)  318.508  341.7395  368.737  473.254 1477.000   100
        ewma(x, 0.9) 1364.997 1403.4015 1458.961 1503.876 2221.252   100

这篇关于指数加权移动平均值的快速R实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆