5

简化问题

我可以让 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 roundfor -0.5 给了我 -1!Numpy 和 Pythonround函数之间的这种差异从何而来?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

4

2 回答 2

2

我认为您可以利用标准 python函数numpy.vectorize创建自定义 numpy函数:roundround

>>> 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
于 2013-09-24T14:10:47.800 回答
1

numpy.round,也称为numpy.around,四舍五入到最接近的半整数偶数值。依赖于平台,而是一个有目的的实现细节。

如果您希望在不使用 Python 的情况下快速进行一轮,请参阅此答案

总结是有一个平台相关的黑客可以使用fesetroundvia设置舍入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
于 2013-09-24T14:10:42.937 回答