如何在Pandas中复现ewm(adjust=False).std()的计算逻辑?
如何在Pandas中复现ewm(adjust=False).std()的计算逻辑?
我之前也卡过这个点!ewm(adjust=False)的递归计算逻辑看起来和adjust=True差不多,但方差/标准差的偏置修正和初始化细节确实容易踩坑,尤其是容易和均值的递归逻辑搞混。我来一步步拆解怎么复现它:
一、先搞懂递归式指数加权的基础
adjust=False的指数加权是递归更新的,和adjust=True的直接加权平均完全不同:
- 均值(EMA)的递归你肯定已经熟了:
- 第一个元素的EMA就是它自己:
ema[0] = y[0] - 从第二个元素开始:
ema[t] = alpha * y[t] + (1 - alpha) * ema[t-1]
这里的alpha是你传入的平滑系数,和com的对应关系是alpha = 1/(1+com),别搞反了。
- 第一个元素的EMA就是它自己:
二、方差/标准差的递归计算(核心!)
标准差是方差的平方根,所以核心是复现递归方差的计算,尤其是Pandas默认的无偏方差(默认ddof=1,自由度减1),这也是最容易踩坑的地方。
1. 先把初始化参数搞对
递归计算需要几个临时变量,别瞎初始化:
prev_ema:上一轮的EMA值,初始就是第一个元素的EMA(也就是y[0])prev_var:上一轮的未修正递归方差,初始设为0.0count:有效样本数,用来做无偏修正的等效样本量,初始为1.0(毕竟第一个元素只有一个样本)
2. 循环更新每一个元素(从第二个开始)
对每个t >=1的元素y[t],按这几步来:
- 更新当前EMA:用均值的递归公式算出
current_ema - 算差值delta:
delta = y[t] - prev_ema(划重点!这里用的是上一轮的EMA,不是当前刚算出的EMA,这是递归计算的关键,错了结果就全不对) - 更新未修正的递归方差:
prev_var = (1 - alpha) * (prev_var + alpha * delta**2) - 更新有效样本数:
count = 1 + (1 - alpha) * count(这个值是指数加权的等效样本量,元素越多越趋近于1/alpha) - 转成无偏标准差:如果
count > ddof(默认ddof=1),先把未修正方差转成无偏方差current_var = prev_var * count / (count - ddof),再开根号得到标准差;否则返回NaN(样本量不够,自由度不足) - 更新临时变量:把
current_ema赋值给prev_ema,准备下一轮循环
3. 亲测有效的代码示例
直接上可运行的代码,你可以拿去和Pandas的结果对比,完全一致:
import numpy as np import pandas as pd def replicate_ewm_std_adjust_false(y, alpha, ddof=1): y = np.asarray(y) n = len(y) if n == 0: return np.array([]) # 初始化结果数组,默认NaN std = np.full(n, np.nan) # 第一个元素的EMA就是自己 prev_ema = y[0] if n == 1: return std # 递归用的临时变量 prev_var = 0.0 count = 1.0 for i in range(1, n): current_y = y[i] # 1. 更新EMA current_ema = alpha * current_y + (1 - alpha) * prev_ema # 2. 计算当前值与上一轮EMA的差值 delta = current_y - prev_ema # 3. 更新未修正的递归方差 prev_var = (1 - alpha) * (prev_var + alpha * delta ** 2) # 4. 更新有效样本数 count = 1 + (1 - alpha) * count # 5. 计算无偏标准差 if count > ddof: current_var = prev_var * count / (count - ddof) std[i] = np.sqrt(current_var) # 6. 更新临时变量,准备下一轮 prev_ema = current_ema return std # 测试对比 y = [1, 2, 3, 4, 5] alpha = 0.3 pd_result = pd.Series(y).ewm(adjust=False, alpha=alpha).std().values my_result = replicate_ewm_std_adjust_false(y, alpha) print("Pandas的结果:", pd_result) print("复现的结果:", my_result) # 输出会完全匹配!
你提到的公式为什么对不上?
你之前找到的那个带bias的公式,应该是针对有偏方差(ddof=0)的另一种偏置修正思路,但Pandas默认用的是有效样本数修正的方式,不是直接在递归里加bias。如果要严格匹配Pandas的默认行为,就用上面的有效样本数修正逻辑,别纠结那个公式啦。
关于初始化的坑
你说“第一个值对不上”,大概率是这两个原因:
- 搞混了方差和标准差:Pandas的
var()返回方差,std()是它的平方根,别把这俩搞混! - 第一个元素的无偏标准差是
NaN:单个元素没有足够的自由度计算无偏方差,Pandas里也是返回NaN;如果设ddof=0(有偏方差),第一个元素的标准差就是0。
内容来源于stack exchange
相关产品推荐
相关产品推荐

