NumPy的主要對象是同類型的多維數組。它是一張表,所有元素(通常是數字)的類型都相同,並通過正整數元組索引。在NumPy中,維度稱為軸。軸的數目為rank。
NumPy的數組類被稱為ndarray。別名為 array。 請注意,numpy.array 與標准Python庫類 array.array 不同,后者僅處理一維數組並提供較少的功能。 ndarray 對象則提供更關鍵的屬性:
- ndarray.ndim:數組的軸(維度)的個數。在Python世界中,維度的數量被稱為rank。
- ndarray.shape:數組的維度。這是一個整數的元組,表示每個維度中數組的大小。對於有n行和m列的矩陣,shape將是(n,m)。因此,
shape元組的長度就是rank或維度的個數ndim。 - ndarray.size:數組元素的總數。這等於shape的元素的乘積。
- ndarray.dtype:一個描述數組中元素類型的對象。可以使用標准的Python類型創建或指定dtype。另外NumPy提供它自己的類型。例如numpy.int32、numpy.int16和numpy.float64。
- ndarray.itemsize:數組中每個元素的字節大小。例如,元素為
float64類型的數組的itemsize為8(=64/8),而complex32類型的數組的itemsize為4(=32/8)。它等於ndarray.dtype.itemsize。 - ndarray.data:該緩沖區包含數組的實際元素。通常,我們不需要使用此屬性,因為我們將使用索引訪問數組中的元素。
一個典型的例子
1 >>> import numpy as np 2 >>> a = np.arange(15).reshape(3, 5) 3 >>> a 4 array([[ 0, 1, 2, 3, 4], 5 [ 5, 6, 7, 8, 9], 6 [10, 11, 12, 13, 14]]) 7 >>> a.shape 8 (3, 5) 9 >>> a.ndim 10 2 11 >>> a.dtype.name 12 'int64' 13 >>> a.itemsize 14 8 15 >>> a.size 16 15 17 >>> type(a) 18 <type 'numpy.ndarray'> 19 >>> b = np.array([6, 7, 8]) 20 >>> b 21 array([6, 7, 8]) 22 >>> type(b) 23 <type 'numpy.ndarray'>
數組的創建
import numpy as np 導入NumPy函數庫
np.asarray(array) #將輸入數據轉化為一個新的(copy)ndarray
np.eye(N) #創建一個N*N的單位矩陣(對角線為1,其余為0)
np.identity(N) #創建一個N*N的單位矩陣(對角線為1,其余為0)
np.array(x) # 將輸入數據轉化為一個ndarray
np.array([1,2,3,5]) 創建數組
np.array([1,2],[2,4]) 創建多維數組
np.array([(1.5,2,3), (4,5,6)])
1 array([[ 1.5, 2. , 3. ], [ 4. , 5. , 6. ]])
np.array(x.dtype) # 將輸入數據轉化為一個類型為type的ndarray
np.array( [ [1,2], [3,4] ], dtype=complex )
1 array([[ 1.+0.j, 2.+0.j], 2 [ 3.+0.j, 4.+0.j]])
函數 zeros 創建一個由0組成的數組,函數 ones 創建一個由1數組的數組,函數 empty 內容是隨機的並且取決於存儲器的狀態。默認情況下,創建的數組的dtype是 float64。
np.zeros(N) #生成一個N長度的一維全零ndarray
np.zeros(N,dtype) #生成一個N長度類型位dtype的一維全零ndarray
np.zeros_like(ndaary) #類似np.ones_like(ndarray)
np.zeros((3,4))
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
np.ones(N) #生成一個N長度的一維全一ndarray
np.ones(N,dtype) #生成一個N長度類型是dtype的一維全一ndarray
np.ones_like(ndarray) #生成一個形狀與參數相同的全一ndarray
np.ones((2,3,4),dtype=np.int16)
array([[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]], dtype=int16)
np.empty(N) #生成一個N長度的未初始化一維ndarray
np.empty(N,dtype) #生成一個N長度類型是dtype的未初始化的一維ndarray
np.empty(ndarray) #類似np.ones_like(ndarray
np.empty((2,3))
array([[1.5, 2. , 3. ],
[4. , 5. , 6. ]])
要創建數字序列,NumPy提供了一個類似於 range 的函數,該函數返回數組而不是列表。
np.arange[num] #生成一個從0到num-1步數為1的一維ndarray
np.arange[begin,end] #生成一個從begin到end-1步數為1的一維ndarray
np.arange[begin,end,step] # #生成一個從begin到end-step步數為step的一維ndarray
np.arange(10,30,5)
array([10, 15, 20, 25])
np.arange(0,3,0.3)
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7])
當 arange 與浮點參數一起使用時,由於浮點數的精度是有限的,通常不可能預測獲得的元素數量。出於這個原因,通常最好使用函數 linspace ,它接收我們想要的元素數量而不是步長作為參數:
np.linspace(0,1,12) 通過指定開始值、終值和元素個數來創建一維數組,可以通過endpoint關鍵字指定是否包括終值,缺省設置是否包括終值
array([0. , 0.09090909, 0.18181818, 0.27272727, 0.36363636, 0.45454545, 0.54545455, 0.63636364, 0.72727273, 0.81818182, 0.90909091, 1. ])
1 from numpy import pi 2 x = np.linspace(0,2*pi,100) 3 f = np.sin(x)
打印數組
當你打印數組時,NumPy以與嵌套列表類似的方式顯示它,但是具有以下布局:
- 最后一個軸從左到右打印,
- 倒數第二個從上到下打印,
- 其余的也從上到下打印,每個切片與下一個用空行分開。
一維數組被打印為行、二維為矩陣和三維為矩陣列表。
a = np.arange(6)
[0 1 2 3 4 5]
b = np.arange(12).reshape(4,3)
[[ 0 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]]
c = np.arange(24).reshape(2,3,4)
[[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] [[12 13 14 15] [16 17 18 19] [20 21 22 23]]]
如果數組太大而無法打印,NumPy將自動跳過數組的中心部分並僅打印角點:
>>> print(np.arange(10000)) [ 0 1 2 ..., 9997 9998 9999] >>> >>> print(np.arange(10000).reshape(100,100)) [[ 0 1 2 ..., 97 98 99] [ 100 101 102 ..., 197 198 199] [ 200 201 202 ..., 297 298 299] ..., [9700 9701 9702 ..., 9797 9798 9799] [9800 9801 9802 ..., 9897 9898 9899] [9900 9901 9902 ..., 9997 9998 9999]]
要禁用此行為並強制NumPy打印整個數組,你可以使用 set_printoptions 更改打印選項。
ndarray.shape 數組的大小。返回一個元素表示一維數組。shape有幾個元素,表示幾維數組
ndarray.shape=4,3 通過修改數組的shape屬性,在保持數組元素個數不變的情況下,改變數組每 個軸的長度
ndarray.shape=2,-1 當某個軸的元素為-1時,將根據數組元素的個數自動計算此軸的長度
ndarray.reshape((2,2)) 創建了一個改變尺寸的新數組,原數組不變
基本操作
基礎知識
# 基礎知識
NumPy的主要對象是同類型的多維數組。它是一張表,所有元素(通常是數字)的類型都相同,並通過正整數元組索引。在NumPy中,維度稱為軸。軸的數目為rank。
例如,3D空間中的點的坐標 [1, 2, 1] 是rank為1的數組,因為它具有一個軸。該軸的長度為3。在下面的示例中,該數組有2個軸。
第一個軸(維度)的長度為2,第二個軸(維度)的長度為3。
[[ 1., 0., 0.], [ 0., 1., 2.]]
NumPy的數組類被稱為ndarray。別名為 array。 請注意,numpy.array 與標准Python庫類 array.array 不同,后者僅處理一維數組並提供較少的功能。 ndarray 對象則提供更關鍵的屬性:
- ndarray.ndim:數組的軸(維度)的個數。在Python世界中,維度的數量被稱為rank。
- ndarray.shape:數組的維度。這是一個整數的元組,表示每個維度中數組的大小。對於有n行和m列的矩陣,shape將是(n,m)。因此,
shape元組的長度就是rank或維度的個數ndim。 - ndarray.size:數組元素的總數。這等於shape的元素的乘積。
- ndarray.dtype:一個描述數組中元素類型的對象。可以使用標准的Python類型創建或指定dtype。另外NumPy提供它自己的類型。例如numpy.int32、numpy.int16和numpy.float64。
- ndarray.itemsize:數組中每個元素的字節大小。例如,元素為
float64類型的數組的itemsize為8(=64/8),而complex32類型的數組的itemsize為4(=32/8)。它等於ndarray.dtype.itemsize。 - ndarray.data:該緩沖區包含數組的實際元素。通常,我們不需要使用此屬性,因為我們將使用索引訪問數組中的元素。
# 一個典型的例子
>>> import numpy as np >>> a = np.arange(15).reshape(3, 5) >>> a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) >>> a.shape (3, 5) >>> a.ndim 2 >>> a.dtype.name 'int64' >>> a.itemsize 8 >>> a.size 15 >>> type(a) <type 'numpy.ndarray'> >>> b = np.array([6, 7, 8]) >>> b array([6, 7, 8]) >>> type(b) <type 'numpy.ndarray'>
# 數組的創建
有幾種創建數組的方法。
例如,你可以使用array函數從常規Python列表或元組中創建數組。得到的數組的類型是從Python列表中元素的類型推導出來的。
>>> import numpy as np >>> a = np.array([2,3,4]) >>> a array([2, 3, 4]) >>> a.dtype dtype('int64') >>> b = np.array([1.2, 3.5, 5.1]) >>> b.dtype dtype('float64')
一個常見的錯誤在於使用多個數值參數調用 array 函數,而不是提供一個數字列表(List)作為參數。
>>> a = np.array(1,2,3,4) # WRONG >>> a = np.array([1,2,3,4]) # RIGHT
array 將序列的序列轉換成二維數組,將序列的序列的序列轉換成三維數組,等等。
>>> b = np.array([(1.5,2,3), (4,5,6)]) >>> b array([[ 1.5, 2. , 3. ], [ 4. , 5. , 6. ]])
數組的類型也可以在創建時明確指定:
>>> c = np.array( [ [1,2], [3,4] ], dtype=complex ) >>> c array([[ 1.+0.j, 2.+0.j], [ 3.+0.j, 4.+0.j]])
通常,數組的元素最初是未知的,但它的大小是已知的。因此,NumPy提供了幾個函數來創建具有初始占位符內容的數組。這就減少了數組增長的必要,因為數組增長的操作花費很大。
函數 zeros 創建一個由0組成的數組,函數 ones 創建一個由1數組的數組,函數 empty 內容是隨機的並且取決於存儲器的狀態。默認情況下,創建的數組的dtype是 float64。
>>> np.zeros( (3,4) ) array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 0., 0., 0., 0.]]) >>> np.ones( (2,3,4), dtype=np.int16 ) # dtype can also be specified array([[[ 1, 1, 1, 1], [ 1, 1, 1, 1], [ 1, 1, 1, 1]], [[ 1, 1, 1, 1], [ 1, 1, 1, 1], [ 1, 1, 1, 1]]], dtype=int16) >>> np.empty( (2,3) ) # uninitialized, output may vary array([[ 3.73603959e-262, 6.02658058e-154, 6.55490914e-260], [ 5.30498948e-313, 3.14673309e-307, 1.00000000e+000]])
要創建數字序列,NumPy提供了一個類似於 range 的函數,該函數返回數組而不是列表。
>>> np.arange( 10, 30, 5 ) array([10, 15, 20, 25]) >>> np.arange( 0, 2, 0.3 ) # it accepts float arguments array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])
當 arange 與浮點參數一起使用時,由於浮點數的精度是有限的,通常不可能預測獲得的元素數量。出於這個原因,通常最好使用函數 linspace ,它接收我們想要的元素數量而不是步長作為參數:
>>> from numpy import pi >>> np.linspace( 0, 2, 9 ) # 9 numbers from 0 to 2 array([ 0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ]) >>> x = np.linspace( 0, 2*pi, 100 ) # useful to evaluate function at lots of points >>> f = np.sin(x)
另見:
array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange, linspace, numpy.random.rand, numpy.random.randn, fromfunction, fromfile
打印數組
當你打印數組時,NumPy以與嵌套列表類似的方式顯示它,但是具有以下布局:
- 最后一個軸從左到右打印,
- 倒數第二個從上到下打印,
- 其余的也從上到下打印,每個切片與下一個用空行分開。
一維數組被打印為行、二維為矩陣和三維為矩陣列表。
>>> a = np.arange(6) # 1d array >>> print(a) [0 1 2 3 4 5] >>> >>> b = np.arange(12).reshape(4,3) # 2d array >>> print(b) [[ 0 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]] >>> >>> c = np.arange(24).reshape(2,3,4) # 3d array >>> print(c) [[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] [[12 13 14 15] [16 17 18 19] [20 21 22 23]]]
有關 reshape 的詳情,請參閱下文。
如果數組太大而無法打印,NumPy將自動跳過數組的中心部分並僅打印角點:
>>> print(np.arange(10000)) [ 0 1 2 ..., 9997 9998 9999] >>> >>> print(np.arange(10000).reshape(100,100)) [[ 0 1 2 ..., 97 98 99] [ 100 101 102 ..., 197 198 199] [ 200 201 202 ..., 297 298 299] ..., [9700 9701 9702 ..., 9797 9798 9799] [9800 9801 9802 ..., 9897 9898 9899] [9900 9901 9902 ..., 9997 9998 9999]]
要禁用此行為並強制NumPy打印整個數組,你可以使用 set_printoptions 更改打印選項。
>>> np.set_printoptions(threshold=np.nan)
# 基本操作
數組上的算術運算符使用元素級別。一個新的數組被創建並填充結果。
a = np.array([20,30,40,50])
b = np.arange(4)
c = a -b #array([20, 29, 38, 47])
b**2 #array([0, 1, 4, 9], dtype=int32)
np.sin(a)*10 #array([ 9.12945251, -9.88031624, 7.4511316 , -2.62374854])
a<35 #array([ True, True, False, False])
與許多矩陣語言不同,乘法運算符 * 的運算在NumPy數組中是元素級別的。矩陣乘積可以使用 dot 函數或方法執行:
A = np.array([[1,1],[0,1]])
array([[1, 1],
[0, 1]])
B = np.array([[2,0],[3,4]])
array([[2, 0],
[3, 4]])
A*B #對應矩陣位置元素相乘
array([[2, 0],
[0, 4]])
A.dot(B) #矩陣相乘
array([[5, 4],
[3, 4]])
np.dot(A,B)
array([[5, 4],
[3, 4]])
某些操作(例如+=和*=)適用於修改現有數組,而不是創建新數組。
a = np.ones((2,3),dtype = int)
[[1 1 1]
[1 1 1]]
b = np.random.random((2,3))
[[0.53189744 0.63659516 0.44626939]
[0.44986348 0.903273 0.46057394]]
a *= 3
[[3 3 3]
[3 3 3]]
b += a
[[3.53189744 3.63659516 3.44626939]
[3.44986348 3.903273 3.46057394]]
a += b
Cannot cast ufunc add output from dtype('float64') to dtype('int32') with casting rule 'same_kind'
當使用不同類型的數組操作時,結果數組的類型對應於更一般或更精確的數組(稱為向上轉換的行為)。
>>> a = np.ones(3, dtype=np.int32) >>> b = np.linspace(0,pi,3) >>> b.dtype.name 'float64' >>> c = a+b >>> c array([ 1. , 2.57079633, 4.14159265]) >>> c.dtype.name 'float64' >>> d = np.exp(c*1j) >>> d array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j, -0.54030231-0.84147098j]) >>> d.dtype.name 'complex128'
許多一元運算,例如計算數組中所有元素的總和,都是作為 ndarray 類的方法實現的。
>>> a = np.random.random((2,3)) >>> a array([[ 0.18626021, 0.34556073, 0.39676747], [ 0.53881673, 0.41919451, 0.6852195 ]]) >>> a.sum() 2.5718191614547998 >>> a.min() 0.1862602113776709 >>> a.max() 0.6852195003967595
默認情況下,這些操作適用於數組,就好像它是數字列表一樣,無論其形狀如何。但是,通過指定 axis 參數,你可以沿着數組的指定軸應用操作:
>>> b = np.arange(12).reshape(3,4) >>> b array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> b.sum(axis=0) # sum of each column array([12, 15, 18, 21]) >>> >>> b.min(axis=1) # min of each row array([0, 4, 8]) >>> >>> b.cumsum(axis=1) # cumulative sum along each row array([[ 0, 1, 3, 6], [ 4, 9, 15, 22], [ 8, 17, 27, 38]])
通用函數
NumPy提供了常見的數學函數,如sin,cos和exp。In NumPy, these are called “universal functions”( ufunc ). 在NumPy中,這些函數在數組上按元素級別操作,產生一個數組作為輸出。
>>> B = np.arange(3) >>> B array([0, 1, 2]) >>> np.exp(B) array([ 1. , 2.71828183, 7.3890561 ]) >>> np.sqrt(B) array([ 0. , 1. , 1.41421356]) >>> C = np.array([2., -1., 4.]) >>> np.add(B, C) array([ 2., 0., 6.])
另見:
all, any, apply_along_axis, argmax, argmin, argsort, average, bincount, ceil, clip, conj, corrcoef, cov, cross, cumprod, cumsum, diff, dot, floor, inner, inv, lexsort, max, maximum, mean, median, min, minimum, nonzero, outer, prod, re, round, sort, std, sum, trace, transpose, var, vdot, vectorize, where
索引、切片和迭代
一維數組可以被索引,切片和迭代,就像列出和其他Python序列一樣。
ndarray[2:4]=100,101 #下標可以用來修改元素的值
ndarray [1:-1:2] #第三個元素表示步長,隔2個元素取一個值
ndarray [::-1] #省略開始和結束下標,步長為-1時,序列頭尾顛倒
ndarray [5:1:-2] #步長為負數時,開始下標應大小結束下標
>>> a = np.arange(10)**3 >>> a array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729]) >>> a[2] 8 >>> a[2:5] array([ 8, 27, 64]) >>> a[:6:2] = -1000 # equivalent to a[0:6:2] = -1000; from start to position 6, exclusive, set every 2nd element to -1000 >>> a array([-1000, 1, -1000, 27, -1000, 125, 216, 343, 512, 729]) >>> a[ : :-1] # reversed a array([ 729, 512, 343, 216, 125, -1000, 27, -1000, 1, -1000]) >>> for i in a: ... print(i**(1/3.)) ... nan 1.0 nan 3.0 nan 5.0 6.0 7.0 8.0 9.0
多維(Multidimensional) 數組每個軸可以有一個索引。 這些索在元組中以逗號分隔給出:
def f(x,y):
return 10*x + y
b = np.fromfunction(f,(5,4),dtype = int)
array([[ 0, 1, 2, 3], [10, 11, 12, 13], [20, 21, 22, 23], [30, 31, 32, 33], [40, 41, 42, 43]])
b[2,3] #23
b[0:5,1] #array([ 1, 11, 21, 31, 41]) # each row in the second column of b
b[ : ,1] #array([ 1, 11, 21, 31, 41]) # equivalent to the previous example
b[1:3, : ] #array([[10, 11, 12, 13], [20, 21, 22, 23]]) # each column in the second and third row of b
當提供比軸數更少的索引時,缺失的索引被認為是一個完整切片 :
>>> b[-1] # the last row. Equivalent to b[-1,:] array([40, 41, 42, 43])
b[i] 方括號中的表達式 i 被視為后面緊跟着 : 的多個實例,用於表示剩余軸。NumPy也允許你使用三個點寫為 b[i,...]。
三個點( ... )表示產生完整索引元組所需的冒號。例如,如果 x 是rank為的5數組(即,它具有5個軸),則
x[1,2,...]等於x[1,2,:,:,:]。x[...,3]等效於x[:,:,:,:,3]。x[4,...,5,:]等效於x[4,:,:,5,:]。
>>> c = np.array( [[[ 0, 1, 2], # a 3D array (two stacked 2D arrays) ... [ 10, 12, 13]], ... [[100,101,102], ... [110,112,113]]]) >>> c.shape (2, 2, 3) >>> c[1,...] # same as c[1,:,:] or c[1] array([[100, 101, 102], [110, 112, 113]]) >>> c[...,2] # same as c[:,:,2] array([[ 2, 13], [102, 113]])
迭代(Iterating) 多維數組是相對於第一個軸完成的:
>>> for row in b: ... print(row) ... [0 1 2 3] [10 11 12 13] [20 21 22 23] [30 31 32 33] [40 41 42 43]
但是,如果想要對數組中的每個元素執行操作,可以使用 flat 屬性,該屬性是數組中所有元素的迭代器:
>>> for element in b.flat: ... print(element) ... 0 1 2 3 10 11 12 13 20 21 22 23 30 31 32 33 40 41 42 43
另見:
Indexing, Indexing (reference), newaxis, ndenumerate, indices
形狀操作
更改數組的形狀
一個數組具有由每個軸上的元素數量給出的形狀:
>>> a = np.floor(10*np.random.random((3,4))) >>> a array([[ 2., 8., 0., 6.], [ 4., 5., 1., 1.], [ 8., 9., 3., 6.]]) >>> a.shape (3, 4)
數組的形狀可以通過各種命令進行更改。請注意,以下三個命令都返回一個修改后的數組,但不要更改原始數組:
>>> a.ravel() # returns the array, flattened array([ 2., 8., 0., 6., 4., 5., 1., 1., 8., 9., 3., 6.]) >>> a.reshape(6,2) # returns the array with a modified shape array([[ 2., 8.], [ 0., 6.], [ 4., 5.], [ 1., 1.], [ 8., 9.], [ 3., 6.]]) >>> a.T # returns the array, transposed array([[ 2., 4., 8.], [ 8., 5., 9.], [ 0., 1., 3.], [ 6., 1., 6.]]) >>> a.T.shape (4, 3) >>> a.shape (3, 4)
由ravel()產生的數組中元素的順序通常是“C風格”,也就是說,最右邊的索引“改變最快”,所以[0,0]之后的元素是[0,1] 。如果數組被重新塑造成其他形狀,數組又被視為“C-style”。NumPy通常創建按此順序存儲的數組,因此ravel()通常不需要復制其參數,但如果數組是通過切片另一個數組或使用不尋常選項創建的,則可能需要復制它。函數ravel()和reshape()也可以通過使用可選參數來指示使用FORTRAN風格的數組,其中最左側的索引更改速度最快。
reshape 函數返回具有修改形狀的參數,而 ndarray.resize 方法修改數組本身:
>>> a array([[ 2., 8., 0., 6.], [ 4., 5., 1., 1.], [ 8., 9., 3., 6.]]) >>> a.resize((2,6)) >>> a array([[ 2., 8., 0., 6., 4., 5.], [ 1., 1., 8., 9., 3., 6.]])
如果在reshape操作中將維度指定為-1,則會自動計算其他維度:
>>> a.reshape(3,-1) array([[ 2., 8., 0., 6.], [ 4., 5., 1., 1.], [ 8., 9., 3., 6.]])
另見:
ndarray.shape, reshape, resize, ravel
將不同數組堆疊在一起
幾個數組可以沿不同的軸堆疊在一起:
>>> a = np.floor(10*np.random.random((2,2))) >>> a array([[ 8., 8.], [ 0., 0.]]) >>> b = np.floor(10*np.random.random((2,2))) >>> b array([[ 1., 8.], [ 0., 4.]]) >>> np.vstack((a,b)) array([[ 8., 8.], [ 0., 0.], [ 1., 8.], [ 0., 4.]]) >>> np.hstack((a,b)) array([[ 8., 8., 1., 8.], [ 0., 0., 0., 4.]])
函數 column_stack 將1D數組作為列疊加到2D數組中。它相當於僅用於二維數組的 hstack:
>>> from numpy import newaxis >>> np.column_stack((a,b)) # with 2D arrays array([[ 8., 8., 1., 8.], [ 0., 0., 0., 4.]]) >>> a = np.array([4.,2.]) >>> b = np.array([3.,8.]) >>> np.column_stack((a,b)) # returns a 2D array array([[ 4., 3.], [ 2., 8.]]) >>> np.hstack((a,b)) # the result is different array([ 4., 2., 3., 8.]) >>> a[:,newaxis] # this allows to have a 2D columns vector array([[ 4.], [ 2.]]) >>> np.column_stack((a[:,newaxis],b[:,newaxis])) array([[ 4., 3.], [ 2., 8.]]) >>> np.hstack((a[:,newaxis],b[:,newaxis])) # the result is the same array([[ 4., 3.], [ 2., 8.]])
另一方面,對於任何輸入數組,函數 row_stack 相當於 vstack。一般來說,對於具有兩個以上維度的數組,hstack 沿第二軸堆疊,vstack 沿第一軸堆疊,concatenate 允許一個可選參數,給出串接應該發生的軸。
請注意
在復雜情況下,r_ 和 c_ 可用於通過沿一個軸疊加數字來創建數組。它們允許使用范圍字面量(“:”)
>>> np.r_[1:4,0,4] array([1, 2, 3, 0, 4])
當以數組作為參數使用時,r_ 和 c_ 類似於其默認行為中的 vstack 和 hstack ,但是允許一個可選參數給出要沿其連接的軸的編號。
另見:
hstack, vstack, column_stack, concatenate, c_, r_
將一個數組分成幾個較小的數組
使用 hsplit ,可以沿其水平軸拆分數組,通過指定要返回的均勻划分的數組數量,或通過指定要在其后進行划分的列:
>>> a = np.floor(10*np.random.random((2,12))) >>> a array([[ 9., 5., 6., 3., 6., 8., 0., 7., 9., 7., 2., 7.], [ 1., 4., 9., 2., 2., 1., 0., 6., 2., 2., 4., 0.]]) >>> np.hsplit(a,3) # Split a into 3 [array([[ 9., 5., 6., 3.], [ 1., 4., 9., 2.]]), array([[ 6., 8., 0., 7.], [ 2., 1., 0., 6.]]), array([[ 9., 7., 2., 7.], [ 2., 2., 4., 0.]])] >>> np.hsplit(a,(3,4)) # Split a after the third and the fourth column [array([[ 9., 5., 6.], [ 1., 4., 9.]]), array([[ 3.], [ 2.]]), array([[ 6., 8., 0., 7., 9., 7., 2., 7.], [ 2., 1., 0., 6., 2., 2., 4., 0.]])]
vsplit 沿縱軸分割,並且 array_split 允許指定沿哪個軸分割。
復制和視圖
當計算和操作數組時,它們的數據有時被復制到新的數組中,有時不復制。對於初學者來說,這經常是一個混亂的來源。有三種情況:
# 完全不復制
簡單賦值不會創建數組對象或其數據的拷貝。
>>> a = np.arange(12) >>> b = a # no new object is created >>> b is a # a and b are two names for the same ndarray object True >>> b.shape = 3,4 # changes the shape of a >>> a.shape (3, 4)
Python將可變對象作為引用傳遞,所以函數調用不會復制。
>>> def f(x): ... print(id(x)) ... >>> id(a) # id is a unique identifier of an object 148293216 >>> f(a) 148293216
# 視圖或淺復制
不同的數組對象可以共享相同的數據。 view 方法創建一個新的數組對象,它查看相同的數據。
>>> c = a.view() >>> c is a False >>> c.base is a # c is a view of the data owned by a True >>> c.flags.owndata False >>> >>> c.shape = 2,6 # a's shape doesn't change >>> a.shape (3, 4) >>> c[0,4] = 1234 # a's data changes >>> a array([[ 0, 1, 2, 3], [1234, 5, 6, 7], [ 8, 9, 10, 11]])
對數組切片返回一個視圖:
>>> s = a[ : , 1:3] # spaces added for clarity; could also be written "s = a[:,1:3]" >>> s[:] = 10 # s[:] is a view of s. Note the difference between s=10 and s[:]=10 >>> a array([[ 0, 10, 10, 3], [1234, 10, 10, 7], [ 8, 10, 10, 11]])
深拷貝
copy 方法生成數組及其數據的完整拷貝。
>>> d = a.copy() # a new array object with new data is created >>> d is a False >>> d.base is a # d doesn't share anything with a False >>> d[0,0] = 9999 >>> a array([[ 0, 10, 10, 3], [1234, 10, 10, 7], [ 8, 10, 10, 11]])
# 函數和方法概述
這里列出了一些根據類別排列的有用的NumPy函數和方法名稱。完整列表見Routines。
- 數組創建
arange, array, copy, empty, empty_like, eye, fromfile, fromfunction, identity, linspace, logspace, mgrid, ogrid, ones, ones_like, r, zeros, zeros_like
- 轉換
ndarray.astype, atleast_1d, atleast_2d, atleast_3d, mat
- 手法
array_split, column_stack, concatenate, diagonal, dsplit, dstack, hsplit, hstack, ndarray.item, newaxis, ravel, repeat, reshape, resize, squeeze, swapaxes, take, transpose, vsplit, vstack
- 問題
all, any, nonzero, where
- 順序
argmax, argmin, argsort, max, min, ptp, searchsorted, sort
- 操作
choose, compress, cumprod, cumsum, inner, ndarray.fill, imag, prod, put, putmask, real, sum
- 基本統計
cov, mean, std, var
- 基本線性代數
cross, dot, outer, linalg.svd, vdot
Less 基礎
# 廣播(Broadcasting)規則
Broadcasting允許通用函數以有意義的方式處理具有不完全相同形狀的輸入。
Broadcasting的第一個規則是,如果所有輸入數組不具有相同數量的維度,則“1”將被重復地添加到較小數組的形狀,直到所有數組具有相同數量的維度。
Broadcasting的第二個規則確保沿着特定維度具有大小為1的數組表現得好像它們具有沿着該維度具有最大形狀的數組的大小。假定數組元素的值沿“Broadcasting”數組的該維度相同。
在應用廣播規則之后,所有陣列的大小必須匹配。更多細節可以在 Broadcasting 中找到。
# 花式索引和索引技巧
NumPy提供了比常規Python序列更多的索引能力。正如我們前面看到的,除了通過整數和切片進行索引之外,還可以使用整數數組和布爾數組進行索引。
# 使用索引數組索引
>>> a = np.arange(12)**2 # the first 12 square numbers >>> i = np.array( [ 1,1,3,8,5 ] ) # an array of indices >>> a[i] # the elements of a at the positions i array([ 1, 1, 9, 64, 25]) >>> >>> j = np.array( [ [ 3, 4], [ 9, 7 ] ] ) # a bidimensional array of indices >>> a[j] # the same shape as j array([[ 9, 16], [81, 49]]) #返回一維數組a的每個j對應索引的值
當被索引的數組 a 是一個多維數組,單個索引數組指的是 a 的第一個維度。以下示例通過使用調色板將標簽圖像轉換為彩色圖像來作為舉例。
>>> palette = np.array( [ [0,0,0], # black ... [255,0,0], # red ... [0,255,0], # green ... [0,0,255], # blue ... [255,255,255] ] ) # white >>> image = np.array( [ [ 0, 1, 2, 0 ], # each value corresponds to a color in the palette ... [ 0, 3, 4, 0 ] ] ) >>> palette[image] # the (2,4,3) color image array([[[ 0, 0, 0], [255, 0, 0], [ 0, 255, 0], [ 0, 0, 0]], [[ 0, 0, 0], [ 0, 0, 255], [255, 255, 255], [ 0, 0, 0]]]) #返回palette中每個image的元素對應的行
我們也可以給出多個維度的索引。每個維度的索引數組必須具有相同的形狀。
>>> a = np.arange(12).reshape(3,4) >>> a array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> i = np.array( [ [0,1], # indices for the first dim of a ... [1,2] ] ) >>> j = np.array( [ [2,1], # indices for the second dim ... [3,3] ] ) >>> >>> a[i,j] # i and j must have equal shape #返回a中i對應的行和j對應列的值 array([[ 2, 5], [ 7, 11]]) >>> >>> a[i,2] #返回a中i對應的行和定列為2的值 array([[ 2, 6], [ 6, 10]]) >>> >>> a[:,j] # i.e., a[ : , j] #返回a中每行元素索引為j對應列的值 array([[[ 2, 1], [ 3, 3]], [[ 6, 5], [ 7, 7]], [[10, 9], [11, 11]]])
當然,我們可以把 i 和 j 放在一個序列中(比如一個列表),然后用列表進行索引。
>>> l = [i,j] >>> a[l] # equivalent to a[i,j] array([[ 2, 5], [ 7, 11]])
然而,我們不能將 i 和 j 放入一個數組中,因為這個數組將被解釋為索引第一個維度。
>>> s = np.array( [i,j] ) >>> a[s] # not what we want Traceback (most recent call last): File "<stdin>", line 1, in ? IndexError: index (3) out of range (0<=index<=2) in dimension 0 >>> >>> a[tuple(s)] # same as a[i,j] array([[ 2, 5], [ 7, 11]])
索引數組的另一個常見用途是搜索時間相關序列的最大值:
>>> time = np.linspace(20, 145, 5) # time scale >>> data = np.sin(np.arange(20)).reshape(5,4) # 4 time-dependent series >>> time array([ 20. , 51.25, 82.5 , 113.75, 145. ]) >>> data array([[ 0. , 0.84147098, 0.90929743, 0.14112001], [-0.7568025 , -0.95892427, -0.2794155 , 0.6569866 ], [ 0.98935825, 0.41211849, -0.54402111, -0.99999021], [-0.53657292, 0.42016704, 0.99060736, 0.65028784], [-0.28790332, -0.96139749, -0.75098725, 0.14987721]]) >>> >>> ind = data.argmax(axis=0) # index of the maxima for each series #返回data中每列值最大的行號 >>> ind array([2, 0, 3, 1]) >>> >>> time_max = time[ind] # times corresponding to the maxima >>> >>> data_max = data[ind, range(data.shape[1])] # => data[ind[0],0], data[ind[1],1]... >>> #返回dat中ind對應的行號和range(5)即0,1,2,3對應的列的值 >>> time_max array([ 82.5 , 20. , 113.75, 51.25]) >>> data_max array([ 0.98935825, 0.84147098, 0.99060736, 0.6569866 ]) >>> >>> np.all(data_max == data.max(axis=0)) True
你還可以使用數組索引作為目標來賦值:
>>> a = np.arange(5) >>> a array([0, 1, 2, 3, 4]) >>> a[[1,3,4]] = 0 >>> a array([0, 0, 2, 0, 0])
然而,當索引列表包含重復時,賦值完成多次,留下最后一個值:
>>> a = np.arange(5) >>> a[[0,0,2]]=[1,2,3] >>> a array([2, 1, 3, 3, 4])
這相當合理,但如果你想使用Python的 += 構造要小心,因為這可能得不到你想要的效果:
>>> a = np.arange(5) >>> a[[0,0,2]]+=1 >>> a array([1, 1, 3, 3, 4])
即使0在索引列表中出現兩次,第0個元素只會增加一次。這是因為Python要求“a + = 1”等同於“a = a + 1”。
# 使用布爾值作為數組索引
當我們用(整數)索引數組索引數組時,我們提供了要選擇的索引列表。使用布爾值作為索引時,方法是不同的;我們明確地選擇數組中的哪些元素我們想要的,哪些不是。
我們可以想到的布爾索引最自然的方式是使用與原始數組具有相同形狀的布爾數組:
>>> a = np.arange(12).reshape(3,4) >>> b = a > 4 >>> b # b is a boolean with a's shape array([[False, False, False, False], [False, True, True, True], [ True, True, True, True]]) >>> a[b] # 1d array with the selected elements array([ 5, 6, 7, 8, 9, 10, 11])
# 此屬性在賦值時非常有用:
>>> a[b] = 0 # All elements of 'a' higher than 4 become 0 >>> a array([[0, 1, 2, 3], [4, 0, 0, 0], [0, 0, 0, 0]])
你可以查看以下示例,了解如何使用布爾索引生成 Mandelbrot 集的圖像:
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> def mandelbrot( h,w, maxit=20 ): ... """Returns an image of the Mandelbrot fractal of size (h,w).""" ... y,x = np.ogrid[ -1.4:1.4:h*1j, -2:0.8:w*1j ] ... c = x+y*1j ... z = c ... divtime = maxit + np.zeros(z.shape, dtype=int) ... ... for i in range(maxit): ... z = z**2 + c ... diverge = z*np.conj(z) > 2**2 # who is diverging ... div_now = diverge & (divtime==maxit) # who is diverging now ... divtime[div_now] = i # note when ... z[diverge] = 2 # avoid diverging too much ... ... return divtime >>> plt.imshow(mandelbrot(400,400)) >>> plt.show()

第二種使用布爾索引的方法更類似於整數索引;對於數組的每個維度,我們給出一個一維布爾數組,選擇我們想要的切片:
>>> a = np.arange(12).reshape(3,4) >>> b1 = np.array([False,True,True]) # first dim selection >>> b2 = np.array([True,False,True,False]) # second dim selection >>> >>> a[b1,:] # selecting rows array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> a[b1] # same thing array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> a[:,b2] # selecting columns array([[ 0, 2], [ 4, 6], [ 8, 10]]) >>> >>> a[b1,b2] # a weird thing to do array([ 4, 10])
請注意,1D布爾數組的長度必須與你要切片的維度(或軸)的長度一致。在前面的示例中, b1 是rank為1的數組,其長度為3( a 中行的數量), b2 (長度4)適合於索引 a 的第二個rank(列)。
# ix_()函數
可以使用 ix_ 函數來組合不同的向量以獲得每個n-uplet的結果。例如,如果要計算從向量a、b和c中的取得的所有三元組的所有a + b * c:
>>> a = np.array([2,3,4,5]) >>> b = np.array([8,5,4]) >>> c = np.array([5,4,6,8,3]) >>> ax,bx,cx = np.ix_(a,b,c) >>> ax array([[[2]], [[3]], [[4]], [[5]]]) >>> bx array([[[8], [5], [4]]]) >>> cx array([[[5, 4, 6, 8, 3]]]) >>> ax.shape, bx.shape, cx.shape ((4, 1, 1), (1, 3, 1), (1, 1, 5)) >>> result = ax+bx*cx >>> result array([[[42, 34, 50, 66, 26], [27, 22, 32, 42, 17], [22, 18, 26, 34, 14]], [[43, 35, 51, 67, 27], [28, 23, 33, 43, 18], [23, 19, 27, 35, 15]], [[44, 36, 52, 68, 28], [29, 24, 34, 44, 19], [24, 20, 28, 36, 16]], [[45, 37, 53, 69, 29], [30, 25, 35, 45, 20], [25, 21, 29, 37, 17]]]) >>> result[3,2,4] 17 >>> a[3]+b[2]*c[4] 17
你還可以如下實現reduce:
>>> def ufunc_reduce(ufct, *vectors): ... vs = np.ix_(*vectors) ... r = ufct.identity ... for v in vs: ... r = ufct(r,v) ... return r
然后將其用作:
>>> ufunc_reduce(np.add,a,b,c) array([[[15, 14, 16, 18, 13], [12, 11, 13, 15, 10], [11, 10, 12, 14, 9]], [[16, 15, 17, 19, 14], [13, 12, 14, 16, 11], [12, 11, 13, 15, 10]], [[17, 16, 18, 20, 15], [14, 13, 15, 17, 12], [13, 12, 14, 16, 11]], [[18, 17, 19, 21, 16], [15, 14, 16, 18, 13], [14, 13, 15, 17, 12]]])
與正常的ufunc.reduce相比,這個版本的reduce的優點是它使用Broadcasting規則,以避免創建參數數組輸出的大小乘以向量的數量。
# 使用字符串索引
請參見結構化數組。
線性代數
讓我們繼續,這個部分包含了基本的線性代數。
# 簡單數組操作
有關更多信息,請參閱numpy目錄中的linalg.py。
>>> import numpy as np >>> a = np.array([[1.0, 2.0], [3.0, 4.0]]) >>> print(a) [[ 1. 2.] [ 3. 4.]] >>> a.transpose() array([[ 1., 3.], [ 2., 4.]]) >>> np.linalg.inv(a) array([[-2. , 1. ], [ 1.5, -0.5]]) >>> u = np.eye(2) # unit 2x2 matrix; "eye" represents "I" >>> u array([[ 1., 0.], [ 0., 1.]]) >>> j = np.array([[0.0, -1.0], [1.0, 0.0]]) >>> np.dot (j, j) # matrix product array([[-1., 0.], [ 0., -1.]]) >>> np.trace(u) # trace 2.0 >>> y = np.array([[5.], [7.]]) >>> np.linalg.solve(a, y) array([[-3.], [ 4.]]) >>> np.linalg.eig(j) (array([ 0.+1.j, 0.-1.j]), array([[ 0.70710678+0.j , 0.70710678-0.j ], [ 0.00000000-0.70710678j, 0.00000000+0.70710678j]]))
Parameters:
square matrix
Returns
The eigenvalues, each repeated according to its multiplicity.
The normalized (unit "length") eigenvectors, such that the column ``v[:,i]`` is the eigenvector corresponding to the eigenvalue ``w[i]`` .
技巧和提示
在這里,我們列出一些簡短而有用的提示。
# “自動”重定義數組形狀
要更改數組的大小,你可以省略其中一個size,它將被自動推導出來:
>>> a = np.arange(30) >>> a.shape = 2,-1,3 # -1 means "whatever is needed" >>> a.shape (2, 5, 3) >>> a 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], [24, 25, 26], [27, 28, 29]]])
# 向量堆疊
我們如何從一個相同大小的行向量列表構造一個二維數組?在MATLAB中,這很容易:如果x和y是兩個長度相同的向量,那么只需要 m=[x;y] 。在NumPy中,這通過函數 column_stack ,dstack ,hstack 和 vstack 工作,具體取決於要做什么堆疊。例如:
x = np.arange(0,10,2) # x=([0,2,4,6,8]) y = np.arange(5) # y=([0,1,2,3,4]) m = np.vstack([x,y]) # m=([[0,2,4,6,8], # [0,1,2,3,4]]) xy = np.hstack([x,y]) # xy =([0,2,4,6,8,0,1,2,3,4])
這些功能背后的邏輯可能很奇怪。
另見:
NumPy for Matlab users
# 直方圖
NumPy的 histogram 函數應用於一個數組,並返回一對向量:數組的histogram和向量的bin。注意: matplotlib 也具有構建histograms的函數(在Matlab中稱為 hist ),它與NumPy中的不同。主要區別是 pylab.hist 自動繪制histogram,而 numpy.histogram 僅生成數據。
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> # Build a vector of 10000 normal deviates with variance 0.5^2 and mean 2 >>> mu, sigma = 2, 0.5 >>> v = np.random.normal(mu,sigma,10000) >>> # Plot a normalized histogram with 50 bins >>> plt.hist(v, bins=50, normed=1) # matplotlib version (plot) >>> plt.show()

>>> # Compute the histogram with numpy and then plot it >>> (n, bins) = np.histogram(v, bins=50, normed=True) # NumPy version (no plot) >>> plt.plot(.5*(bins[1:]+bins[:-1]), n) >>> plt.show()

0
