【问题标题】:Differences between Matlab and Numpy and Python's `round` functionMatlab和Numpy与Python的`round`函数的区别
【发布时间】:2013-09-29 17:32:03
【问题描述】:

简化问题

我可以让 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 舍入语义的问题吗? Furthermore 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

【问题讨论】:

  • 如果您不将值缩放到 int16,两种情况下的读数是否相同?如果是的话,我会进一步检查np.linspace() 后者函数的行为;圆形,interp 和 int16。我猜这可能是圆形或插值函数的行为略有不同?
  • @Faultier 在底部检查我的编辑,看起来区别在于round 的输出(Matlab vs Numpy vs Python)。有什么建议吗?
  • 我认为这是定义的主题 - 你想要什么行为?我只会使用相应的圆形功能。另外,请参阅有关此主题的 numpy 手册草案:docs.scipy.org/doc/numpy/reference/generated/…
  • 我的 0.02 美元:起初可能令人惊讶的是,有多个定义如何舍入恰好介于两个整数之间的值。 The Wikipedia site on rounding has a good explanation on what is called tie-breaking.

标签: python matlab numpy rounding numerical


【解决方案1】:

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

如果您希望在不使用 Python 的情况下进行快速回合,请参阅this answer

总结是,有一个依赖于平台的技巧可以通过ctypes 使用fesetround 设置舍入。来自帖子:

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

【讨论】:

  • “这不依赖于平台,而是一个有目的的实现细节。”这是否意味着 Python 和 Matlab 的这一轮是平台相关的?
  • 不,他们只是使用了不同的方法。 Numpy 使用舍入到偶数,Python 使用舍入到零。第一个对统计更有用,第二个更通用。
  • @Veedrac:实际上,Python 内置的round 从零开始远离
  • 此变通办法的范围是什么?整个可执行文件?当前模块?
  • 另外,它的便携性如何?
【解决方案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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2017-09-25
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 2020-10-23
  • 1970-01-01
  • 2011-03-08
  • 1970-01-01
相关资源
最近更新 更多