【问题标题】:numpy array casting ruled not 'safe'numpy 数组强制转换规则不“安全”
【发布时间】:2015-05-05 09:34:42
【问题描述】:

用另一个索引一个 numpy 数组 - 两者都定义为 dtype='uint32'。使用 numpy.take 进行索引并获得不安全的转换错误。以前没有遇到过这个。知道发生了什么吗?

Python 2.7.8 |Anaconda 2.1.0 (32-bit)| (default, Jul  2 2014, 15:13:35) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.

>>> import numpy
>>> numpy.__version__
'1.9.0'

>>> a = numpy.array([9, 7, 5, 4, 3, 1], dtype=numpy.uint32)
>>> b = numpy.array([1, 3], dtype=numpy.uint32)
>>> c = a.take(b)

Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    c = a.take(b)
TypeError: Cannot cast array data from dtype('uint32') to dtype('int32') according to the rule 'safe'

【问题讨论】:

  • 运行 python 3.4.3 64 位和 numpy '1.9.2rc1' 时没有收到警告
  • 我认为问题在于将a.take(b) 分配给c。尝试在c = a.take(b)之前设置c =numpy.array(0,dtype=numpy.uint32)
  • 在 Python 2.7.5 64 位和 numpy 1.9.1 中也没有警告。
  • 更新到 numpy 1.9.2 但仍然是同样的错误。设置 c=numpy.array(0, dtype=numpy.uint32) 也不起作用。在 Windows 32 位 XP 和 Windows 8.1 上的结果相同。奇怪!
  • 我将这个问题解释如下。 NumPy 使用有符号整数进行索引(毕竟a[-1] 的工作方式就像在 Python 列表中一样)。当它发现索引数组具有错误的 dtype 时,它​​会尝试将索引数组转换为有符号整数数组(如果b 是一个数组,例如int16,这将是合理的并产生合理的结果)。由于这种转换对于uint32 的数组是不安全的——例如,最大的uint32 值将变为-1,一个相当不同的索引——NumPy 会引发错误。在使用take 之前,您可能需要自己转换b 的dtype。

标签: python arrays numpy types casting


【解决方案1】:

这在处理需要指定索引或长度的 NumPy 函数时很常见(不仅仅是take,请参见例如here)。

问题在于,出于索引目的,NumPy 想将您的 uint32 数组视为 int32 数组(这可能是 32 位系统上的“指针”整数类型 np.intp)并希望将其转换为该类型。

它不能安全地执行此操作 - 无符号数组中的某些整数可能无法表示为有符号 32 位整数。您看到的错误反映了这一点。

这意味着如果 b 具有 dtype int64 或 float dtype,但如果它是 int32 或更小的整数 dtype,则不会出现相同的错误。

对于它的价值,这对于索引符号a[b] 来说不是一个直接的问题,它允许不安全的强制转换(但如果索引超出范围则会引发错误)。尝试例如 a[2**31] - NumPy 转换为 int32 但随后抱怨索引 -2147483648 超出范围。

【讨论】:

  • 谢谢!我通常使用 a[b] 但这应该比 .take 慢。无论如何,会坚持有效的!
  • 在 1.9.x 中不再慢了。并且这种行为可能应该被报告为一个错误,np.take 应该做与索引相同的事情:一旦确认索引是一个整数,就使用不安全的强制转换,例如在 32 位系统上a[2**32-1] 返回a[-1],因为2**32-1 被转换为np.uint32,然后不安全地转换为np.int32。这种极端情况下的错误行为比使np.uint32 无法用作索引更令人讨厌。
  • @Jaime 很高兴听到 a[b] 类型的索引不再慢。我会在关于 np.take 的 numpy 邮件列表上写一个便条。谢谢!
猜你喜欢
  • 2022-08-20
  • 2019-08-26
  • 1970-01-01
  • 1970-01-01
  • 2013-04-19
  • 1970-01-01
  • 2015-08-31
  • 1970-01-01
  • 2017-10-12
相关资源
最近更新 更多