資料分析入門——numpy類庫基礎知識
numpy類庫是資料分析的利器,用於高效能的科學計算和資料分析。使用python進行資料分析,numpy這個類庫是必須掌握的。numpy並沒有提供強大的資料分析功能,而是它提供的ndarray資料結構能夠讓你快速的處理海量的資料。
shape和dtype屬性
ndarray是numpy的多維陣列物件,是numpy類庫中主要的資料結構,它有兩個重要的屬性,shape和dtype,shape是描述陣列維度的元組,dtype用於說明陣列資料型別。
data = [1,2,3,4,5] arr1 = np.array(data) arr1 Out[6]: array([1, 2, 3, 4, 5]) arr1.shape Out[7]: (5,) arr1.dtype Out[8]: dtype('int32')
上面程式碼說明可arr1是長度為5的一維陣列,資料型別是int32。
ndarray陣列的資料都是整數時,資料型別是int32,當有小數時,資料型別則是float64。
ndarray陣列中的資料必須是同一型別,如果有不同型別的資料,dtype為<U11
。
numpy主要用於處理資料,因此ndarray陣列中的資料必須是同一資料型別,否則無法進行數學計算。
建立ndarray
numpy提供了array函式建立ndarray物件,array函式要傳入一個list列表型別的物件。
list1 = [1.2,2.3,4.6,7.8] ndarray1 = np.array(list1) ndarray1 Out[22]: array([1.2, 2.3, 4.6, 7.8])
傳入的list列表是等長的多維列表時,建立的是多維的ndarray陣列物件。
list2 = [[1.2,2.3,4.6,7.8],[12.2,13.5,1.6,9.8]] ndarray2 = np.array(list2) ndarray2 Out[25]: array([[ 1.2,2.3,4.6,7.8], [12.2, 13.5,1.6,9.8]])
多維列表的長度不一致時,生成ndarray物件的資料型別dtype就變成object,不是具體的資料型別。
list3 = [[1.2,2.3,4.6,7.8],[12.2,13.5,1.6,9.8,0.8]] ndarray3 = np.array(list3) ndarray3 Out[28]: array([list([1.2, 2.3, 4.6, 7.8]), list([12.2, 13.5, 1.6, 9.8, 0.8])], dtype=object)
numpy還提供了zeros和ones兩個方法分別用於建立值為0或者1的陣列。
使用zero方法建立陣列值為0的ndarray陣列:
np.zeros(5)//建立長度為5,陣列值都為0的ndarray一維陣列 np.zeros((3,4))//建立3行4列,陣列值都為0的二維陣列 np.zeros((3,4,5))//建立維度為3,值為0的ndarray三維陣列。
只用ones方法建立陣列值都為1的ndarray陣列:
np.ones(5)//建立長度為5,陣列值都為1的ndarray一維陣列 np.ones((3,4))//建立3行4列,陣列值都為1的二維陣列 np.ones((3,4,5))//建立維度為3,值為1的ndarray三維陣列。
arange()方法直接呼叫python內建的range()函式生成初始值為0步長為1的陣列:
data3 = np.arange(13) data3 Out[12]: array([ 0,1,2,3,4,5,6,7,8,9, 10, 11, 12])
empty()方法建立一個新的陣列,陣列值是隨機生成,用於佔用記憶體空間:
data4 = np.empty((2,2)) data4 Out[20]: array([[7.32086553e-315, 1.01777082e-311], [0.00000000e+000, 7.31249282e-315]])
型別轉換
ndarray提供astype方法將資料型別轉換為其他的資料型別。
將浮點數轉為整數時,會自動擷取掉小數部分:
data5 = np.array([2.2,3.4,5.6]) data6 = data5.astype(np.int32) data6 Out[23]: array([2, 3, 5])
astype可以將全是數字的字串陣列轉換為數值形式:
data7 = np.array(['2.4','3.5','4.6']) data8 = data7.astype(np.float64) data8 Out[34]: array([2.4, 3.5, 4.6])
陣列間的數學運算
兩個陣列之間是可以進行加減乘除間的數學運算。
兩個陣列之間的相加:
data1 = np.array([1,2,3,4]) data2 = np.array([5,6,7,8]) data3 = data1 +data2 data3 Out[38]: array([ 6,8, 10, 12])
兩個陣列之間相減:
data1 = np.array([1,2,3,4]) data2 = np.array([5,6,7,8]) data3 = data1 - data2 data3 Out[45]: array([-4, -4, -4, -4])
兩個陣列之間相乘:
data1 = np.array([1,2,3,4]) data2 = np.array([5,6,7,8]) data3 = data1 * data2 data3 Out[49]: array([ 5, 12, 21, 32])
兩個陣列之間相除:
data1 = np.array([1,2,3,4]) data2 = np.array([5,6,7,8]) data3 = data1 / data2 data3 Out[53]: array([0.2, 0.33333333, 0.42857143, 0.5])
兩個陣列之間進行數學運算時,陣列之間的shape物件值必須一致,就是長度必須一致。否則會報ValueError: operands could not be broadcast together with shapes 的錯誤:
data1 = np.array([1,2,3,4]) data2 = np.array([5,6,7,8,9]) data3 = data1+ data2
上面的程式碼會報ValueError: operands could not be broadcast together with shapes (4,) (5,) 錯誤,data1陣列的shape為(4,),data2的shape為(5,),兩者不一樣,無法進行數學運算。
陣列的索引和切片
通過索引可以訪問NumPy陣列某個位置上的數值。陣列索引從0開始,於長度-1結束:
data1 = np.arange(10) data1.size Out[73]: 10 data1[0] Out[74]: 0 data1[9] Out[75]: 9 data1[10]
在上面的程式碼中,長度為10的一維度陣列data1,索引從0開始,於9(長度10-1)結束。通過data1[9]訪問到陣列中的第10個元素,如果通過data1[10],則會出現IndexError: index 10 is out of bounds for axis 0 with size 10的錯誤,俗稱陣列越界。
這是一維陣列的情況,對於多維陣列,要想訪問某個具體元素時,必須指定這個元素在每一個維度的索引位置:
data1 = [[[1,2,3],[4,5,6]],[[7,8,9,],[10,11,12]]] data1[1][1][1] Out[85]: 11
上述程式碼中data1是一個2X2X3的三維陣列,要想訪問11,必須指定三個維度上的索引data1[1][1][1]。
data1[1][1]返回的結果是1維的陣列:
data1[1][1] Out[86]: [10, 11, 12]
data1[1]返回的是2維的陣列:
data1[1] Out[87]: [[7, 8, 9], [10, 11, 12]]
data1[1][1][1]和data1[1,1,1]的效果一樣,返回的數值都是11。
NumPy提供在ndarray陣列上進行切片的操作,返回的是ndarray陣列的子檢視。
data1 = np.arange(10) data1[1:4] Out[91]: array([1, 2, 3]) data1[:4] Out[92]: array([0, 1, 2, 3]) data1[4:] Out[93]: array([4, 5, 6, 7, 8, 9])
data1[1:4]切片操作返回的是從索引1開始,到索引4結束,不包括索引4的元素的陣列。
data1[:4]切片操作是從索引0開始,到索引4結束,不包括索引4的元素的陣列。
data1[4:]切片操作返回的是從索引4開始到最後一個元素的陣列。
切片操作返回的是原陣列的檢視,不是重新生成一個數組,通過對這個切片做賦值操作,就可以修改原陣列對應索引位置上元素的數值:
data1 = np.arange(10) data1[4:]=10 data1 Out[98]: array([ 0,1,2,3, 10, 10, 10, 10, 10, 10])
data1陣列從索引4開始到最後一個索引9上的元素數值都變為10。
二維及以上的多維陣列,也可以支援切片操作,但是比一維陣列要複雜些:
data1 = np.array([[1,2,3],[4,5,6],[7,8,9]]) data1 Out[100]: array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) data1[:2] Out[101]: array([[1, 2, 3], [4, 5, 6]]) data1[:2,:2] Out[102]: array([[1, 2], [4, 5]]) data1[:2,1:]
多維陣列的切片,可在每個維度都進行切片操作。
布林型陣列
顧名思義,布林型陣列就是指陣列的元素時布林值True和False。
變數的比較運算產生的結果是布林型的,ndarray陣列的比較運算也不例外,結果也是布林型別的,因此可以將一個數字型別或者字元型別的ndarray數字通過比較運算轉換為布林型陣列:
data1 = np.array(['Tom','Yong','Jim','John']) data1 == 'Tom' Out[111]: array([ True, False, False, False])
上面的程式碼首先建立一個字元型別的ndarray陣列data1,接著對陣列進行比較操作,data1 == 'Tom',如果陣列中的元素等於'Tom',則返回True,否則返回False。
布林型數值一個最經常的用法是設定值:
arr = np.random.randn(3,4) arr Out[62]: array([[ 0.52428143, -1.04842533, -1.00102911, -0.86488208], [ 3.20965669,0.4379931 , -0.82962251,0.63862152], [-1.03235591, -1.17507334, -0.01953273, -1.13759955]]) arr[arr<0] = 0 arr Out[64]: array([[0.52428143, 0., 0., 0.], [3.20965669, 0.4379931 , 0., 0.63862152], [0., 0., 0., 0.]])
上面的程式碼是將arr陣列中小於零的元素設定為0。
陣列轉置
陣列轉置和線性代數中矩陣轉置一樣。NumPy提供transpose方法和特殊屬性T實現陣列轉置。
data1 = np.arange(4) data1 Out[71]: array([0, 1, 2, 3]) data1.T Out[72]: array([0, 1, 2, 3])
一維陣列的轉置還是陣列本身。
data1 = np.arange(14).reshape(2,7) data1 Out[74]: array([[ 0,1,2,3,4,5,6], [ 7,8,9, 10, 11, 12, 13]]) data1.T Out[75]: array([[ 0,7], [ 1,8], [ 2,9], [ 3, 10], [ 4, 11], [ 5, 12], [ 6, 13]])
二維陣列的轉置是將行和列對應位置的元素互相調換。
特殊屬性T只適用於一維和二維陣列,對於三維以上的陣列,必須使用transpose方法才可以實現陣列轉置。
呼叫transpose方法時需要傳入一個元組,用於指定按照哪些軸進行轉置。元組的元素個數和陣列的維度要保持一致。如果適合3維陣列,那麼元組個數也必須是3。
data1 = np.arange(24).reshape(2,3,4) data1 Out[107]: array([[[ 0,1,2,3], [ 4,5,6,7], [ 8,9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]) data1.transpose((2,1,0)) Out[108]: array([[[ 0, 12], [ 4, 16], [ 8, 20]], [[ 1, 13], [ 5, 17], [ 9, 21]], [[ 2, 14], [ 6, 18], [10, 22]], [[ 3, 15], [ 7, 19], [11, 23]]])
上面程式碼先是建立一個2x3x4的三維陣列,然後呼叫transpose((2,1,0))方法實現陣列轉置。data1陣列的軸用數字0,1,2表示(類似三維空間中的x,y,z軸)。呼叫transpose((2,1,0))時,元組(2,1,0)表示將data1的第0軸和第2軸置換,1軸不變。
陣列置換返回的是源資料的檢視,不會重新生成新的陣列。