在NumPy数组中使用array.dtype = <data type =“”>分配dtype值会产生不明确的结果

时间:2017-07-07 13:34:01

标签: python numpy ipython jupyter-notebook

我是编程和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中那些含糊不清的数字背后的原因。它们是什么以及它们意味着什么?

1 个答案:

答案 0 :(得分:4)

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

当您重新分配数组的dtype属性时,保持基础数据不变,并且您正在以新的方式告诉解释这种位模式。由于解释现在与数据的原始定义不匹配,最终会出现乱码(无意义的数字)。

另一方面,通过.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个。两个全1模式被重新解释为单个16位数字,结果相应地改变。您经常看到更奇怪的数字的原因是,将浮点数重新解释为整数,反之亦然将导致数据更强大,因为浮点数在内存中的表示方式。

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