Welford 在线算法(数值稳定的增量标准差)
Welford 在线算法 是专门用来:
在数据一条一条进来时,稳定地计算“均值 + 方差/标准差”
而且不会炸精度,这是它封神的地方。
🌟 它解决什么痛点?
普通做法算方差是:
[
\sigma^2 = E[x^2] - (E[x])^2
]
问题是:
- 两个很大的数相减
- 浮点数精度损失(catastrophic cancellation)
- 数据量大时误差会越来越离谱
在金融高频、传感器数据、实时系统里,这会慢慢把结果算歪。
Welford = 数值稳定 + 实时更新 + 不用存历史数据
🎯 核心思想
每来一个新数据 (x_n),只更新 3 个量:
| 变量 | 含义 |
|---|---|
| n | 当前数据个数 |
| mean | 当前均值 |
| M2 | “平方偏差累计量” |
最终:
[
\text{方差} = \frac{M2}{n} \quad (\text{总体})
]
[
\text{样本方差} = \frac{M2}{n-1}
]
🧠 更新公式(灵魂所在)
新数据:x
n += 1
delta = x - mean_old
mean = mean_old + delta / n
delta2 = x - mean_new
M2 = M2_old + delta * delta2
就这 4 行。
但背后数学非常巧妙:
它避免了“大数减大数”的结构
永远在处理“偏差”,不是平方和
📊 直观理解它在干嘛
当新值进来时:
- 看它离旧平均差多少 →
delta - 更新平均值
- 再看它离新平均差多少 →
delta2 - 把这次对“总体波动”的贡献加进 M2
你可以理解为:
每个新点都在“修正整个波动结构”
💻 Python实现(标准写法)
class RunningStats:
def __init__(self):
self.n = 0
self.mean = 0.0
self.M2 = 0.0
def update(self, x):
self.n += 1
delta = x - self.mean
self.mean += delta / self.n
delta2 = x - self.mean
self.M2 += delta * delta2
@property
def variance(self):
return self.M2 / self.n if self.n > 0 else 0.0
@property
def sample_variance(self):
return self.M2 / (self.n - 1) if self.n > 1 else 0.0
@property
def std(self):
return self.variance ** 0.5
🚀 为什么它在量化 & 实时系统里是标配?
| 场景 | 优势 |
|---|---|
| 实时行情 | tick一条条来,不可能存全部历史 |
| 高频交易 | 精度问题会积累成真钱 |
| 大数据流 | 内存 O(1) |
| 滚动Z-score | 均值 + 标准差随时可用 |
⚔️ 和普通算法对比
| 方法 | 需要存历史 | 精度稳定 | 实时更新 |
|---|---|---|---|
| 直接公式 | ❌ | ❌ | ❌ |
| 先算均值再算方差 | ❌ | 一般 | ❌ |
| Welford | ✅ O(1) | ✅ 极稳 | ✅ |
🔥 一句话本质
Welford = 用“偏差递推”代替“平方和计算”的数值稳定魔法
如果你做的是交易策略或价差 Z-score,这个算法可以直接变成:
- 滚动波动率
- 实时风险估计
- 异常波动检测