Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have a simple vector as follows:

x = c(14.24, 13.82, 12.75, 12.92, 12.94, 13.00, 14.14, 16.28, 20.64, 17.64)

I am trying to find the rolling EMA of this vector using the following function -

library(TTR)
y = EMA(x, 5)

I am getting the result as follows -

 [1]     NA     NA     NA     NA 13.33400 13.22267 13.52844 14.44563 16.51042 16.88695

However, I want the result as below -

 [1]     14.24 14.03 13.06 13.43 13.33400 13.22267 13.52844 14.44563 16.51042 16.88695
  1. The first value should be the same as in the original vector
  2. The second value should be the EMA of the first and second value
  3. The third value should be the EMA of the initial three values in the vector
  4. The fourth value should be the EMA of the initial four values in the vector

The rest of the calculation is correctly handled by the function EMA

Solutions I tried -

  1. Running the following command - zoo::rollapplyr(x, width = 5, FUN = EMA, partial = TRUE) will give error as EMA has its own rolling window.

  2. Using function stats::filter works but the answer is not correct as I am not sure about the right value of the ratio parameter. Fast R implementation of an Exponentially Weighted Moving Average? Here is a custom function.

ema_2 <- function (k, width) {
  ratio <- 2/(width + 1)
  c(stats::filter(k * ratio, 1 - ratio, "convolution", init = k[1]))
}

The ideal solution should take at most twice the computation time as taken by EMA function of TTR library.

Here are the performance results of the 2 solutions shared by Waldi and Andre.

              expr     min       lq     mean   median       uq      max neval cld
    TTR::EMA(x, 5) 433.593 457.5815 500.9478 477.0535 530.7105  1128.49  1000   a
        EMA3(x, 5) 445.388 468.9585 515.2009 490.4345 546.5025  1843.46  1000   a
 rollmeanEMA(x, 5) 436.689 461.0885 535.7035 481.8815 538.3150 33122.75  1000   a

Thanks!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
440 views
Welcome To Ask or Share your Answers For Others

1 Answer

This gives the desired result:

require(TTR)

x <- c(14.24, 13.82, 12.75, 12.92, 12.94, 13.00, 14.14, 16.28, 20.64, 17.64)

rollmeanEMA <- function(vec, len) {
  c(cumsum(vec[1:(len-1)]) / seq_along(vec[1:(len-1)]),
    EMA(vec, len)[len:length(vec)])
}

rollmeanEMA(x,5)
#[1] 14.24000 14.03000 13.60333 13.43250 13.33400 13.22267 13.52844 14.44563
#[9] 16.51042 16.88695

Edit: As I suggested in the comments, replacing the NA part with mean(). This gives a tremendous speedup. Plus, removed the surrounding condition.

y <- rnorm(1000000)

system.time( rollmeanEMA(y,10000) )
#   user  system elapsed
#  0.031   0.003   0.034

system.time( EMA(y,10000) )
#   user  system elapsed
#  0.018   0.002   0.019

Added NA "handling":

rollmeanEMA <- function(vec, len) {
  v_n <- !is.na(vec)
  c( vec[is.na(vec)],
     cumsum(vec[v_n][1:(len-1)]) / seq_along(vec[v_n][1:(len-1)]),
     EMA(vec[v_n], len)[len:length(vec[v_n])])
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...