时间序列分析论文翻译与笔记:The correct way to start an Exponential Moving Average (EMA)

        在之前的笔记中,我们初步认识了指数移动平均(指数加权移动平均),本文将通过翻译一篇David Owen 在2017年的一篇博客,讨论如何确保移动平均数能够通过识别记录信息的时长,来适应新的信息。原文链接:点击这里(原文的代码为R,本文将补充py代码)

目录

如何正确地开始指数移动平均(EMA)

错误的方法

正确的方法


如何正确地开始指数移动平均(EMA)

        指数移动平均(EMA)是一个非常有用的工具。它可以让我们计算最近数据的平均值。但是,不同于简单移动平均(SMA),我们不需要保留一个样本窗口——我们可以在线更新EMA,一次一个样本。

错误的方法

        假设我们有如下的输入数据:

        x = [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]

 

        最直接的方法是让EMA的初始值为某个任意常数(通常为0)。这意味着EMA的初始值会偏向这个常数,需要足够多的样本来“预热”后才能得到准确的结果。代码如下:

R:

make.ema0 <- function (r) {
    s <- 0
    list(
        update=function (x) {
            s <<- r * s + (1 - r) * x
        }
    )
}

m0 <- make.ema0(0.7)

for (i in 1:length(x)) {
    y0[i] <- m0$update(x[i])
}

py:

import matplotlib.pyplot as plt

def make_ema0(r):
    s = 0
    def update(x):
        nonlocal s
        s = r * s + (1 - r) * x
        return s
    return update

x = [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
ema0 = make_ema0(0.7)
y0 = [ema0(xi) for xi in x]

# 绘制初始值为0的EMA曲线图
plt.figure(figsize=(10, 6))
plt.plot(x, label='Original Data', marker='o')
plt.plot(y0, label='EMA with initial value 0', marker='x')
plt.title('EMA with initial value 0')
plt.xlabel('Time')
plt.ylabel('Value')
plt.legend()
plt.grid(True)
plt.show()

        另一种常见的方法是将第一个样本作为EMA的初始值。代码如下:

R:

make.ema1 <- function (r) {
    started <- FALSE
    s <- NULL
    list(
        update=function (x) {
            if (!started) {
                started <<- TRUE
                s <<- x
            } else {
                s <<- r * s + (1 - r) * x
            }
        }
    )
}

m1 <- make.ema1(0.7)

for (i in 1:length(x)) {
    y1[i] <- m1$update(x[i])
}

py:

def make_ema1(r):
    started = False
    s = None
    def update(x):
        nonlocal started, s
        if not started:
            started = True
            s = x
        else:
            s = r * s + (1 - r) * x
        return s
    return update

ema1 = make_ema1(0.7)
y1 = [ema1(xi) for xi in x]

# 绘制初始值为第一个样本的EMA曲线图
plt.figure(figsize=(10, 6))
plt.plot(x, label='Original Data', marker='o')
plt.plot(y1, label='EMA with first sample as initial value', marker='x')
plt.title('EMA with first sample as initial value')
plt.xlabel('Time')
plt.ylabel('Value')
plt.legend()
plt.grid(True)
plt.show()

        以上两种方法都有一个共同的错误。在第一种方法中,我们假设在第一个实际样本之前看到了一串无限的0。在第二种方法中,我们假设在开始前看到了一串无限的第一个样本。无论哪种方法,都需要足够的时间让EMA“预热”,即需要足够的时间使得假想的无限序列的影响变得可以忽略不计。

正确的方法

        正确的方法是积极考虑进入EMA的数据量,以及在我们的样本到达之前EMA值中的虚拟数据量。

        假设 r=0.5,我们的前三个样本依次为:3、4、5。计算指数加权和,并除以权重和,得到期望的EMA:

        如果使用初始值为0的方法,得到:

s0=3.875(5×0.5+4×0.25+3×0.125+0×0.125)

        如果使用第一个样本作为初始值的方法,得到:

s1=4.25(5×0.5+4×0.25+3×0.25)

        正确的方法是考虑到我们已经看到了一串无限的数据,初始化我们的EMA,并尝试消除其影响。

        假设 α=0,那么分子自动处理: 

        剩下的就是适当地缩放结果以考虑分母中的额外权重。下面的代码执行了这个修正并给出了正确的EMA: 

R:

make.ema2 <- function (r) {
    s <- 0
    extra <- 1
    list(
        update=function (x) {
            s <<- r * s + (1 - r) * x
            extra <<- r * extra
            s / (1 - extra)
        }
    )
}

 py:

def make_ema2(r):
    s = 0
    extra = 1
    def update(x):
        nonlocal s, extra
        s = r * s + (1 - r) * x
        extra = r * extra
        return s / (1 - extra)
    return update

ema2 = make_ema2(0.7)
y2 = [ema2(xi) for xi in x]

# 绘制正确初始化的EMA曲线图
plt.figure(figsize=(10, 6))
plt.plot(x, label='Original Data', marker='o')
plt.plot(y2, label='Corrected EMA', marker='x')
plt.title('Corrected EMA')
plt.xlabel('Time')
plt.ylabel('Value')
plt.legend()
plt.grid(True)
plt.show()

         这个修正可能对你的数据平均值不太重要,但同样的技术可以用来获得有意义和有用的指数移动方差等相关值。通过这些,可以构建一个完全在线的回归来拟合数据,并具有有意义的置信区间和预测区间。

相关推荐

  1. 【sklearn | 3】时间序列分析自然语言处理

    2024-07-14 19:04:02       27 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 19:04:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 19:04:02       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 19:04:02       58 阅读
  4. Python语言-面向对象

    2024-07-14 19:04:02       69 阅读

热门阅读

  1. SQL多表查询

    2024-07-14 19:04:02       20 阅读
  2. 高通平台sensor初始化步骤

    2024-07-14 19:04:02       23 阅读
  3. pid内容索引

    2024-07-14 19:04:02       18 阅读
  4. C++ 异常

    2024-07-14 19:04:02       20 阅读
  5. 嵌入式是Linux:shell使用解析

    2024-07-14 19:04:02       25 阅读