Numpy均值计算结果随行顺序不同略有差异
浮点运算顺序导致的均值计算差异
我们在测试中使用np.testing.assert_allclose验证两组数据的均值是否一致,但发现数据内容完全相同仅顺序不同时,计算出的均值存在微小差异。以下是最简复现代码:
import numpy as np x = np.array( [[0.5224021, 0.8526993], [0.6045113, 0.7965965], [0.5053657, 0.86290526], [0.70609194, 0.7081201]], dtype=np.float32, ) y = np.array( [[0.5224021, 0.8526993], [0.70609194, 0.7081201], [0.6045113, 0.7965965], [0.5053657, 0.86290526]], dtype=np.float32, ) print("X mean", x.mean(0)) print("Y mean", y.mean(0)) z = x[[0, 3, 1, 2]] print("Z", z) print("Z mean", z.mean(0)) np.testing.assert_allclose(z.mean(0), y.mean(0)) np.testing.assert_allclose(x.mean(0), y.mean(0))
在Python 3.10.6 + NumPy 1.24.2环境下运行,输出如下:
X mean [0.58459276 0.8050803 ] Y mean [0.5845928 0.8050803] Z [[0.5224021 0.8526993 ] [0.70609194 0.7081201 ] [0.6045113 0.7965965 ] [0.5053657 0.86290526]] Z mean [0.5845928 0.8050803] Traceback (most recent call last): File "/home/nuric/semafind-db/scribble.py", line 19, in <module> np.testing.assert_allclose(x.mean(0), y.mean(0)) File "/home/nuric/semafind-db/.venv/lib/python3.10/site-packages/numpy/testing/_private/utils.py", line 1592, in assert_allclose assert_array_compare(compare, actual, desired, err_msg=str(err_msg), File "/usr/lib/python3.10/contextlib.py", line 79, in inner return func(*args, **kwds) File "/home/nuric/semafind-db/.venv/lib/python3.10/site-packages/numpy/testing/_private/utils.py", line 862, in assert_array_compare raise AssertionError(msg) AssertionError: Not equal to tolerance rtol=1e-07, atol=0 Mismatched elements: 1 / 2 (50%) Max absolute difference: 5.9604645e-08 Max relative difference: 1.0195925e-07 x: array([0.584593, 0.80508 ], dtype=float32) y: array([0.584593, 0.80508 ], dtype=float32)
目前可以通过降低断言容差解决,但想了解该现象的原因是什么?
原因分析
这是浮点数精度限制和加法运算的顺序敏感性导致的:
- 浮点数精度限制:你使用的
float32(单精度浮点数)仅支持约7-8位十进制有效数字,无法精确表示所有实数,每次加法运算都会产生微小的舍入误差。 - 加法的顺序影响误差累积:浮点数加法不满足结合律,即
(a + b) + c与a + (b + c)在浮点数运算中结果可能不同。不同的累加顺序会导致舍入误差的累积方式不同,最终总和(进而均值)出现微小差异。你的示例中x和y元素相同但顺序不同,NumPy计算均值时的累加顺序不同,因此产生了约5.96e-08的差异。 - NumPy实现细节:
mean函数底层是先计算总和再除以元素个数,不同顺序的数组会因累加误差累积方式不同,导致最终均值出现细微差别;而z是x按y的顺序重排后的数组,累加顺序与y一致,所以均值完全相同。
解决建议
- 调整断言容差:针对
float32类型,将assert_allclose的rtol(相对容差)调整到1e-6左右,atol(绝对容差)调整到1e-7左右,即可兼容正常的浮点误差:np.testing.assert_allclose(x.mean(0), y.mean(0), rtol=1e-6, atol=1e-7) - 使用更高精度浮点数:改用
float64(双精度浮点数),其有效数字可达15-17位,此类误差会显著缩小,甚至在多数场景下可忽略。
内容的提问来源于stack exchange,提问作者nuric
相关产品推荐
相关产品推荐

