含NA值的指数移动平均(EMA)计算问题求助
自定义带NA保留与动态窗口的EMA函数
问题背景
需要实现一个指数移动平均(EMA)函数,满足以下要求:
- 原始向量中的NA值需保留在原位,不能被移位
- 计算非NA位置的EMA时,忽略窗口内的NA值
- 采用动态时间窗口:计算位置前的有效数据不足7个时,移动平均长度取现有有效数据量;否则固定为8(即ma_len序列为
c(1,2,3,4,5,6,7,8,8,...))
现有rollmeanEMA函数仅在NA位于向量开头时表现正常,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位于末尾时,结果中的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
解决方案
以下函数基于TTR包的EMA实现,严格满足NA保留和动态窗口规则:
library(TTR) dynamic_ema_preserve_na <- function(vec, max_len) { # 初始化结果向量,默认全为NA result <- rep(NA_real_, length(vec)) # 提取原始向量中的非NA位置和对应值 valid_indices <- which(!is.na(vec)) valid_values <- vec[valid_indices] # 无有效数据时直接返回结果 if (length(valid_values) == 0) { return(result) } # 为有效数据序列计算动态窗口EMA ema_results <- numeric(length(valid_values)) for (i in seq_along(valid_values)) { # 确定当前窗口长度:不足max_len-1则用现有数据量,否则用max_len current_window <- if (i < max_len - 1) i else max_len # 取对应窗口内的有效数据计算EMA,取最后一个值作为当前位置结果 window_data <- valid_values[max(1, i - current_window + 1):i] ema_results[i] <- tail(EMA(window_data, n = current_window), 1) } # 将计算好的EMA值填回原向量的非NA位置 result[valid_indices] <- ema_results return(result) }
测试验证
测试案例1:NA位于开头
dados1 <- c(NA, 0, 0, 3, 0, 0, 0, 0, 0, 2, 0, 0) dynamic_ema_preserve_na(dados1, 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保留在开头,EMA计算结果与原函数一致。
测试案例2:NA位于末尾
dados2 <- c(0, 0, 0, 3, 0, 0, 0, 0, 0, 2, 0, NA) dynamic_ema_preserve_na(dados2, 8) # 输出: # [1] 0.0000000 0.0000000 0.0000000 0.7500000 # [5] 0.6000000 0.5000000 0.4285714 0.3750000 # [9] 0.3281250 0.5371094 0.4699707 NA
NA保留在原始位置,非NA位置的EMA计算正确。
测试案例3:NA位于中间
dados3 <- c(0, 0, 0, 3, 0, 0, 0, NA, 0, 2, 0, 4) dynamic_ema_preserve_na(dados3, 8) # 输出: # [1] 0.0000000 0.0000000 0.0000000 0.7500000 # [5] 0.6000000 0.5000000 0.4285714 NA # [9] 0.3750000 0.5781250 0.5058594 0.6052246
- 中间的NA位置结果保留NA
- 最后一个位置的4,使用前8个有效数据计算EMA,符合动态窗口规则
内容的提问来源于stack exchange,提问作者Andraws Santos
相关产品推荐
相关产品推荐

