基礎(chǔ)
NumPy提供的最主要的對(duì)象就是同數(shù)據(jù)類(lèi)型的多維數(shù)組坦敌。他實(shí)際上可以被理解成一張表(元素通常是數(shù)組)岖妄,所有元素具有相同的類(lèi)型,這些元素可以使用由正整數(shù)構(gòu)建的元組(tuple)來(lái)索引。在NumPy中捆姜,各個(gè)維度被稱(chēng)為軸(axes)妆够。軸的總數(shù)被稱(chēng)為秩(rank)识啦。
舉例來(lái)說(shuō),三維空間的一個(gè)點(diǎn)的坐標(biāo)是[1,2,3]神妹,它就是一個(gè)rank是1的一個(gè)數(shù)組颓哮。因?yàn)樗灰?axis,而這個(gè)axis的長(zhǎng)度是3.
再來(lái)看一個(gè)例子:
[[1.,0.,0.],
[0.,1.,2.]]
該數(shù)組的rank是2(兩個(gè)維度)鸵荠,第一個(gè)維度的長(zhǎng)度是2冕茅,第二個(gè)維度的長(zhǎng)度是3。
NumPy的數(shù)組類(lèi)叫做ndarray蛹找。同時(shí)也有個(gè)別名array姨伤。這里需要注意一下,numpy.array和Python標(biāo)準(zhǔn)庫(kù)的array.array完全不是一個(gè)東西熄赡,后者僅僅支持一維數(shù)組且提供的功能較少姜挺。ndarray對(duì)象比較重要的屬性有:
ndarray.ndim
數(shù)組的axes的數(shù)目。
ndarray.shape
數(shù)組的形狀彼硫。如一個(gè)n * m的矩陣炊豪,它的shape就是(n,m)凌箕。而且len(ndarray.shape)==ndarray.ndim
ndarray.size
數(shù)組中所有元素的個(gè)數(shù)。它實(shí)際上是ndarray.shape中所有值的乘積词渤。
ndarray.dtype
用于描述數(shù)組中元素類(lèi)型的對(duì)象牵舱。我們可以使用Python標(biāo)準(zhǔn)類(lèi)型來(lái)創(chuàng)建或指定dtype。不過(guò)NumPy也提供了一些它自己的類(lèi)型缺虐,比如:numpy.int32,numpy.int16,numpy.float64等芜壁。
ndarray.itemsize
數(shù)組中單個(gè)元素以字節(jié)計(jì)的大小。比如高氮,若類(lèi)型是float64,則itemsize就是8(64/8)慧妄。它限ndarray.dtype.itemsize是等價(jià)的。
ndarray.data
存儲(chǔ)數(shù)組中實(shí)際的數(shù)據(jù)剪芍。通常我們不會(huì)直接用這個(gè)屬性塞淹,因?yàn)楫?dāng)我們需要訪問(wèn)數(shù)據(jù)時(shí)幾乎總是使用數(shù)組提供的索引功能。
一個(gè)例子
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,a.itemsize
('int32', 4)
a.size
15
type(a)
numpy.ndarray
b = np.array([6,7,8])
b
array([6, 7, 8])
type(b)
numpy.ndarray
創(chuàng)建數(shù)組
有好幾種方法可以創(chuàng)建數(shù)組罪裹。
比如:通過(guò)array饱普,我們可以從普通的Python列表或者元組直接創(chuàng)建。元素的類(lèi)型根據(jù)源類(lèi)型推斷状共。
a = np.array([2,3,4])
a
array([2, 3, 4])
a.dtype
dtype('int32')
b = np.array([1.2,3.5,5.1])
b.dtype
dtype('float64')
一個(gè)常見(jiàn)的錯(cuò)誤是套耕,把數(shù)組內(nèi)容當(dāng)做參數(shù)直接傳給array,而不是作為一個(gè)列表或元組:
a = np.array(1,2,3,4) #錯(cuò)誤
a = np.array([1,2,3,4]) #正確
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-16-f55a2f3e0f54> in <module>()
----> 1 a = np.array(1,2,3,4) #錯(cuò)誤
2 a = np.array([1,2,3,4]) #正確
ValueError: only 2 non-keyword arguments accepted
array將兩層嵌套序列轉(zhuǎn)成二維數(shù)組峡继,三層嵌套序列轉(zhuǎn)成三維數(shù)組冯袍,以此類(lèi)推:
b = np.array([(1.5,2,3),(4,5,6)])
b
array([[1.5, 2. , 3. ],
[4. , 5. , 6. ]])
數(shù)據(jù)類(lèi)型在創(chuàng)建時(shí)可以指定:
c = np.array([[1,2],[3,4]],dtype=complex)
c
array([[1.+0.j, 2.+0.j],
[3.+0.j, 4.+0.j]])
在實(shí)際的工作中,我們常常需要固定形狀大小的數(shù)組鬓椭,但在定義數(shù)組時(shí)還沒(méi)有加載數(shù)據(jù)颠猴。
NumPy為我們提供了一些包含占位符的數(shù)組創(chuàng)建函數(shù)关划。這樣我們就可以避免使用動(dòng)態(tài)數(shù)組小染,因?yàn)閯?dòng)態(tài)數(shù)組在增長(zhǎng)的時(shí)候很耗時(shí)的。
- zeros函數(shù)可以創(chuàng)建所有元素均為0的數(shù)組贮折;
- ones函數(shù)可以創(chuàng)建所有元素均為1的數(shù)組裤翩;
- empty函數(shù)創(chuàng)建的數(shù)組,其元素都是隨機(jī)的5鏖S辉!
默認(rèn)情況下每庆,創(chuàng)建時(shí)的dtype都是float64筐带;
np.zeros((3,4)) #他的參數(shù)并不是數(shù)據(jù),而是數(shù)組的形狀(shape)
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
np.ones((2,3,4),dtype=np.int16) # 指定數(shù)據(jù)類(lèi)型
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)) # 一定要小心缤灵,元素都是隨機(jī)的
array([[1.5, 2. , 3. ],
[4. , 5. , 6. ]])
NumPy提供了一個(gè)類(lèi)似于Python標(biāo)準(zhǔn)庫(kù)中range類(lèi)似的函數(shù)np.arange來(lái)生成數(shù)字序列
np.arange(10,30,5) # start,stop,step
array([10, 15, 20, 25])
np.arange(0,2,0.3) #接受浮點(diǎn)數(shù)參數(shù)
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])
不過(guò)因?yàn)楦↑c(diǎn)數(shù)的有限精度問(wèn)題伦籍,arange返回的數(shù)組長(zhǎng)度可能無(wú)法預(yù)知蓝晒。因此,最好使用linspace帖鸦,它可以指定所需要的數(shù)組長(zhǎng)度芝薇,而不需要設(shè)定步長(zhǎng):
np.linspace(0,2,9)
array([0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ])
from numpy import pi
x = np.linspace(0,2*pi,100)
f = np.sin(x)
f
array([ 0.00000000e+00, 6.34239197e-02, 1.26592454e-01, 1.89251244e-01,
2.51147987e-01, 3.12033446e-01, 3.71662456e-01, 4.29794912e-01,
4.86196736e-01, 5.40640817e-01, 5.92907929e-01, 6.42787610e-01,
6.90079011e-01, 7.34591709e-01, 7.76146464e-01, 8.14575952e-01,
8.49725430e-01, 8.81453363e-01, 9.09631995e-01, 9.34147860e-01,
9.54902241e-01, 9.71811568e-01, 9.84807753e-01, 9.93838464e-01,
9.98867339e-01, 9.99874128e-01, 9.96854776e-01, 9.89821442e-01,
9.78802446e-01, 9.63842159e-01, 9.45000819e-01, 9.22354294e-01,
8.95993774e-01, 8.66025404e-01, 8.32569855e-01, 7.95761841e-01,
7.55749574e-01, 7.12694171e-01, 6.66769001e-01, 6.18158986e-01,
5.67059864e-01, 5.13677392e-01, 4.58226522e-01, 4.00930535e-01,
3.42020143e-01, 2.81732557e-01, 2.20310533e-01, 1.58001396e-01,
9.50560433e-02, 3.17279335e-02, -3.17279335e-02, -9.50560433e-02,
-1.58001396e-01, -2.20310533e-01, -2.81732557e-01, -3.42020143e-01,
-4.00930535e-01, -4.58226522e-01, -5.13677392e-01, -5.67059864e-01,
-6.18158986e-01, -6.66769001e-01, -7.12694171e-01, -7.55749574e-01,
-7.95761841e-01, -8.32569855e-01, -8.66025404e-01, -8.95993774e-01,
-9.22354294e-01, -9.45000819e-01, -9.63842159e-01, -9.78802446e-01,
-9.89821442e-01, -9.96854776e-01, -9.99874128e-01, -9.98867339e-01,
-9.93838464e-01, -9.84807753e-01, -9.71811568e-01, -9.54902241e-01,
-9.34147860e-01, -9.09631995e-01, -8.81453363e-01, -8.49725430e-01,
-8.14575952e-01, -7.76146464e-01, -7.34591709e-01, -6.90079011e-01,
-6.42787610e-01, -5.92907929e-01, -5.40640817e-01, -4.86196736e-01,
-4.29794912e-01, -3.71662456e-01, -3.12033446e-01, -2.51147987e-01,
-1.89251244e-01, -1.26592454e-01, -6.34239197e-02, -2.44929360e-16])
作為補(bǔ)充,可以看看他們的文檔:array,zeros,zero_like(生成一個(gè)和原矩陣相同形狀的全是0的矩陣),numpy.random.rand,numpy.random.randn,fromfunction,fromfile
可以在notebook里面直接np.array?閱讀作儿,也可以去Numpy的官方文檔洛二。
打印數(shù)組
打印出來(lái)非常類(lèi)似于嵌套函數(shù)
a = np.arange(6) # 一維
print(a)
[0 1 2 3 4 5]
b = np.arange(12).reshape(3,4) # 二維
print(b)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
c = np.arange(24).reshape(2,3,4) # 二維
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]]]
如果數(shù)組太長(zhǎng),NumPy會(huì)自動(dòng)忽略中間部分的數(shù)據(jù)攻锰,只打印首尾:
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]]
當(dāng)然晾嘶,我們可以通過(guò)設(shè)置set_printoptions選項(xiàng)來(lái)關(guān)閉該功能:
np.set_printoptions(threshold='nan)
基礎(chǔ)操作
在數(shù)組上進(jìn)行算術(shù)操作都是元素級(jí)別的操作
a = np.array([20,30,40,50])
b = np.arange(4)
c = a - b
c
array([20, 29, 38, 47])
b ** 2
array([0, 1, 4, 9], dtype=int32)
10 * np.sin(a)
array([ 9.12945251, -9.88031624, 7.4511316 , -2.62374854])
a < 45
array([ True, True, True, False])
在線性代數(shù)中,乘號(hào) * 一般表達(dá)的是矩陣乘法娶吞,但在NumPy中它表示元素級(jí)別的乘法变擒,矩陣乘法在NumPy中使用dot:
A = np.array([[1,1],
[0,1]])
B = np.array([[2,0],
[3,4]])
A * B #元素級(jí)別乘法
array([[2, 0],
[0, 4]])
A.dot(B)
array([[5, 4],
[3, 4]])
np.dot(A,B)
array([[5, 4],
[3, 4]])
上面的操作符都會(huì)新建一個(gè)數(shù)組,而有一些操作符則會(huì)直接修改現(xiàn)有數(shù)組寝志,比如+=娇斑,*=
a = np.ones((2,3),dtype=int)
b = np.random.random((2,3))
a *= 3
a
array([[3, 3, 3],
[3, 3, 3]])
b += a
b
array([[3.96590659, 3.57016481, 3.16824186],
[3.7746882 , 3.05928896, 3.94018039]])
a += b # 類(lèi)型轉(zhuǎn)換失敗,因?yàn)閎是float材部,更加精確毫缆,而a是int
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-50-294cacd62d6f> in <module>()
----> 1 a += b
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int32') with casting rule 'same_kind'
ndarray類(lèi)里內(nèi)置了很多方法來(lái)完成一些一元操作符,比如計(jì)算所有元素之和:
a = np.random.random((2,3))
a
array([[0.80608285, 0.07392699, 0.49798093],
[0.69115847, 0.82903752, 0.63852812]])
print(a.sum(),a.min(),a.max())
18 3 3
默認(rèn)情況下乐导,這些方法不關(guān)心數(shù)組的形狀苦丁,會(huì)將所有元素一起計(jì)算,不過(guò)可以通過(guò)制定axis(軸)來(lái)計(jì)算沿著該軸的數(shù)據(jù):
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)
array([12, 15, 18, 21])
b.min(axis=1)
array([0, 4, 8])
b.cumsum(axis=1)
array([[ 0, 1, 3, 6],
[ 4, 9, 15, 22],
[ 8, 17, 27, 38]], dtype=int32)
通用函數(shù)
numpy提供了一些常用的數(shù)學(xué)函數(shù)物臂,如:sin旺拉,cos,exp等棵磷,操作是作用于每個(gè)單獨(dú)的元素上蛾狗,并產(chǎn)生一個(gè)新的數(shù)組。
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.])
索引仪媒,切片以及遍歷
一維數(shù)組非常類(lèi)似于python的序列沉桌,他們可以被索引,被切片算吩,被遍歷
a = np.arange(10) ** 3
a
array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729], dtype=int32)
a[2]
8
a[2:5]
array([ 8, 27, 64], dtype=int32)
a[:6:2] = -1000 # 等價(jià)于 a[0:6:2] = -1000 從開(kāi)始到第6個(gè)(不含)留凭,以2為步長(zhǎng)將元素設(shè)置為-1000
a
array([-1000, 1, -1000, 27, -1000, 125, 216, 343, 512,
729], dtype=int32)
a[::-1] #數(shù)組倒序
array([ 729, 512, 343, 216, 125, -1000, 27, -1000, 1,
-1000], dtype=int32)
for i in a:
print(i ** (1/3.0))
nan
1.0
nan
3.0
nan
5.0
5.999999999999999
6.999999999999999
7.999999999999999
8.999999999999998
C:\Users\ttc\Anaconda3\lib\site-packages\ipykernel_launcher.py:2: RuntimeWarning: invalid value encountered in power
多維數(shù)組每一個(gè)軸均有一個(gè)索引,這些索引使用“偎巢,”分隔蔼夜,以元組的形式表現(xiàn):
def f(x,y):
return 10 * x + y
b = np.fromfunction(f,(5,4),dtype=int)
b
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])
b[:,1]
array([ 1, 11, 21, 31, 41])
b[1:3,:]
array([[10, 11, 12, 13],
[20, 21, 22, 23]])
當(dāng)提供的索引不夠,那么NumPy會(huì)自動(dòng)補(bǔ)全其他軸的索引:
b[-1] # 等價(jià)于b[-1,:]
array([40, 41, 42, 43])
另外压昼,NumPy還有...這種寫(xiě)法求冷,它會(huì)自動(dòng)判斷所需要填補(bǔ)的索引:
比如翠订,我們現(xiàn)在有一個(gè)擁有五個(gè)軸(axis)的數(shù)組:
- x[1,2,...]等價(jià)于 x[1,2,:,:,:]
- x[...,3]等價(jià)于x[:,:,:,:,3]
- x[4,...,5,:] 等價(jià)于x[4,:,:,5,:]
c = np.array([[[0,1,2],
[10,12,13]],
[[100,101,102],
[110,112,113]]])
c.shape
(2, 2, 3)
c[1,...]
array([[100, 101, 102],
[110, 112, 113]])
c[...,2]
array([[ 2, 13],
[102, 113]])
遍歷從第一個(gè)軸開(kāi)始的:
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]
不過(guò),要是想要將數(shù)組"打平"訪問(wèn)遵倦,可以使用flat屬性:
for element in b.flat:
print(element,end=' ')
0 1 2 3 10 11 12 13 20 21 22 23 30 31 32 33 40 41 42 43
形狀操作
修改一個(gè)數(shù)組的形狀
a = np.floor(10 * np.random.random((3,4)))
a
array([[4., 9., 4., 0.],
[7., 1., 6., 6.],
[2., 7., 4., 0.]])
a.shape
(3, 4)
在NumPy中有多種方法可以改變一個(gè)數(shù)組的形狀尽超。
請(qǐng)注意,下面三種方法均返回一個(gè)修改后的數(shù)組梧躺,但又不改變?cè)瓉?lái)的數(shù)組:
a.ravel() # 返回打平的數(shù)組
array([4., 9., 4., 0., 7., 1., 6., 6., 2., 7., 4., 0.])
a.reshape(6,2) # 返回目標(biāo)形狀的數(shù)組
array([[4., 9.],
[4., 0.],
[7., 1.],
[6., 6.],
[2., 7.],
[4., 0.]])
a.T # 返回它的轉(zhuǎn)置
array([[4., 7., 2.],
[9., 1., 7.],
[4., 6., 4.],
[0., 6., 0.]])
由ravel()返回的數(shù)組似谁,其元素的順序默認(rèn)是C語(yǔ)言風(fēng)格的,即最右側(cè)的索引“變化最快”掠哥,因此a[0,0]的下一個(gè)元素是a[0,1]巩踏,如果傳給ravel()的數(shù)組時(shí)從其他數(shù)組切片得到的,或者使用不尋常的選項(xiàng)構(gòu)建的续搀,那就不得不拷貝一次數(shù)據(jù)了塞琼。
ravel()和reshape()函數(shù)本身也接受一個(gè)可選的參數(shù),可以使用Fortran風(fēng)格(Fortran-style)的數(shù)組u禁舷,它最左側(cè)的索引變化的最快彪杉,即a[0,0]的下一個(gè)元素是a[1,0]。
reshape函數(shù)不會(huì)改變?cè)瓟?shù)組牵咙,而ndarray.resize方法則會(huì)改變?cè)瓟?shù)組:
a
array([[4., 9., 4., 0.],
[7., 1., 6., 6.],
[2., 7., 4., 0.]])
a.resize((2,6))
a
array([[4., 9., 4., 0., 7., 1.],
[6., 6., 2., 7., 4., 0.]])
如果在reshape操作時(shí)將某一維度設(shè)置為-1派近,那么該維度就會(huì)被自動(dòng)計(jì)算,比如:
a.reshape(3,-1) # 只在乎數(shù)組第一維是3洁桌,第二維讓系統(tǒng)自動(dòng)計(jì)算
array([[4., 9., 4., 0.],
[7., 1., 6., 6.],
[2., 7., 4., 0.]])
將不同的數(shù)組堆疊(stacking)起來(lái)
多個(gè)數(shù)組可以沿著不同的軸堆疊起來(lái):
a = np.floor(10 * np.random.random((2,2)))
a
array([[4., 3.],
[5., 3.]])
b = np.floor(10 * np.random.random((2,2)))
b
array([[9., 7.],
[9., 3.]])
np.vstack((a,b)) # 垂直堆疊
array([[4., 3.],
[5., 3.],
[9., 7.],
[9., 3.]])
np.hstack((a,b)) # 水平堆疊
array([[4., 3., 9., 7.],
[5., 3., 9., 3.]])
column_stack可以將一維數(shù)組作為一列插入一個(gè)二維數(shù)組:
c = np.array([3,3])
np.column_stack((a,c))
array([[4., 3., 3.],
[5., 3., 3.]])
對(duì)于超過(guò)二維的情況渴丸,不討論
將一個(gè)數(shù)組切分成多個(gè)
使用hsplit,我們可以將一個(gè)數(shù)組沿水平方向進(jìn)行切分。切分時(shí)可以指定:
- 目標(biāo)數(shù)組個(gè)數(shù) ——將自動(dòng)計(jì)算切分后的數(shù)組的形狀
- 切分列下表 —— 將在指定的列下標(biāo)處進(jìn)行切分
a = np.floor(10 * np.random.random((2,12)))
a
array([[5., 4., 7., 6., 0., 6., 2., 8., 7., 1., 2., 5.],
[3., 9., 3., 0., 4., 1., 3., 1., 0., 9., 2., 1.]])
np.hsplit(a,3) # 將a橫向切分成三個(gè)數(shù)組
[array([[5., 4., 7., 6.],
[3., 9., 3., 0.]]), array([[0., 6., 2., 8.],
[4., 1., 3., 1.]]), array([[7., 1., 2., 5.],
[0., 9., 2., 1.]])]
np.hsplit(a,(3,4)) # 在第三列和第四列進(jìn)行切分另凌,從1開(kāi)始計(jì)數(shù)
[array([[5., 4., 7.],
[3., 9., 3.]]), array([[6.],
[0.]]), array([[0., 6., 2., 8., 7., 1., 2., 5.],
[4., 1., 3., 1., 0., 9., 2., 1.]])]
類(lèi)似的谱轨,還有vsplit,而array_split則允許指定切分的軸
拷貝(copy)與視圖(view)
當(dāng)我們操作數(shù)組的時(shí)候吠谢,其數(shù)據(jù)有時(shí)候會(huì)被拷貝到一個(gè)新的數(shù)組土童,而有時(shí)又不會(huì)。這對(duì)于初學(xué)者而言常常是一個(gè)覺(jué)得很不清晰的地方囊卜。
實(shí)際上娜扇,一共有三種情況:
根本不拷貝
簡(jiǎn)單的賦值不會(huì)發(fā)生任何拷貝行為:
a = np.arange(12)
b = a # 不會(huì)新建對(duì)象
b is a # a和b是對(duì)同一個(gè)ndarray對(duì)象的兩個(gè)名字
True
b.shape = 3,4 # 同時(shí)會(huì)修改a的形狀
a.shape
(3, 4)
Python以引用的方式傳遞可變對(duì)象,所以函數(shù)調(diào)用不會(huì)產(chǎn)生拷貝:
def f(x):
print(id(x))
print(id(a)) # id是一個(gè)對(duì)象(實(shí)例)獨(dú)一無(wú)二的標(biāo)識(shí)符
f(a)
87464496
87464496
視圖和淺拷貝
不同的數(shù)據(jù)對(duì)象可以共享相同的數(shù)據(jù)栅组。view方法新建一個(gè)數(shù)組對(duì)象,但仍然使用相同的數(shù)據(jù)枢析。
c = a.view()
c is a
False
c.base is a # c僅僅是a中數(shù)據(jù)的一個(gè)視圖
True
c.flags.owndata # c不擁有自己的數(shù)據(jù)
False
c.shape = 2,6
a.shape
(3, 4)
c[0,4] = 1234 # a的數(shù)據(jù)會(huì)改變S竦А!醒叁!
a
array([[ 0, 1, 2, 3],
[1234, 5, 6, 7],
[ 8, 9, 10, 11]])
c
array([[ 0, 1, 2, 3, 1234, 5],
[ 6, 7, 8, 9, 10, 11]])
對(duì)一個(gè)數(shù)組進(jìn)行切片會(huì)返回它的視圖:
s = a[:,1:3]
s[:] = 10
a
array([[ 0, 10, 10, 3],
[1234, 10, 10, 7],
[ 8, 10, 10, 11]])
深拷貝
copy方法會(huì)對(duì)數(shù)組及其數(shù)據(jù)做一次完整的拷貝司浪。
d = a.copy() # 新建一個(gè)數(shù)組對(duì)象泊业,而且把數(shù)據(jù)也拷貝了一份
d is a
False
d.base is a # d不從a共享任何東西
False
d[0,0] = 9999
a
array([[ 0, 10, 10, 3],
[1234, 10, 10, 7],
[ 8, 10, 10, 11]])
基礎(chǔ)函數(shù)及方法總覽
我們這里按照類(lèi)目列出了一些最常用的NumPy的函數(shù)及方法。請(qǐng)參考routines以了解更全的列表
Array Creation
arange,array,copy ...
Conversions
ndarray.astype,atleast_1d ....
Mainpulations
array_split,column_stack ...
Questions
all,any,nonzero,where
Odering
argmax,argmin,argsort,max,min,ptp,searchsorted,sort
Operations
choose,compress,cumprod,cumsum,inner....
Basic Statistics
cov,mean,std,var
Basic Linear Algebra
cross,dot,outer,linalg.svd,vdot
廣播機(jī)制
Numpy的Universal functions 中要求輸入的數(shù)組shape是一致的啊易,當(dāng)數(shù)組的shape不想等的時(shí)候吁伺,則會(huì)使用廣播機(jī)制,調(diào)整數(shù)組使得shape一樣租谈,滿足規(guī)則篮奄,則可以運(yùn)算,否則就出錯(cuò)
四條規(guī)則如下:
- 讓所有輸入數(shù)組都向其中shape最長(zhǎng)的數(shù)組看齊割去,shape中不足的部分都通過(guò)在前面加1補(bǔ)齊
- 輸出數(shù)組的shape是輸入數(shù)組shape的各個(gè)軸上的最大值
- 如果輸入數(shù)組的某個(gè)軸和輸出數(shù)組的對(duì)應(yīng)軸的長(zhǎng)度相同或者其長(zhǎng)度為1時(shí)窟却,這個(gè)數(shù)組能夠用來(lái)計(jì)算,否則出錯(cuò)
-
當(dāng)輸入數(shù)組的某個(gè)軸的長(zhǎng)度為1時(shí)呻逆,沿著此軸運(yùn)算時(shí)都用此軸上的第一組值
時(shí)髦索引(fancy indexing)及索引技巧
NumPy比一般的Python序列支持更多的索引功能夸赫。
在支持使用整型數(shù)字及切片來(lái)進(jìn)行索引的基礎(chǔ)上,數(shù)組還可以使用整形數(shù)據(jù)和布爾型數(shù)組來(lái)進(jìn)行索引咖城。
使用索引數(shù)組(array if indices)來(lái)進(jìn)行索引
a = np.arange(12) ** 2 # 12個(gè)平方數(shù)
i = np.array([1,1,3,8,5]) # 一些索引
a[i]
array([ 1, 1, 9, 64, 25], dtype=int32)
j = np.array([[3,4],[9,7]]) # 一個(gè)二維的索引數(shù)組
a[j]
array([[ 9, 16],
[81, 49]], dtype=int32)
當(dāng)數(shù)組a是多維數(shù)組的時(shí)候茬腿,一個(gè)單獨(dú)的索引數(shù)組表達(dá)的是數(shù)組a的第一個(gè)維度。
下面這個(gè)例子定義了一個(gè)調(diào)色盤(pán)宜雀,然后圖片以調(diào)色盤(pán)的索引來(lái)表示滓彰,它可以詮釋上面那句話的含義:
palette = np.array([[0,0,0],[255,0,0],[0,255,0],[0,0,255],[255,255,255]])
image = np.array([[0,1,2,0],
[0,3,4,0]])
palette[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]]])
我們也可以讓索引有多個(gè)維度。不過(guò)州袒,所有的索引數(shù)組在每一個(gè)維度上就必須有同樣的形狀:
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],
[1,2]]) # 數(shù)組a的第一個(gè)維度
j = np.array([[2,1],
[3,3]]) # 數(shù)組a的第二個(gè)維度
a[i,j] # i 和 j必須要有相同的形狀 (0,2),(1,1),(1,3),(2,3)
array([[ 2, 5],
[ 7, 11]])
a[i,2]
array([[ 2, 6],
[ 6, 10]])
a[:,j]
array([[[ 2, 1],
[ 3, 3]],
[[ 6, 5],
[ 7, 7]],
[[10, 9],
[11, 11]]])
我們也可以把i和j打包到一個(gè)序列中揭绑,然后使用這個(gè)序列來(lái)進(jìn)行索引:
l = [i,j]
a[l]
array([[ 2, 5],
[ 7, 11]])
但是得千萬(wàn)注意,不要把i和j放在一個(gè)數(shù)組(ndarray)里郎哭,因?yàn)檫@個(gè)數(shù)組表達(dá)的是以第一個(gè)維度來(lái)對(duì)數(shù)組a進(jìn)行索引他匪。
s = np.array([i,j])
a[s]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-135-537bf3252a3e> in <module>()
1 s = np.array([i,j])
----> 2 a[s]
IndexError: index 3 is out of bounds for axis 0 with size 3
a[tuple(s)] # 等價(jià)于a[i,j]
array([[ 2, 5],
[ 7, 11]])
另一個(gè)常用的使用數(shù)組進(jìn)行索引的方式是:在一個(gè)時(shí)間依賴(lài)的序列中找到最大值:
time=np.linspace(20,145,5)
data = np.sin(np.arange(20)).reshape(5,4)
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)
ind
array([2, 0, 3, 1], dtype=int64)
time[ind]
array([ 82.5 , 20. , 113.75, 51.25])
data_max = data[ind,range(data.shape[1])]
data_max
array([0.98935825, 0.84147098, 0.99060736, 0.6569866 ])
np.all(data.max(axis=0) == data_max) # 比較所有元素
True
使用索引數(shù)組不僅可以訪問(wèn)數(shù)組元素,還可以更改數(shù)組元素:
a = np.arange(5)
a
array([0, 1, 2, 3, 4])
a[[1,3,4]] = 0
a
array([0, 0, 2, 0, 0])
不過(guò)如果同一個(gè)索引在索引數(shù)組中出現(xiàn)多次的話夸研,那么賦值操作實(shí)際上就會(huì)被多次執(zhí)行:
a = np.arange(5)
a[[0,0,2]] = [1,2,3] # 0位置被賦值了兩次
a
array([2, 1, 3, 3, 4])
不過(guò)要注意的是邦蜜,python的+=語(yǔ)法結(jié)構(gòu)的行為會(huì)出乎你的預(yù)料,建議不要使用+=操作:
a[[0,0,2]] +=1 # 0位置出現(xiàn)兩次 但是并沒(méi)有多次執(zhí)行+1
a
array([3, 1, 4, 3, 4])
使用布爾數(shù)組來(lái)索引
前面我們使用整型的索引數(shù)組來(lái)訪問(wèn)數(shù)據(jù)的時(shí)候亥至,我們實(shí)際上是提供了想要訪問(wèn)的數(shù)據(jù)的坐標(biāo)悼沈。
而布爾數(shù)組則有所不同,它明確指示了哪些數(shù)組元素是想要的姐扮,哪些數(shù)組元素是不想要的絮供。
一種最自然的布爾數(shù)組的想法是,用于索引的布爾數(shù)組形狀和數(shù)據(jù)數(shù)組的形狀完全一致:
a = np.arange(12).reshape(3,4)
b = a > 4
b
array([[False, False, False, False],
[False, True, True, True],
[ True, True, True, True]])
a[b]
array([ 5, 6, 7, 8, 9, 10, 11])
這種性質(zhì)非常適合賦值:
a[b] = 0
a
array([[0, 1, 2, 3],
[4, 0, 0, 0],
[0, 0, 0, 0]])
第二種使用布爾索引的方式跟整形索引更加相似茶敏。
對(duì)于數(shù)組的每一個(gè)維度壤靶,使用一個(gè)一維數(shù)組來(lái)指定所需要的數(shù)據(jù)切片:
a = np.arange(12).reshape(3,4)
a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
b1 = np.array([False,True,True]) # 第一維
b2 = np.array([True,False,True,False]) # 第二維
a[b1,:] # 選擇行
array([[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
a[:,b2] # 選擇列
array([[ 0, 2],
[ 4, 6],
[ 8, 10]])
a[b1,b2] # 選定坐標(biāo),(1,0)惊搏,(2,2)這個(gè)實(shí)際上很奇怪贮乳,一般不會(huì)用
array([ 4, 10])
ix_()函數(shù)
ix_函數(shù)可以用于使用不同的向量來(lái)生成它們之間的笛卡爾積忧换。
比如我們現(xiàn)在有a,b,c三個(gè)長(zhǎng)度不一致的向量,我們想計(jì)算所有可能的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)
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
上面用了廣播機(jī)制向拆,技巧比較高
基本的線性代數(shù)
簡(jiǎn)單的數(shù)組操作
如有必要亚茬,請(qǐng)閱讀linalg的文檔以了解更多
a = np.array([[1.0,2.0],[3.0,4.0]])
print(a)
[[1. 2.]
[3. 4.]]
a.transpose() #轉(zhuǎn)置
array([[1., 3.],
[2., 4.]])
np.linalg.inv(a) #求逆
array([[-2. , 1. ],
[ 1.5, -0.5]])
u = np.eye(2) # 單位陣
u
array([[1., 0.],
[0., 1.]])
j = np.array([[0.0,-1.0],[1.0,0.0]])
np.dot(j,j) # 矩陣乘法
array([[-1., 0.],
[ 0., -1.]])
np.trace(u) # 矩陣的跡
2.0
解線性方程:
x_1 + 2x_2 = 5
3x_1 + 4x_2 = 7
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. -0.70710678j, 0. +0.70710678j]]))
技巧與小貼士
這里給一些短小但有用的貼士。
“自動(dòng)”變形
在改變一個(gè)數(shù)組的形狀的時(shí)候浓恳,我們可以省略一個(gè)維度的值刹缝,它會(huì)被自動(dòng)計(jì)算出來(lái):
a = np.arange(30)
a.shape = 2,-1,3 # 這里的-1指的是在滿足其他維度的情況下,這個(gè)維度自動(dòng)幫我算出來(lái)
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]]])
向量堆疊
我們?nèi)绾螌⒌乳L(zhǎng)的行向量組建成一個(gè)二維的數(shù)組呢奖蔓?
我們可以使用column_stack,dstack,hstack,vstack赞草。實(shí)際上只要記住stack這個(gè)詞就夠了。
x = np.arange(0,10,2)
y = np.arange(5)
m = np.vstack([x,y])
m
array([[0, 2, 4, 6, 8],
[0, 1, 2, 3, 4]])
xy = np.hstack([x,y])
xy
array([0, 2, 4, 6, 8, 0, 1, 2, 3, 4])
超過(guò)二維時(shí)吆鹤,函數(shù)的邏輯有些怪厨疙,不需要關(guān)心,不怎么用
直方圖
NumPy的histogram函數(shù)作用在一個(gè)數(shù)組上的時(shí)候疑务,會(huì)返回一堆向量:
- 每個(gè)桶的技術(shù)
- 同的劃分
請(qǐng)注意沾凄,matplotlib也有一個(gè)函數(shù)(hist)可以創(chuàng)建直方圖,它和NumPy的不一樣知允。
二者主要的區(qū)別在于撒蟀,matplotlib的hist會(huì)自動(dòng)繪制出直方圖,而numpy.histogram僅僅生成數(shù)據(jù)温鸽。
import matplotlib.pyplot as plt
mu,sigma = 2,0.5
v = np.random.normal(mu,sigma,10000) # 使用正態(tài)分布隨機(jī)生成一萬(wàn)個(gè)點(diǎn)
# matplotlib版本
plt.hist(v,bins=50,density=1) # 數(shù)據(jù)都規(guī)范化了
plt.show()
# NumPy版本
# 先生成histogram數(shù)據(jù)保屯,然后再繪制
(n,bins)= np.histogram(v,bins=50,density=True) # bins是區(qū)間的上下界
plt.plot(.5*(bins[1:]+bins[:-1]),n)
plt.show()
進(jìn)一步學(xué)習(xí)
如果完全消化了本課的內(nèi)容,進(jìn)一步學(xué)習(xí)建議:
- 閱讀《利用Python進(jìn)行數(shù)據(jù)分析》
- 閱讀NumPy手冊(cè)