
Welford 算法计算的是样本方差(自由度为 n−1),而 NumPy 的 np.var() 默认计算总体方差(自由度为 n);二者本质定义不同,并非数值误差所致,只需统一自由度参数(如 ddof=1)即可完全一致。
welford 算法计算的是样本方差(自由度为 n−1),而 numpy 的 `np.var()` 默认计算总体方差(自由度为 n);二者本质定义不同,并非数值误差所致,只需统一自由度参数(如 `ddof=1`)即可完全一致。
在流式统计计算中,Welford 算法因其数值稳定性与单次遍历特性被广泛用于在线均值与方差估计。然而,初学者常误将 welford.var_s 与默认调用的 np.var() 直接对比,进而发现微小但显著的差异(如示例中约 0.012 的偏差),并怀疑是浮点累积误差或实现缺陷所致。实际上,该差异源于统计定义的根本区别,而非数值精度问题。
核心区别:自由度(Degrees of Freedom)
样本方差(Sample Variance):
公式为
[ s^2 = \frac{1}{n-1} \sum_{i=1}^{n} (x_i - \bar{x})^2 ]
用于从样本推断总体,具有无偏性。Welford 实现中的 var_s 即为此定义,对应 ddof=1(Delta Degrees of Freedom = 1)。总体方差(Population Variance):
公式为
[ \sigma^2 = \frac{1}{n} \sum_{i=1}^{n} (x_i - \mu)^2 ]
假设数据即全体总体。np.var() 默认行为即为此,等价于 ddof=0。
因此,正确对齐的关键在于显式指定 ddof 参数:
import numpy as np from welford import Welford np.random.seed(42) random_sample = np.random.normal(0, 1, 100) # ✅ 匹配 Welford 的样本方差(var_s) np_var_sample = np.var(random_sample, ddof=1, dtype=np.longdouble) welford = Welford() welford.add_all(random_sample) np.testing.assert_allclose(np_var_sample, welford.var_s, atol=1e-15) # 通过 # ✅ 或匹配总体方差(var_p) np_var_pop = np.var(random_sample, ddof=0, dtype=np.longdouble) np.testing.assert_allclose(np_var_pop, welford.var_p, atol=1e-15) # 同样通过
注意事项与最佳实践
- ❌ 不要盲目改用 Decimal:Welford 算法本身在 float64 下已具备优异数值稳定性;差异来自统计语义,非浮点误差。
- ✅ 明确业务需求:若用于描述性统计(如数据集自身离散程度),用总体方差(var_p / ddof=0);若用于统计推断(如假设检验、置信区间),必须用样本方差(var_s / ddof=1)。
- ? 验证一致性时,优先使用 np.testing.assert_allclose()(支持容差)而非 assertAlmostEqual,更鲁棒地处理浮点比较。
- ? Welford 类同时暴露 var_s(样本)和 var_p(总体)属性,应根据场景主动选择,避免隐式假设。
综上,Welford 与 NumPy 方差结果不一致并非 bug,而是统计约定的自然体现。理解 ddof 的含义并显式对齐,是确保算法可复现、结果可解释的前提。

















