我可以让Numpy同意Matlab和Python的round
吗?
Matlab 2013a:
>> round(-0.5)
ans =
-1
Python(使用Numpy数组,或只是一个标量,相同的结果):
>>> import numpy
>>> round(numpy.array(-0.5))
-1.0
Numpy,奇怪的是:
>>> import numpy
>>> numpy.round(numpy.array(-0.5))
-0
圆形平台的这种差异是否依赖?
Matlab附带一个包含一些音频数据的文件“handel.mat”:
>> which handel.mat
C:\Program Files\MATLAB\R2013a\toolbox\matlab\audiovideo\handel.mat
>> load handel
>> soundsc(y) % play the short audio clip
我想在Python中处理这些数据,所以我使用scipy.io.loadmat
[1]。具体来说,我想缩放音频的值以跨越16位有符号整数的整个范围,即,音频信号的最小值被映射到-2 ^ 15,最大的值被映射到2 ^ 15-1。在Matlab中这样做给我的结果与Python不同,我感到很惊讶:
Matlab的:
>> load handel
>> int16(round(interp1([min(y), max(y)], [-2^15, 2^15-1], y(1:10))))
ans =
-1 %%% <-- Different from Python
-253
-3074
-1277
252
1560
772
-1025
-1277
-3074
的Python:
In [1]: import numpy as np
In [2]: import scipy.io as io
In [3]: mat = io.loadmat('handel.mat')
In [4]: np.int16(np.round(np.interp(mat['y'][:10], [mat['y'].min(), mat['y'].max()], [-2.0**15, 2.0**15-1.0])))
Out[4]:
array([[ 0], ### <-- Different from Matlab
[ -253],
[-3074],
[-1277],
[ 252],
[ 1560],
[ 772],
[-1025],
[-1277],
[-3074]], dtype=int16)
实际上有1231个样本(总共73113个),Python和Matlab有所不同。我认为我对我的类型很谨慎,但实际上,这里的类型错误的错误表面很少:loadmat
应该从MAT文件中推断出类型,并且int16之间的差异不大这两个系统。
已添加 interp
/ interp1d
命令输出的第一个元素都是-0.5(在Python和Matlab中将其打印到第100个小数位确认了这一点但是,Numpy(np.round
)中的舍入产生0,而Matlab将其舍入为-1。这是Matlab舍入语义的问题吗? 此外 Python的内置非Numpy round
for -0.5给了我-1! Numpy和Python的round
功能之间存在这种差异吗? Python的round
总是匹配Matlab的吗?
Windows64,Matlab 8.1(2013a),Python 2.7.4。
[1] http://docs.scipy.org/doc/scipy/reference/generated/scipy.io.loadmat.html
答案 0 :(得分:2)
我认为您可以利用numpy.vectorize
使用标准python round
函数创建自定义numpy round
函数:
>>> import numpy as np
>>> myround = np.vectorize(lambda x: round(x))
>>> a = np.array([-0.5, 0.5, -1.5, 1.5, -2.5, 2.5, 3.5, -3.5])
>>> print myround(a)
[-1. 1. -2. 2. -3. 3. 4. -4.]
显示与Matlab相同的结果:
>> a = [-1. 1. -2. 2. -3. 3. 4. -4.];
>> round(a)
ans =
-1 1 -2 2 -3 3 4 -4
答案 1 :(得分:1)
numpy.round
,也称为numpy.around
,舍入为最接近偶数值的半整数。这是不平台依赖,但是有目的的实现细节。
如果您希望在不使用Python的情况下进行快速回合,请参阅this answer。
摘要是,通过fesetround
使用ctypes
设置舍入是依赖于平台的黑客攻击。从帖子:
import numpy as np
import ctypes
FE_TONEAREST = 0x0000
FE_DOWNWARD = 0x0400
FE_UPWARD = 0x0800
FE_TOWARDZERO = 0x0c00
libc = ctypes.CDLL('libc.dylib')
v = 1. / (1<<23)
print repr(np.float32(1+v) - np.float32(v/2)) # prints 1.0
libc.fesetround(FE_UPWARD)
print repr(np.float32(1+v) - np.float32(v/2)) # prints 1.0000002