numpy - 为什么均值和标准差对于相同的值不稳定?

问题描述

问题

为什么相同的值 -3.29686744 会导致不同的均值和标准差?

预期

X = np.array([
    [-1.11793447,-3.29686744,-3.50615096],[-1.11793447,-3.50615096]
])

mean = np.mean(X,axis=0)
print(f"mean is \n{mean}\nX-mean is \n{X-mean}\n")

sd = np.std(X,axis=0)
print(f"SD is \n{sd}\n")

结果:

mean is 
[-1.11793447 -3.29686744 -3.50615096]
X-mean is 
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]

SD is 
[0. 0. 0.]

意外

X = np.array([
    [-1.11793447,axis=0)
print(f"SD is \n{sd}\n")

结果是:

mean is 
[-1.11793447 -3.29686744 -3.50615096]
X-mean is 
[[0.0000000e+00 4.4408921e-16 4.4408921e-16]
 [0.0000000e+00 4.4408921e-16 4.4408921e-16]
 [0.0000000e+00 4.4408921e-16 4.4408921e-16]
 [0.0000000e+00 4.4408921e-16 4.4408921e-16]
 [0.0000000e+00 4.4408921e-16 4.4408921e-16]]

SD is 
[0.0000000e+00 4.4408921e-16 4.4408921e-16]

解决方法

当您考虑 IEEE-754 双精度浮点数存储为 64 位数据时,这是正常行为。 53 位是尾数 10 位是指数,一位是符号。您可以在别处查找详细信息。

重要的部分是浮点数有效地存储为具有比例因子的整数。这是科学记数法的二进制模拟。事实上,您可以使用更熟悉的十进制科学记数法来直观地了解正在发生的事情。

假设您有三位数的小数精度可用,并且您想计算 [2.31e2,2.31e2,2.31e2] 的平均值。总和为 6.93e2,因此均值明确为 2.31e2。但是如果你的数组是 [2.31e2,2.31e2] 呢?现在总和是 1.155e3,但只有三位数可用,您能做的最好是 1.15e31.16e3,具体取决于您是截断还是舍入。除以五和截断/四舍五入得到 2.30e22.32e2。当您的总和与原始数字的比例不同时,通常会出现一些量化误差。

希望您能看到这也直接转化为二进制表示:您会看到最后一位数字的差异与均值运算期间尺度变化的差异。

注意 2^-53 ~= 1.11e-16。鉴于 X 中所有元素的比例约为 1,这与您看到的量化误差非常吻合。

这与 Is floating point math broken?

密切相关