浮點和整數(numpy.float64
s和numpy.int64
s)在內存中的表示方式不同。存儲在這些不同類型中的值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個。兩個全1模式被重新解釋爲一個16位數字,結果相應改變。你經常看到更多的數字的原因是重新解釋浮點數,因爲整數反過來也會導致更強大的數據混亂,這是由於浮點數在內存中的表示方式。
hpaulj noted如,可以直接通過構建陣列的新view
與改性dtype
執行數據的此重新解釋。這可能比必須重新分配給定數組的dtype
更有用,但是再次更改dtype
僅在相當少見的非常具體的用例中才有用。
我幾乎驚訝於直接分配是允許的。它只是感覺危險。直接分配'形狀'也是允許的,但我很少使用它。 – hpaulj
@hpaulj與'strides'一樣的東西,我寧願留下所有這些屬性。 –