精度,为什么Matlab和Python numpy的输出差异如此大?
我知道基本的数据类型,比如浮点数(float,double)不能精确表示某些数字。
在把一些代码从Matlab移植到Python(Numpy)时,我发现计算结果有很大的差异,我觉得这可能和精度有关。
举个例子,下面的代码是对一个500维的向量进行z标准化,只有前两个元素有非零值。
Matlab代码:
Z = repmat(0,500,1); Z(1)=3;Z(2)=1;
Za = (Z-repmat(mean(Z),500,1)) ./ repmat(std(Z),500,1);
Za(1)
>>> 21.1694
Python代码:
from numpy import zeros,mean,std
Z = zeros((500,))
Z[0] = 3
Z[1] = 1
Za = (Z - mean(Z)) / std(Z)
print Za[0]
>>> 21.1905669677
除了Python显示的数字位数稍多一点外,我觉得差别非常大,超过了0.02。
据我所知,Python和Matlab都使用64位的数据类型。Python用的是'numpy.float64',Matlab用的是'double'。
为什么差别会这么大?哪个更准确呢?
3 个回答
根据SciPy的文档,std
函数有一个叫做ddof
的参数:
ddof : 整数,选填
这个参数代表“自由度的增量”。在计算时,使用的除数是 N - ddof,其中 N 是元素的数量。默认情况下,ddof 的值是零。
在 numpy 中,ddof
默认是零,而在 MATLAB 中则是一个。所以,我认为这可能会解决问题:
std(Z,ddof=1)
针对你的问题,不是精度的问题。正如@rocksportrocker所说,标准差有两种常用的计算方法。MATLAB中的std
函数提供了这两种方法,但默认使用的和你在Python中用的不同。
你可以试试用 std(Z,1)
,而不是 std(Z)
:
Za = (Z-repmat(mean(Z),500,1)) ./ repmat(std(Z,2),500,1);Za(1)
sprintf('%1.10f', Za(1))
这样在MATLAB中会得到
Za(1) = 21.1905669677
关于这两种结果哪个更适合你的需求,可以看看rockspotrocker的回答哦;-)。
也许差异来自于 mean
和 std
的调用。先比较这两个。
对于 std
,有几种不同的定义,有些使用的是平方根的
1 / n * sum((xi - mean(x)) ** 2)
而其他的则使用
1 / (n - 1) * sum((xi - mean(x)) ** 2)
来代替。
从数学的角度来看,这些公式是用来估算正态分布随机变量的方差的。这个分布有两个参数 sigma
和 mu
。如果你知道 mu
的确切值,那么 sigma ** 2
的最佳估算公式是
1 / n * sum((xi - mu) ** 2)
如果你需要通过数据来估算 mu
,使用 mu = mean(xi)
,那么 sigma**2
的最佳估算公式是
1 / (n - 1) * sum((xi- mean(x))**2)