NumPy基礎(chǔ)

基礎(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í)可以指定:

  1. 目標(biāo)數(shù)組個(gè)數(shù) ——將自動(dòng)計(jì)算切分后的數(shù)組的形狀
  2. 切分列下表 —— 將在指定的列下標(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ī)則如下:

  1. 讓所有輸入數(shù)組都向其中shape最長(zhǎng)的數(shù)組看齊割去,shape中不足的部分都通過(guò)在前面加1補(bǔ)齊
  2. 輸出數(shù)組的shape是輸入數(shù)組shape的各個(gè)軸上的最大值
  3. 如果輸入數(shù)組的某個(gè)軸和輸出數(shù)組的對(duì)應(yīng)軸的長(zhǎng)度相同或者其長(zhǎng)度為1時(shí)窟却,這個(gè)數(shù)組能夠用來(lái)計(jì)算,否則出錯(cuò)
  4. 當(dāng)輸入數(shù)組的某個(gè)軸的長(zhǎng)度為1時(shí)呻逆,沿著此軸運(yùn)算時(shí)都用此軸上的第一組值


    image.png

時(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()
output_199_0.png
# 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()
output_200_0.png

進(jìn)一步學(xué)習(xí)

如果完全消化了本課的內(nèi)容,進(jìn)一步學(xué)習(xí)建議:

  1. 閱讀《利用Python進(jìn)行數(shù)據(jù)分析》
  2. 閱讀NumPy手冊(cè)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涤垫,一起剝皮案震驚了整個(gè)濱河市姑尺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蝠猬,老刑警劉巖切蟋,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異榆芦,居然都是意外死亡柄粹,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)匆绣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)驻右,“玉大人,你說(shuō)我怎么就攤上這事犬绒⊥耄” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵凯力,是天一觀的道長(zhǎng)茵瘾。 經(jīng)常有香客問(wèn)我,道長(zhǎng)咐鹤,這世上最難降的妖魔是什么拗秘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮祈惶,結(jié)果婚禮上雕旨,老公的妹妹穿的比我還像新娘。我一直安慰自己捧请,他們只是感情好凡涩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著疹蛉,像睡著了一般活箕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上可款,一...
    開(kāi)封第一講書(shū)人閱讀 49,816評(píng)論 1 290
  • 那天育韩,我揣著相機(jī)與錄音,去河邊找鬼闺鲸。 笑死筋讨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的摸恍。 我是一名探鬼主播悉罕,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼立镶!你這毒婦竟也來(lái)了壁袄?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谜慌,失蹤者是張志新(化名)和其女友劉穎然想,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體欣范,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡变泄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恼琼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妨蛹。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖晴竞,靈堂內(nèi)的尸體忽然破棺而出蛙卤,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布颤难,位于F島的核電站神年,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏行嗤。R本人自食惡果不足惜已日,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望栅屏。 院中可真熱鬧飘千,春花似錦、人聲如沸栈雳。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)哥纫。三九已至霉旗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間磺箕,已是汗流浹背奖慌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留松靡,地道東北人简僧。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像雕欺,于是被迫代替她去往敵國(guó)和親岛马。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容