首页 > 解决方案 > 当存在 nan 值且 adjust=false 时,如何计算 ewm mean?

问题描述

为了优化 pandas 的 EWM 均值计算,我使用 numba 库对其进行了复制。但是,我无法弄清楚当存在 nan 值时如何进行计算。

该文档指出以下内容:

当 ignore_na 为 False(默认)时,权重基于绝对位置。例如,x 和 y 的权重用于计算 ... (1-alpha)**2 和 alpha 的最终加权平均值(如果调整为 False)。

如果将span数组设置为 2 [1, None, 2],这意味着第三个 EMA 值将计算为:

alpha = 2 / (2 + 1)
((1 - alpha)**2) * 1 + alpha * 2

这是 1.6666。但是执行时的实际值为series.ewm(span=2, adjust=False).mean()[-1]1.85714286。

在 nan 值的情况下,确切的公式是什么?上面的公式没有多大意义,因为权重不相等 - 如果两个权重总和为 1,则更有意义。

标签: pythonpandasnumba

解决方案


在 numpy 中检查以下版本的 panda ewm.mean()。希望这可以帮助。

@jit((float64[:], float64, boolean, boolean), nopython=True, nogil=True)
def _numba_ema(X, alpha, adjust, ignore_na):
    """Exponentialy weighted moving average specified by a decay ``alpha``

    Reference:
    https://stackoverflow.com/questions/42869495/numpy-version-of-exponential-weighted-moving-average-equivalent-to-pandas-ewm

    Example:
        >>> ignore_na = True     # or False
        >>> adjust = True     # or False
        >>> myema = _numba_ema_adjusted(X, alpha=alpha, ignore_na=ignore_na)
        >>> pdema = pd.Series(X).ewm(alpha=alpha, adjust=adjust, ignore_na=ignore_na).mean().values
        >>> print(np.allclose(myema, pdema, equal_nan=True))
        True

    Args:
        X (array): raw data
        alpha (float): decay factor
        adjust (boolean):
            True for assuming infinite history via the recursive form
            False for assuming finite history via the recursive form
        ignore_na (boolean): True for decaying by relative location, False for absolute location

    Returns:
        TYPE: Description
    """
    ewma = np.empty_like(X, dtype=float64)
    offset = 1
    w = 1
    for i, x in enumerate(X):
        if i == 0:
            ewma[i] = x
            ewma_old = x
        else:
            is_ewma_nan = math.isnan(ewma[i - 1])
            is_x_nan = math.isnan(x)
            if is_ewma_nan and is_x_nan:
                ewma[i] = np.nan
            elif is_ewma_nan:
                ewma[i] = x
                ewma_old = x
            elif is_x_nan:
                offset += 1
                ewma[i] = ewma[i - 1]
            else:
                if ignore_na:
                    if adjust:
                        w = w * (1 - alpha) + 1
                        ewma_old = ewma_old * (1 - alpha) + x
                        ewma[i] = ewma_old / w
                    else:
                        ewma[i] = ewma[i - 1] * (1 - alpha) + x * alpha
                else:
                    if adjust:
                        w = w * (1 - alpha) ** offset + 1
                        ewma_old = ewma_old * (1 - alpha) ** offset + x
                        ewma[i] = ewma_old / w
                    else:
                        ewma[i] = (ewma[i - 1] * (1 - alpha) ** offset + x * alpha) / ((1 - alpha) ** offset + alpha)
                    offset = 1
    return ewma

推荐阅读