numpy數據類型說明以及自動轉換陷阱

       numpy的dtype是一個很重要的概念,因爲numpy爲了性能,優化了內存管理,ndarray的值在內存中幾乎是連續的,同時其每個元素的內存大小也被設計成是一樣的,因此,當生成ndarray時,每個元素的數據類型都會被轉爲相同的類型,這時如果原生的數據類型是不一樣的,那麼就涉及到一個數據類型轉換的問題,即data type casting。

       明白numpy中的數據類型轉換可以有效的避免和理解很多的行爲,因爲numpy中很多的error往往都是有數據類型轉換引起的,所以理解numpy的數據類型轉換可以預防和排查很多的問題。首先,在numpy中有很多的數據類型,多於python內置數據類型,具體有哪些類型,可以參看下圖,下圖的columns和index是數據類型在numpy中的符號,具體的釋義可以查看這裏。下面,我們重點講一下numpy中關於數據類型以及轉換中容易碰到的陷進或者需要注意的點。

一、數據類型的表示

       在numpy中,一個數據類型實際上是一個dtype對象,其有一些重要的屬性,比如字節順序、數據類型、字節數大小等,一般的,numpy中的數據類型會表示成類似'<i4'這樣,這個表示法中,<表示字節順序,i表示數據類型,這裏表示整數,4表示一個元素佔據的字節數,這裏4字節,表示32位整數。

二、構造ndarray時的dtype

       在構造ndarray時,可以指定dtype參數來設置ndarray裏面元素的數據類型,這個dtype可以用'i4'這樣的表示方式,也可以用int表示,但是後者沒法指定字節數。要注意的是,指定dtype時,一定要確認這個dtype可以兼容所有元素,防止溢出或者不兼容,對此我們可以通過result_type(*array_like)來判斷我們應該設定的dtype,這個函數返回的dtype是可以兼容所有元素的最小size的數據類型;或者我們無需設定,其會自動進行數據類型的轉換,我們也可以通過ndarray.dtype屬性查看數據類型。Anyway,我們要有這種數據類型轉換的意識,因爲這會影響後續對ndarray的操作。

三、不同數據類型之間的轉換兼容性

       numpy的數據類型之間能夠實現轉換,可以通過np.can_cast(fromtype,totype)這個函數來判斷,更詳細的可以查看下圖。

四、numpy對python對象數據類型'O'的處理

       當numpy中有python獨有的原生數據類型,比如Decimal,那麼ndarray會被轉爲object數據類型,表示python對象數據類型,當然這裏也可以轉爲字符串,但是字符串對於np.nan往往會佔據更大的itemsize。

       當numpy函數對dtype位object的ndarray處理時,會先把裏面的元素再進一步轉爲其他numpy的數據類型,這樣纔可以操作,所以這裏如果函數沒法或沒有指定類型參數,那麼會默認以第一個inner loop到的數據類型作爲所有元素的類型,並以此類型進行後續轉換,這時,對於object類型的ndarray來說,往往容易出現數據無法轉換成功的異常。所以要注意處理時第一個inner loop遇到的元素的類型是否可以兼容後面要處理的所有元素,不然會拋出異常。看下面的例子說明。

import numpy as np
from decimal import Decimal

arr=np.array([[1,2.0,3],['a',3,np.nan],[2,np.nan,Decimal('5')]])
arr1=np.apply_along_axis(lambda x:x[0],arr=arr,axis=1)
arr1
# output:
# ValueError: invalid literal for int() with base 10: 'a'

arr2=np.apply_along_axis(lambda x:x[1],arr=arr,axis=1)
arr2
# output:
# array([ 2.,  3., nan])

arr2=np.apply_along_axis(lambda x:x[2],arr=arr,axis=1)
arr2
# output:
# array([          3, -2147483648,           5])

       從上面的例子中可以看到,arr1中,由於第一個inner loop遇到的元素是整數1,所以便會以整數類型對後續的元素進行轉換,但是後面的一個元素是字符'a',無法將其轉爲int,因此就會報上述error;arr2中,第一個遇到的元素是2.0,爲float,所以後面的元素都會被轉爲float,因此輸出爲array([ 2.,  3., nan]),其中都變成了float,要注意的是,由於np.nan本身就是一個浮點數,因此這裏可以正確的轉換,轉換之後還是np.nan;但是看arr2,由於第一個遇到的元素類型爲int32,後面的np.nan爲float64,會造成溢出,這樣便無法正確的轉換,從而會用int32最接近np.nan的值去替換,所以就是-2**31==-2147483648,這裏之所以是2**31,而不是2**32-1,是因爲這裏的int是signed int,即有正負號的int,所以其範圍是-2**31~2**31-1;而Decimal('5')被轉爲了int 5,所以就出現了上述的結果。

       所以,當要被轉成ndarray的原始數據中有np.nan時,要特別注意這一點,最好是指定float類型,注意其他數據的兼容;而如果同時又是obejct數據類型時,那麼同時也要注意第一個inner loop遇到的元素的數據類型,注意和後面的數據類型保持兼容。

五、結語

       numpy的dtype有諸多陷進,需要小心對待,謹慎覈查,然後靈活運用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章