【问题标题】:Assigning dtype value using array.dtype = <data type> in NumPy arrays gives ambiguous results在 NumPy 数组中使用 array.dtype = <data type> 分配 dtype 值会产生模棱两可的结果
【发布时间】:2017-07-07 13:34:00
【问题描述】:

我是编程和 numpy 的新手...在阅读教程和在 jupyter-notebook 上进行实验时...我想到了将 numpy 数组的 dtype 转换如下:

import numpy as np
c = np.random.rand(4)*10
print c
#Output1: [ 0.12757225  5.48992242  7.63139022  2.92746857]
c.dtype = int
print c
#Output2: [4593764294844833304 4617867121563982285 4620278199966380988 4613774491979221856]

我知道正确的改变方法是:

c = c.astype(int)

但我想知道 Output2 中那些模棱两可的数字背后的原因。它们是什么,它们代表什么?

【问题讨论】:

  • 允许直接分配让我几乎感到惊讶。只是感觉很危险。直接赋值shape也是可以的,不过我很少用。
  • @hpaulj 与 strides 相同,我宁愿不理会所有这些属性。

标签: python numpy ipython jupyter-notebook


【解决方案1】:

浮点数和整数(numpy.float64s 和 numpy.int64s)在内存中的表示方式不同。这些不同类型中存储的值 42 对应于内存中不同的位模式。

当您重新分配数组的 dtype 属性时,您会保持底层数据不变,并且您告诉 numpy 以一种新的方式解释该位模式。由于现在的解释与数据的原始定义不匹配,因此您最终会得到胡言乱语(无意义的数字)。

另一方面,通过.astype() 转换数组实际上会转换内存中的数据:

>>> import numpy as np
>>> arr = np.random.rand(3)
>>> arr.dtype
dtype('float64')
>>> arr
array([ 0.7258989 ,  0.56473195,  0.20885672])
>>> arr.data
<memory at 0x7f10d7061288>
>>> arr.dtype = np.int64
>>> arr.data
<memory at 0x7f10d7061348>
>>> arr
array([4604713535589390862, 4603261872765946451, 4596692876638008676])

正确转换:

>>> arr = np.random.rand(3)*10
>>> arr
array([ 3.59591191,  1.21786042,  6.42272461])
>>> arr.astype(np.int64)
array([3, 1, 6])

如您所见,使用astype 将有意义地转换数组的原始值,在这种情况下它将截断为整数部分,并返回一个具有对应值和dtype 的新数组。

请注意,分配新的dtype 不会触发任何检查,因此您可以对数组进行非常奇怪的操作。在上面的示例中,64 位浮点数被重新解释为 64 位整数。但您也可以更改位大小:

>>> arr = np.random.rand(3)
>>> arr.shape
(3,)
>>> arr.dtype
dtype('float64')
>>> arr.dtype = np.float32
>>> arr.shape
(6,)
>>> arr
array([  4.00690371e+35,   1.87285304e+00,   8.62005305e+13,
         1.33751166e+00,   7.17894062e+30,   1.81315207e+00], dtype=float32)

通过告诉 numpy 你的数据占用了原来一半的空间,numpy 会推断出你的数组有两倍的元素!显然不是你应该想做的事。


另一个例子:考虑 8 位无符号整数 255==2**8-1:它对应于二进制的 11111111。现在,尝试将其中两个数字重新解释为一个 16 位无符号整数:

>>> arr = np.array([255,255],dtype=np.uint8)
>>> arr.dtype = np.uint16
>>> arr
array([65535], dtype=uint16)

如您所见,结果是单个数字 65535。如果它没有响起,它正好是 2**16-1,其二进制模式中有 16 个。两个全一模式被重新解释为一个 16 位数字,结果也相应改变。您经常看到奇怪数字的原因是,由于浮点数在内存中的表示方式,将浮点数重新解释为整数(反之亦然)会导致数据更严重。


作为hpaulj noted,您可以通过使用修改后的dtype 构造数组的新view,直接对数据进行这种重新解释。这可能比必须重新分配给定数组的dtype 更有用,但是再次更改dtype 仅在相当少见、非常具体的用例中有用。

【讨论】:

    猜你喜欢
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-02
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    相关资源
    最近更新 更多