numpy基礎入門第一部分,介紹了numpy中最重要的數據結構numpy.ndarray的一些基本概念和常用操作。
基本概念
多維數組
numpy中最主要的數據對象就是多維數組,多維數組的緯度稱爲axis。下面例子中的這個數組有兩個維度,第一個維度(axis)的長度(length)爲2,第二個維度的長度爲3
[[1,2,3]
[4,5,6]]
numpy的數組(array)的數據類型爲ndarray, 和python本身的數組(list)是不同的,python本身的數組(list)只提供了一維的操作,並且不支持對數組進行運算,而numpy的數組提供了更多的功能。
>>> a = np.array([[1,2,3],[4,5,6]])
>>> type(a)
<class 'numpy.ndarray'>
numpy數組(ndarray)的一些重要屬性如下:
以如下數組(ndarray)爲例:
>>> a
array([[[ 11, 22],
[ 44, 55],
[ 11, 44]],
[[ 77, 55],
[ 44, 55],
[477, 55]]])
ndarray.ndim
數組的維度數目
>>> a.ndim
3
ndarray.shape
數組每個維度的長度
>>> a.shape
(2, 3, 2)
ndarray.size
數組所有元素的個數
>>> a.size
12
ndarray.dtype
數組中元素的類型,類型可以是python本身的數據類型,也可以是numpy定義的數據類型,比如numpy.int32, numpy.int16, and numpy.float64等等
>>> a.dtype
dtype('int64')
ndarray.itemsize
數組中單個元素佔用的字節數
>>> a.itemsize
8
ndarray.data
數組所在的內存地址,一般不會使用
>>> a.data
<memory at 0x7f67930e69a8>
數組(ndarray)的創建
創建任意的數組
將python的list或者tuple傳入numpy.array()
來創建,
可是使用numpy.array()
的dtype
參數來顯示地指定元素類型
# 一維
a = np.array( [1,2,3] )
# 二維
b = np.array( [ [1,2],
[3,4],
[5,6] ] )
# 三維
c = np.array([ [ [1, 2, 3],
[3 ,4, 5],
[5, 6, 7] ],
[ [7, 8, 9],
[4, 5, 6],
[3, 2, 1] ] ])
創建指定大小的數組
使用numpy.zeros()
來創建一個指定大小(shape)的全零的數組,傳入的參數爲包含每個維度(axis)的長度(length)的tuple
, 類似的還可以使用numpy.ones()
和numpy.empty()
創建全1或者未初始化的數組。默認的數據類型(dtype)是float64
,可以通過參數dtype
指定。
>>> a = np.zeros( (2,3,4) )
>>> a
array([[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
>>> a = np.empty( (2,3) )
>>> a
array([[2.45126520e-316, 5.72938864e-313, 6.90063282e-310],
[6.90063282e-310, 0.00000000e+000, 3.39285907e-310]])
>>> a = np.ones( (2,3) )
>>> a
array([[1., 1., 1.],
[1., 1., 1.]])
使用numpy.random.random()
來創建一個指定形狀(shape)的元素爲0-1之間隨機浮點數的數組
>>> np.random.random((5,5))
array([[0.92209695, 0.31994049, 0.82087437, 0.55672011, 0.38671646],
[0.87978651, 0.16631933, 0.25305667, 0.20991795, 0.27141552],
[0.65721032, 0.33116113, 0.72580006, 0.24957755, 0.51630277],
[0.17331517, 0.73900267, 0.41050214, 0.75883384, 0.8719157 ],
[0.65308589, 0.85678774, 0.77877104, 0.89501972, 0.89551946]])
創建序列數組
numpy.arange
使用numpy.arange()
來創建一個一維的序列數組(ndarray),該函數和python的range()類似,但產生的數組類型爲ndarray而不是list, 並且支持產生浮現數序列。給numpy.arange()
傳入一個參數,則參數結束值
;傳入兩個參數,參數按順序爲初始值
,結束值
;傳入三個參數爲,參數按順序爲初始值
,結束值
和步長
。生成的數組中包含初始值,不包含結束值(對整數成立,對浮點數來說由於精度問題可能存在其他情況)。
>>> np.arange(5)
array([0, 1, 2, 3, 4])
>>> np.arange(1,5,1)
array([1, 2, 3, 4])
>>> np.arange(0.1,0.6,0.2)
array([0.1, 0.3, 0.5])
注意:
將np.arange()
用於生成浮點數時,由於浮點數精度問題得到的序列長度可能是不確定的,可能會多一個或者少一個
>>> a = np.arange(0.1,0.1000005,0.00000001)
>>> a.size
51 #由於0.00000001無法精確的用二進制表示,這裏多生成了一個數字
>>> a
array([0.1 , 0.10000001, 0.10000002, 0.10000003, 0.10000004,
0.10000005, 0.10000006, 0.10000007, 0.10000008, 0.10000009,
0.1000001 , 0.10000011, 0.10000012, 0.10000013, 0.10000014,
0.10000015, 0.10000016, 0.10000017, 0.10000018, 0.10000019,
0.1000002 , 0.10000021, 0.10000022, 0.10000023, 0.10000024,
0.10000025, 0.10000026, 0.10000027, 0.10000028, 0.10000029,
0.1000003 , 0.10000031, 0.10000032, 0.10000033, 0.10000034,
0.10000035, 0.10000036, 0.10000037, 0.10000038, 0.10000039,
0.1000004 , 0.10000041, 0.10000042, 0.10000043, 0.10000044,
0.10000045, 0.10000046, 0.10000047, 0.10000048, 0.10000049,
0.1000005 ]) #好像0.1000005也被加進去了,其實並不是
>>> b = a[50]
>>> b == 0.1000005
False
>>> b - 0.1000005
-2.636779683484747e-16 #由於0.00000001存在誤差,在加了50次後得到的值略小於0.1000005
numpy.linspace
爲了創建指定區間包含指定元素個數的數組,可以使用numpy.linspace()
,該函數會根據指定的區間和元素個數自動決定步長。
該函數參數爲起始值
,結束值
和元素個數
,其中起始值和結束值都會包含在生成的數組中
numpy.linspace()
默認數據類型爲float64
>>> a = np.linspace(0.1, 0.1000005, 50)
>>> a
array([0.1 , 0.10000001, 0.10000002, 0.10000003, 0.10000004,
0.10000005, 0.10000006, 0.10000007, 0.10000008, 0.10000009,
0.1000001 , 0.10000011, 0.10000012, 0.10000013, 0.10000014,
0.10000015, 0.10000016, 0.10000017, 0.10000018, 0.10000019,
0.1000002 , 0.10000021, 0.10000022, 0.10000023, 0.10000024, #後面的是跳過了一個數0.10000025
0.10000026, 0.10000027, 0.10000028, 0.10000029, 0.1000003 ,
0.10000031, 0.10000032, 0.10000033, 0.10000034, 0.10000035,
0.10000036, 0.10000037, 0.10000038, 0.10000039, 0.1000004 ,
0.10000041, 0.10000042, 0.10000043, 0.10000044, 0.10000045,
0.10000046, 0.10000047, 0.10000048, 0.10000049, 0.1000005 ])
# 如果指定的類型爲整數,根據要求生成的數組個數計算出的步長爲小數時,linspace()會把生成數組中對應小數取整得到整數數組
>>> a = np.linspace(1, 8, 6,dtype=np.int64)
>>> a
array([1, 2, 3, 5, 6, 8])
>>> a = np.linspace(1, 8, 6)
>>> a
array([1. , 2.4, 3.8, 5.2, 6.6, 8. ])
其他方式創建數組
numpy.fromfunction
該函數基本參數爲用於生成數組元素的函數
,數組的大小(shape)
,可以使用dtype
指定數組元素的類型,默認類型是float64
。該函數會把每個數組元素的索引值傳給用於生成數組元素的函數
,將該函數的返回值作爲元素的值。
>>> def f(a,b):
... return a+b
...
>>> b = np.fromfunction(f, (3,3))
>>> b
array([[0., 1., 2.],
[1., 2., 3.],
[2., 3., 4.]])
基本操作
算數運算會作用到數組的每一個元素上,然後生成一個新的數組
普通算數運算
>>> a = np.array([[1,2],
[3,4]])
>>> b = np.array([[5,6],
[7,8]])
# 加法
>>> c = a+b
>>> c
array([[ 6, 8],
[10, 12]])
# 乘法
>>> c = a * b
>>> c
array([[ 5, 12],
[21, 32]])
矩陣乘法
(還是上例的a和b)使用@
運算符或者ndarry.dot()
方法
>>> c = a@b
>>> c
array([[19, 22],
[43, 50]])
>>> c = a.dot(b)
>>> c
array([[19, 22],
[43, 50]])
注意:不同類型(int64,int32,float64…)的數組進行運算時,會自動進行類型轉換,將類型統一爲表示範圍更大的類型
一些有用的方法
名稱 | 作用 |
---|---|
ndarray.min | 求數組中所有元素的最小值,或者指定某一個維度(axis)的最小值 |
ndarray.max | 求數組中所有元素的最大值,或者指定某一個維度(axis)的最小值 |
ndarray.sum | 求數組中所有元素的和,或者指定某一個維度(axis)的最小值 |
ndarray.cumsum | 求數組中所有元素的累計和(a1, a1+a2, a1+a2+a3…),或者指定某一個維度(axis)的累積和 |
numpy.exp | 計算e爲底數,數組中每個數作爲指數的冪 |
numpy.sqrt | 計算數組中每個數的平方根 |
numpy.sin | 計算數組中每個數的正弦值 |
numpy.cos | 計算數組中每個數的餘弦值 |
數組的訪問,切分和遍歷
訪問單個元素
數組(ndarray)的訪問使用類似a[<index1>, <index2>, <index3>]
或者a[<index1>][<index2>][index3]
的形式來訪問, 索引值從0開始,也可以使用負數來表示倒序的索引值,負數索引從-1開始
>>> a = np.array([[1,2],[3,4]])
>>> a
array([[1, 2],
[3, 4]])
>>> a[1,1]
4
>>> a[0,1]
2
>>> a[-1,-1]
4
>>> a[1][1]
4
切片訪問
使用[<start> : <end>]
來表示對範圍元素的訪問,即數組的切片,範圍中包括<start>
不包括<end>
。如果省略<start>
或者<end>
分別表示從第一個元素開始以及直到最後一個元素(包括最後一個元素)。
此外還可以使用...
來表示選取除了指定部分之外的全部元素, 例如,若x是5維數組, 那麼
- x[1,2,…]等價於x[1,2,:,:,:]
- x[…,3]等價於x[:,:,:,:,3]
- x[4,…,5,:]等價於x[4,:,:,5,:]
注意:使用了...
後即使訪問範圍只有一個元素也會返回數組類型(ndarray)
>>> a = np.fromfunction(f,(5,5), dtype=int)
>>> a
array([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
>>> a[...]
array([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
>>> a[1,...,1]
array(2)
>>> a[1:3,1:3]
array([[2, 3],
[3, 4]])
>>> a[1:3,...]
array([[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6]])
遍歷數組
假設有三維數組a,可以直接使用for遍歷a,循環的次數爲第一個維度(axis)的長度(length)
# 生成三維數組
>>> a = np.fromfunction(lambda x,y,z:x+y+z, (3, 3, 3), dtype=int)
>>> a
array([[[0, 1, 2],
[1, 2, 3],
[2, 3, 4]],
[[1, 2, 3],
[2, 3, 4],
[3, 4, 5]],
[[2, 3, 4],
[3, 4, 5],
[4, 5, 6]]])
>>> for i in a:
... print(i)
...
[[0 1 2]
[1 2 3]
[2 3 4]]
[[1 2 3]
[2 3 4]
[3 4 5]]
[[2 3 4]
[3 4 5]
[4 5 6]]
還可以使用for循環遍歷a.flat, 這樣會遍歷到a中的每個元素,循環次數爲a中元素的個數(size)
# 還是上個例子中的數組a
>>> for i in a.flat:
... print(i,end=" ")
...
0 1 2 1 2 3 2 3 4 1 2 3 2 3 4 3 4 5 2 3 4 3 4 5 4 5 6
調整數組形狀(shape)
函數 | 作用 |
---|---|
ndarray.ravel | 利用原數組生成對應的一維數組 |
ndarray.reshape | 利用原數組生成指定形狀(shape)的數組 |
ndarray.T | 生成原數組的轉置 |
以上函數不改變原數組
函數 | 作用 |
---|---|
ndarray.resize | 改變原數組的形狀(shape) |
>>> a = np.floor( np.random.random((2,3)) * 10)
>>> a
array([[5., 9., 5.],
[1., 7., 3.]])
>>> a.ravel()
array([5., 9., 5., 1., 7., 3.])
>>> a.reshape(3,2)
array([[5., 9.],
[5., 1.],
[7., 3.]])
>>> a.T
array([[5., 1.],
[9., 7.],
[5., 3.]])
# 不改變a
>>> a
array([[5., 9., 5.],
[1., 7., 3.]])
# 改變a
>>> a.resize(3,2)
>>> a
array([[5., 9.],
[5., 1.],
[7., 3.]])
注意:轉置和ndarray.reshap
e生成同樣形狀的數組時生成規則是不一樣的,轉置會把第二個維度作爲第一個維度,把第一個維度作爲第二個維度,而利用reshape生成同樣形狀的數組時並不做維度交換,具體的區別請看上述例子。
數組的合併
numpy.vstack & numpy.row_stack
這兩個函數的作用是一樣的,將數組在第一個維度上合併。
說明:官方文檔中並沒有numpy.row_stack
文檔,只有numpy.ma.row_stack
,不過numpy.row_stack
確實是可以調用的,在python中輸入help(numpy.row_stack)
會跳轉到numpy.vstack
的說明文檔,因此numpy.row_stack
可能只是numpy.vstack
的一個別名。
關於numpy.ma是什麼,參見numpy.ma
>>> a
array([[0., 1., 2.],
[1., 2., 3.]])
>>> b
array([[0., 1., 2.],
[2., 3., 4.]])
>>> np.vstack( (a,b) )
array([[0., 1., 2.],
[1., 2., 3.],
[0., 1., 2.],
[2., 3., 4.]])
>>> np.row_stack( (a,b) )
array([[0., 1., 2.],
[1., 2., 3.],
[0., 1., 2.],
[2., 3., 4.]])
numpy.hstack
將數組在第二個維度合併
# 使用上個例子中的a和b
>>> np.hstack((a,b))
array([[0., 1., 2., 0., 1., 2.],
[1., 2., 3., 2., 3., 4.]])
>>>
注意:如果數組沒有第二個維度(一維數組),則合併第一個維度
>>> a
array([1, 2])
>>> b
array([3, 4])
>>> np.hstack((a,b))
array([1, 2, 3, 4])
numpy.column_stack
將數組在第二個維度上合併(該方法一般用來將一維數組作爲列合併成二維數組,見注意部分)
詳細函數說明請參考numpy.column_stack
>>> a
array([[0., 1.],
[1., 2.]])
>>> b
array([[3., 4.],
[4., 5.]])
>>> np.column_stack((a,b))
array([[0., 1., 3., 4.],
[1., 2., 4., 5.]])
注意:如果數組沒有第二個維度(一維數組),則將原數組轉置爲2維列向量然後合併
>>> a
array([1, 2])
>>> b
array([3, 4])
>>> np.column_stack((a,b))
array([[1, 3],
[2, 4]])
numpy.column_stack
和numpy.hstack
只有在處理一維數組上存在上述差異,其他維度是相同的,下面是3維數組的一個測試
>>> bb = np.fromfunction(lambda x,y,z:50+x+y+z,(2,2,2))
>>> aa = np.fromfunction(lambda x,y,z:1+x+y+z,(2,2,2))
>>> aa
array([[[1., 2.],
[2., 3.]],
[[2., 3.],
[3., 4.]]])
>>> bb
array([[[50., 51.],
[51., 52.]],
[[51., 52.],
[52., 53.]]])
>>> np.hstack((aa,bb))
array([[[ 1., 2.],
[ 2., 3.],
[50., 51.],
[51., 52.]],
[[ 2., 3.],
[ 3., 4.],
[51., 52.],
[52., 53.]]])
>>> np.column_stack((aa,bb))
array([[[ 1., 2.],
[ 2., 3.],
[50., 51.],
[51., 52.]],
[[ 2., 3.],
[ 3., 4.],
[51., 52.],
[52., 53.]]])
numpy.concatenate
該函數將數組在參數axis
指定的維度上合併
詳細函數說明請參考numpy.concatenate
>>> aa
array([[[1., 2.],
[2., 3.]],
[[2., 3.],
[3., 4.]]])
>>> bb
array([[[50., 51.],
[51., 52.]],
[[51., 52.],
[52., 53.]]])
>>> np.concatenate((aa,bb), axis=2)
array([[[ 1., 2., 50., 51.],
[ 2., 3., 51., 52.]],
[[ 2., 3., 51., 52.],
[ 3., 4., 52., 53.]]])
>>> np.concatenate((aa,bb), axis=1)
array([[[ 1., 2.],
[ 2., 3.],
[50., 51.],
[51., 52.]],
[[ 2., 3.],
[ 3., 4.],
[51., 52.],
[52., 53.]]])
>>> np.concatenate((aa,bb), axis=0)
array([[[ 1., 2.],
[ 2., 3.]],
[[ 2., 3.],
[ 3., 4.]],
[[50., 51.],
[51., 52.]],
[[51., 52.],
[52., 53.]]])