我正在尝试创建指数移动平均线。然而,似乎没有一个函数能够以完全相同的方式处理
NA
值。所以我从某人那里找到了一个处理 NA
值的解决方案,但不是我想要的方式:
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])])
}
当我在向量的开头有
NA
时,它工作正常:
dados <- c(NA, 0, 0, 3, 0, 0, 0, 0, 0, 2, 0, 0)
> rollmeanEMA(dados, 8)
[1] NA 0.0000000 0.0000000 1.0000000
[5] 0.7500000 0.6000000 0.5000000 0.4285714
[9] 0.3750000 0.5781250 0.5058594 0.4426270
但是当我将
NA
放在另一个位置时,它的行为不正确,因为它将 NA
移动到向量的开头,而我希望它保持在原来的位置:
dados <- c(0, 0, 0, 3, 0, 0, 0, 0, 0, 2, 0, NA)
> rollmeanEMA(dados, 8)
[1] NA 0.0000000 0.0000000 0.0000000
[5] 0.7500000 0.6000000 0.5000000 0.4285714
[9] 0.3750000 0.3281250 0.5371094 0.4699707```
所以,我实际上希望代码与常规移动平均线完全相同,并忽略
NA
值。也就是说,如果数据是c(0, 0, 0, 3, 0, 0, 0, NA, 0, 2, 0, 4)
,在与NA
的线上,我希望它计算c(0, 0, 0, 3, 0, 0, 0)
的指数移动平均值。
如果它与 4
在线,我希望它计算 c(4, 0, 2, 0)
的指数平均值,忽略 c(NA, 0, 0, 0, 3)
,从而使用时间窗口中的 8
值。
值得注意的是,我正在使用动态时间窗口,因此如果在我要计算平均值的行之前没有
7
先前的数据点,则 ma_len
(移动平均长度)将是之前存在的行数,即每组的 ma_len = c(1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, ...)
。
评论太长了。
据我了解,您希望每次迭代选择八个(过去)
x
值,并计算这些值的指数加权(移动)平均值(〜EMA)。
如果所选序列包含
NA
值,您希望忽略这些值并减少 n
(= "要平均的周期数。[...]") 动态 以匹配 的长度所选窗口中的
NA
值,请参阅?TTR::EMA
。
您可以尝试一下
的变体unrecommended = \(x, k) {
# I use k instead of n
y = rep(NA, length(x))
for (i in seq_along(x))
if (i > k) {
rw = na.omit(x[(i-k+1L):i]); l = length(rw)
if(k >= l) y[[i]] = TTR::EMA(rw, k)[[k]] else y[[i]] = TTR::EMA(rw, l)[[l]]
}
y
}
这给出了
> x = c(14.24, 13.82, 12.75, 12.92, 12.94, 13.00, 14.14, 16.28, 20.64, 17.64)
> lapply(c(2,4,6,8), \(k) unrecommended(x, k = k))
[[1]]
[1] NA NA 13.285 12.835 12.930 12.970 13.570 15.210
[9] 18.460 19.140
[[2]]
[1] NA NA NA NA 13.1075 12.9025 13.2500
[8] 14.0900 16.0150 17.1750
[[3]]
[1] NA NA NA NA NA NA
[7] 13.26167 13.67167 14.98667 15.77333
[[4]]
[1] NA NA NA NA NA NA
[7] NA NA 14.56125 15.03875
显然,这种方法是右对齐,您可以用类似于
@Waldi的
NA
的想法替换前导i < k
(由于
EMA2
而自然发生)。
我认为
unrecommended()
背后的做法是错误的。我建议改变方法。请至少查看这些来源
zoo::na.locf()
,请参阅将 NA 更改为插值扁条注意