Python的收集整理:Numpy

Numpy模塊

導(dǎo)入

import numpy as np

創(chuàng)建

通過(guò)Python列表

直接傳入1層,2層嵌套列表,變?yōu)?維,2維數(shù)組
a = np.array([1,2,3,4])
b = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])

通常,我們無(wú)法事先知道數(shù)組元素的具體值,但是數(shù)組大小是已知的。 這時(shí)可以用下面幾種方法生成數(shù)組。
zeros 函數(shù)生成元素全部為0的數(shù)組。
ones函數(shù)生成元素全部為1的數(shù)組。
empty函數(shù)生成元素沒(méi)有賦值的數(shù)組,這時(shí)元素值由內(nèi)存中原來(lái)的內(nèi)容決定。 默認(rèn)生成的數(shù)組元素類(lèi)型為float64.

>>> np.zeros( (3,4) )  
array([[0.,  0.,  0.,  0.],  
       [0.,  0.,  0.,  0.],  
       [0.,  0.,  0.,  0.]])  
>>> np.ones( (2,3,4), dtype=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) )  
array([[  3.73603959e-262,   6.02658058e-154,   6.55490914e-260],  
       [  5.30498948e-313,   3.14673309e-307,   1.00000000e+000]])  

屬性

ndarray.ndim:數(shù)組的維數(shù),也稱(chēng)為rank
ndarray.shape:數(shù)組各維的大小tuple 類(lèi)型,對(duì)一個(gè)n 行m 列的矩陣來(lái)說(shuō), shape 為 (n,m)。
ndarray.size:元素的總數(shù)。 
ndarray.dtype:每個(gè)元素的類(lèi)型,可以是 numpy.int32, numpy.int16, and numpy.float64 等。 
ndarray.itemsize:每個(gè)元素占用的字節(jié)數(shù)。
ndarray.data:指向數(shù)據(jù)內(nèi)存。

長(zhǎng)度

訪問(wèn)shape屬性得到數(shù)組長(zhǎng)度
a.shape #(4,) #一維
b.shape #(4,3)  #二維

修改shape屬性修改數(shù)組長(zhǎng)度
b.shape = 3,4
#b = array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])
#當(dāng)某個(gè)軸的元素為-1時(shí),長(zhǎng)度將自動(dòng)計(jì)算
b.shape = 2,-1  #將計(jì)算為2x6
#b = array([[1,2],[3,4],[5,6],[7,8],[9,10],[11,12]])
#注意修改時(shí)元素總個(gè)數(shù)不能變 3x4 = 4x3 = 2x6

使用reshape創(chuàng)建新數(shù)組,原數(shù)組的shape不變
c = a.reshape((2,2))
#c = array([[1,2],[3,4]])
#a = array([1,2,3,4])
#注意,a和c指向相同地址空間,修改其中任意一個(gè),另一個(gè)也會(huì)改變
a[1] = 100 
#a = array([1,100,3,4])
#c = array([[1,100],[3,4]])

類(lèi)型

dtype 屬性可以獲得數(shù)組元素的類(lèi)型,該屬性也可以在創(chuàng)建數(shù)組時(shí)指定
d = np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]], dtype=np.float)
#d = array([[1., 2., 3., 4.],[4., 5., 6., 7.],[7., 8., 9., 10.]])

其他創(chuàng)建方法

arange()方法

指定開(kāi)始值,終值和步長(zhǎng)創(chuàng)建1維數(shù)組(注意不包括終值)
e = np.arange(0,1,0.1)  #開(kāi)始為0,結(jié)束為1(不包括1),每0.1算一個(gè)
#e = array([0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])

linspace()方法

指定開(kāi)始值,終值和元素個(gè)數(shù)創(chuàng)建1維數(shù)組,等差(可以用endpoint指定包不包括終值,默認(rèn)包括)
f = np.linspace(0, 1, 12)
#f = array([ 0.      , 0.09090909, 0.18181818, 0.27272727, 0.36363636,
           0.45454545, 0.54545455, 0.63636364, 0.72727273, 0.81818182,
           0.90909091, 1.        ])

logspace()方法

logspace函數(shù)和linspace類(lèi)似,不過(guò)它創(chuàng)建等比數(shù)列,下面的例子產(chǎn)生1(10的0次)到100(10的2次)、有20個(gè)元素的等比數(shù)列
g = np.logspace(0, 2, 20)
#g = array([1.         ,    1.27427499,    1.62377674,    2.06913808,
            2.6366509  ,    3.35981829,    4.2813324 ,    5.45559478,
            6.95192796 ,    8.8586679 ,   11.28837892,   14.38449888,
            18.32980711,   23.35721469,   29.76351442,   37.92690191,
            48.32930239,   61.58482111,   78.47599704,  100.        ])

字節(jié)方法

frombuffer(), fromstring(), fromfile()等函數(shù)可以從字節(jié)序列創(chuàng)建數(shù)組,以fromstring為例:

s = "abcdefgh"
Python的字符串實(shí)際上是字節(jié)序列,每個(gè)字符占一個(gè)字節(jié),因此如果從字符串s創(chuàng)建一個(gè)8bit的整數(shù)數(shù)組的話,所得到的數(shù)組正好就是字符串中每個(gè)字符的ASCII編碼:
h = np.fromstring(s, dtype=np.int8)
#h = array([ 97,  98,  99, 100, 101, 102, 103, 104], dtype=int8)

如果從字符串s創(chuàng)建16bit的整數(shù)數(shù)組,那么兩個(gè)相鄰的字節(jié)就表示一個(gè)整數(shù),把字節(jié)98和字節(jié)97當(dāng)作一個(gè)16位的整數(shù),它的值就是98*256+97 = 25185??梢钥闯鰞?nèi)存中是以little endian(低位字節(jié)在前)方式保存數(shù)據(jù)的。
j = np.fromstring(s, dtype=np.int16)
#j= array([25185, 25699, 26213, 26727], dtype=int16)

如果把整個(gè)字符串轉(zhuǎn)換為一個(gè)64位的雙精度浮點(diǎn)數(shù)數(shù)組,那么它的值是:
k = np.fromstring(s, dtype=np.float)
#k = array([  8.54088322e+194])
顯然這個(gè)例子沒(méi)有什么意義,但是可以想象如果我們用C語(yǔ)言的二進(jìn)制方式寫(xiě)了一組double類(lèi)型的數(shù)值到某個(gè)文件中,那們可以從此文件讀取相應(yīng)的數(shù)據(jù),并通過(guò)fromstring函數(shù)將其轉(zhuǎn)換為float64類(lèi)型的數(shù)組。

函數(shù)方法

我們可以寫(xiě)一個(gè)Python的函數(shù),它將數(shù)組下標(biāo)轉(zhuǎn)換為數(shù)組中對(duì)應(yīng)的值,然后使用此函數(shù)創(chuàng)建數(shù)組(傳入下標(biāo),計(jì)算,傳出元素值):
fromfunction函數(shù)的第一個(gè)參數(shù)為計(jì)算函數(shù),第二個(gè)參數(shù)為數(shù)組的大小(shape),因?yàn)樗С侄嗑S數(shù)組,所以第二個(gè)參數(shù)必須是一個(gè)序列,本例中用(10,)創(chuàng)建一個(gè)10元素的一維數(shù)組。

def func(i):
   return i%4+1
l = np.fromfunction(func, (10,))  #下標(biāo)0~9
#l = array([ 1.,  2.,  3.,  4.,  1.,  2.,  3.,  4.,  1.,  2.])

下面的例子創(chuàng)建一個(gè)二維數(shù)組表示九九乘法表,輸出的數(shù)組a中的每個(gè)元素a[i, j]都等于func2(i, j):

def func2(i, j):
    return (i+1) * (j+1)
m = np.fromfunction(func2, (9,9))
#m = array([[  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.],
            [  2.,   4.,   6.,   8.,  10.,  12.,  14.,  16.,  18.],
            [  3.,   6.,   9.,  12.,  15.,  18.,  21.,  24.,  27.],
            [  4.,   8.,  12.,  16.,  20.,  24.,  28.,  32.,  36.],
            [  5.,  10.,  15.,  20.,  25.,  30.,  35.,  40.,  45.],
            [  6.,  12.,  18.,  24.,  30.,  36.,  42.,  48.,  54.],
            [  7.,  14.,  21.,  28.,  35.,  42.,  49.,  56.,  63.],
            [  8.,  16.,  24.,  32.,  40.,  48.,  56.,  64.,  72.],
            [  9.,  18.,  27.,  36.,  45.,  54.,  63.,  72.,  81.]])

存?。ㄒ痪S)

切片

數(shù)組元素存取和python切片操作一致
注意:通過(guò)下標(biāo)范圍獲取的新的數(shù)組(b = a[3:7])是原始數(shù)組的一個(gè)視圖。它與原始數(shù)組共享同一塊數(shù)據(jù)空間(一個(gè)改變,都改變)

其他存取方法

使用整數(shù)序列

使用整數(shù)序列(列表或者數(shù)組)中的每個(gè)元素作為下標(biāo)。這樣獲得的新數(shù)組不和原始數(shù)組共享數(shù)據(jù)空間。

x = np.arange(10,1,-1)
#x = array([10,  9,  8,  7,  6,  5,  4,  3,  2])

x[[3, 3, 1, 8]] # 獲取x中的下標(biāo)為3, 3, 1, 8的4個(gè)元素,組成一個(gè)新的數(shù)組
#array([7, 7, 9, 2])

b = x[np.array([3,3,-3,8])]  #下標(biāo)可以是負(fù)數(shù)
b[2] = 100
#b = array([7, 7, 100, 2])
#x = array([10,  9,  8,  7,  6,  5,  4,  3,  2]) x不變
x[[3,5,1]] = -1, -2, -3 # 整數(shù)序列下標(biāo)也可以用來(lái)修改元素的值
#x = array([10, -3,  8, -1,  6, -2,  4,  3,  2])

使用布爾數(shù)組

當(dāng)使用布爾數(shù)組b作為下標(biāo)存取數(shù)組x中的元素時(shí),將收集數(shù)組x中所有在數(shù)組b中對(duì)應(yīng)下標(biāo)為T(mén)rue的元素。使用布爾數(shù)組作為下標(biāo)獲得的數(shù)組不和原始數(shù)組共享數(shù)據(jù)空間,注意只對(duì)應(yīng)于布爾數(shù)組,不能使用布爾列表。(取True位置的元素)

x = np.arange(5,0,-1)
#x = array([5, 4, 3, 2, 1])

x[np.array([True, False, True, False, False])]
# 布爾數(shù)組中下標(biāo)為0,2的元素為T(mén)rue,因此獲取x中下標(biāo)為0,2的元素
#array([5, 3])

x[[True, False, True, False, False]]
# 如果是布爾列表,則把True當(dāng)作1, False當(dāng)作0,按照整數(shù)序列方式獲取x中的元素
#array([4, 5, 4, 5, 5])

x[np.array([True, False, True, True])]
# 布爾數(shù)組的長(zhǎng)度不夠時(shí),不夠的部分都當(dāng)作False
#array([5, 3, 2])

x[np.array([True, False, True, True])] = -1, -2, -3
# 布爾數(shù)組下標(biāo)也可以用來(lái)修改元素
#x = array([-1,  4, -2, -3,  1])

布爾數(shù)組一般不是手工產(chǎn)生,而是使用布爾運(yùn)算的ufunc函數(shù)產(chǎn)生。

x = np.random.rand(10) # 產(chǎn)生一個(gè)長(zhǎng)度為10,元素值為0-1的隨機(jī)數(shù)的數(shù)組
#x = array([ 0.72223939,  0.921226  ,  0.7770805 ,  0.2055047 ,  0.17567449,
             0.95799412,  0.12015178,  0.7627083 ,  0.43260184,  0.91379859])

x>0.5
# 數(shù)組x中的每個(gè)元素和0.5進(jìn)行大小比較,得到一個(gè)布爾數(shù)組,True表示x中對(duì)應(yīng)的值大于0.5
#array([ True,  True,  True, False, False,  True, False,  True, False,  True], dtype=bool)

x[x>0.5]
# 使用x>0.5返回的布爾數(shù)組收集x中的元素,因此得到的結(jié)果是x中所有大于0.5的元素的數(shù)組
#array([ 0.72223939, 0.921226, 0.7770805, 0.95799412, 0.7627083, 0.91379859])

二維數(shù)組

注意:axis第0軸為縱y軸,第1軸為橫x軸

多維數(shù)組訪問(wèn)

與一維類(lèi)似,多維用,分割選取行,列,注意不要用'()'

a為6x6數(shù)組
a[0,3:5] #第0行,第3,4列的交叉元素 
a[4:,4:] #第4,5行,第4,5列的交叉元素
a[:,2] #全部行,第2列的交叉元素
a[2::2,::2] #第2,4行,第0,2,4列的交叉元素

同樣也可用數(shù)組和布爾方法進(jìn)行存取

a[(0,1,2,3,4),(1,2,3,4,5)]  #(0,1),(1,2),(2,3),(3,4),(4,5)這五個(gè)位置的元素
a[3:,[0,2,5]] #第3,4,5行,第0,2,5列的交叉元素
mask = np.array([1,0,1,0,0,1],dtype=np.bool)
a[mask,2] #第0,2,5行,第2列的交叉元素 

多維數(shù)組迭代

多維數(shù)組迭代時(shí)以第一個(gè)維度為迭代單位:

a = array([[0 ,1 ,2 ,3] , 
           [10 ,11 ,12 ,13] , 
           [20, 21 ,22 ,23] , 
           [30, 31, 32 ,33] , 
           [40, 41 ,42 ,43] ])

>>> 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]  

如果我們想忽略維度,將所有元素迭代出來(lái)也是可以的
>>> 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 

ufunc運(yùn)算

能對(duì)數(shù)組每個(gè)元素都進(jìn)行操作

x = np.linspace(0, 2*np.pi, 10)
# 對(duì)數(shù)組x中的每個(gè)元素進(jìn)行正弦計(jì)算,返回一個(gè)同樣大小的新數(shù)組
y = np.sin(x)
#y = array([0.00000000e+00,   6.42787610e-01,   9.84807753e-01,
            8.66025404e-01,   3.42020143e-01,  -3.42020143e-01,
           -8.66025404e-01,  -9.84807753e-01,  -6.42787610e-01,
           -2.44921271e-16])

計(jì)算之后x中的值并沒(méi)有改變,而是新創(chuàng)建了一個(gè)數(shù)組保存結(jié)果。如果我們希望將sin函數(shù)所計(jì)算的結(jié)果直接覆蓋到數(shù)組x上去的話,可以將要被覆蓋的數(shù)組作為第二個(gè)參數(shù)傳遞給ufunc函數(shù)。

t = np.sin(x,x)
#x = array([0.00000000e+00,   6.42787610e-01,   9.84807753e-01,
            8.66025404e-01,   3.42020143e-01,  -3.42020143e-01,
           -8.66025404e-01,  -9.84807753e-01,  -6.42787610e-01,
           -2.44921271e-16])
#id(t) == id(x)

np.sin()同時(shí)支持?jǐn)?shù)組和單個(gè)運(yùn)算
但對(duì)于數(shù)組,np.sin()的速度很快,但對(duì)單個(gè)元素,np.sin()的速度還不如Python中的math.sin()

Python中可以用符號(hào)代替計(jì)算函數(shù)

y = x1 + x2:    add(x1, x2 [, y])
y = x1 - x2:    subtract(x1, x2 [, y])
y = x1 * x2:    multiply (x1, x2 [, y])
y = x1 / x2:    divide (x1, x2 [, y]), 如果兩個(gè)數(shù)組的元素為整數(shù),那么用整數(shù)除法
y = x1 / x2:    true divide (x1, x2 [, y]), 總是返回精確的商
y = x1 // x2:   floor divide (x1, x2 [, y]), 總是對(duì)返回值取整
y = -x: negative(x [,y])
y = x1**x2: power(x1, x2 [, y])
y = x1 % x2:    remainder(x1, x2 [, y]), mod(x1, x2, [, y])

自己創(chuàng)建ufunc

假設(shè)已知橫坐標(biāo),需要計(jì)算三角波縱坐標(biāo)的數(shù)組

def triangle_wave(x, c, c0, hc):
    x = x - int(x) # 三角波的周期為1,因此只取x坐標(biāo)的小數(shù)部分進(jìn)行計(jì)算
    if x >= c: r = 0.0
    elif x < c0: r = x / c0 * hc
    else: r = (c-x) / (c-c0) * hc
    return r

顯然triangle_wave函數(shù)只能計(jì)算單個(gè)數(shù)值,不能對(duì)數(shù)組直接進(jìn)行處理。我們可以用下面的方法先使用列表包容(List comprehension),計(jì)算出一個(gè)list,然后用array函數(shù)將列表轉(zhuǎn)換為數(shù)組:

x = np.linspace(0, 2, 1000)
y = np.array([triangle_wave(t, 0.6, 0.4, 1.0) for t in x])

這種做法每次都需要使用列表包容語(yǔ)法調(diào)用函數(shù),對(duì)于多維數(shù)組是很麻煩的。我們用frompyfunc函數(shù)來(lái)解決這個(gè)問(wèn)題:

triangle_ufunc = np.frompyfunc( lambda x: triangle_wave(x, 0.6, 0.4, 1.0), 1, 1)
y2 = triangle_ufunc(x)

frompyfunc的調(diào)用格式為frompyfunc(func, nin, nout),其中func是計(jì)算單個(gè)元素的函數(shù),nin是此函數(shù)的輸入?yún)?shù)的個(gè)數(shù),nout是此函數(shù)的返回值的個(gè)數(shù)。

雖然triangle_wave函數(shù)有4個(gè)參數(shù),但是由于后三個(gè)c, c0, hc在整個(gè)計(jì)算中值都是固定的,因此所產(chǎn)生的ufunc函數(shù)其實(shí)只有一個(gè)參數(shù)。為了滿足這個(gè)條件,我們用一個(gè)lambda函數(shù)對(duì)triangle_wave的參數(shù)進(jìn)行一次包裝。這樣傳入frompyfunc的函數(shù)就只有一個(gè)參數(shù)了。這樣子做,效率并不是太高,另外還有一種方法:

def triangle_func(c, c0, hc):
    def trifunc(x):
        x = x - int(x) # 三角波的周期為1,因此只取x坐標(biāo)的小數(shù)部分進(jìn)行計(jì)算
        if x >= c: r = 0.0
        elif x < c0: r = x / c0 * hc
        else: r = (c-x) / (c-c0) * hc
        return r

    # 用trifunc函數(shù)創(chuàng)建一個(gè)ufunc函數(shù),可以直接對(duì)數(shù)組進(jìn)行計(jì)算, 不過(guò)通過(guò)此函數(shù)
    # 計(jì)算得到的是一個(gè)Object數(shù)組,需要進(jìn)行類(lèi)型轉(zhuǎn)換
    return np.frompyfunc(trifunc, 1, 1)

y2 = triangle_func(0.6, 0.4, 1.0)(x)

我們通過(guò)函數(shù)triangle_func包裝三角波的三個(gè)參數(shù),在其內(nèi)部定義一個(gè)計(jì)算三角波的函數(shù)trifunc,trifunc函數(shù)在調(diào)用時(shí)會(huì)采用triangle_func的參數(shù)進(jìn)行計(jì)算。最后triangle_func返回用frompyfunc轉(zhuǎn)換結(jié)果。

值得注意的是用frompyfunc得到的函數(shù)計(jì)算出的數(shù)組元素的類(lèi)型為object,因?yàn)閒rompyfunc函數(shù)無(wú)法保證Python函數(shù)返回的數(shù)據(jù)類(lèi)型都完全一致。因此還需要再次 y2.astype(np.float64)將其轉(zhuǎn)換為雙精度浮點(diǎn)數(shù)組

print(type(y2))
#object
y3 = y2.astype(np.float64)
print(type(y3))
#np.float64

廣播

兩個(gè)數(shù)組計(jì)算時(shí),要求這兩個(gè)數(shù)組有相同的大小(shape相同)。如果兩個(gè)數(shù)組的shape不同的話,會(huì)進(jìn)行如下的廣播(broadcasting)處理:

處理規(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í)都用此軸上的第一組值

例子

先創(chuàng)建一個(gè)二維數(shù)組a,其shape為(6,1):

a = np.arange(0, 60, 10).reshape(-1, 1)
#a = array([[ 0], [10], [20], [30], [40], [50]])
#a.shape = (6, 1)

再創(chuàng)建一維數(shù)組b,其shape為(5,):

b = np.arange(0, 5)
#b = array([0, 1, 2, 3, 4])
#b.shape = (5,)

計(jì)算a和b的和,得到一個(gè)加法表,它相當(dāng)于計(jì)算a,b中所有元素組的和,得到一個(gè)shape為(6,5)的數(shù)組:

c = a + b
#c = array([[ 0,  1,  2,  3,  4],
             [10, 11, 12, 13, 14],
             [20, 21, 22, 23, 24],
             [30, 31, 32, 33, 34],
             [40, 41, 42, 43, 44],
             [50, 51, 52, 53, 54]])
#c.shape = (6, 5)

由于a和b的shape長(zhǎng)度(也就是ndim屬性)不同,根據(jù)規(guī)則1,需要讓b的shape向a對(duì)齊(維數(shù)對(duì)齊),于是將b的shape前面加1,補(bǔ)齊為(1,5)。相當(dāng)于做了如下計(jì)算:

b.shape=1,5
#b = array([[0, 1, 2, 3, 4]])

這樣加法運(yùn)算的兩個(gè)輸入數(shù)組的shape分別為(6,1)和(1,5),根據(jù)規(guī)則2,輸出數(shù)組的各個(gè)軸的長(zhǎng)度為輸入數(shù)組各個(gè)軸上的長(zhǎng)度的最大值,可知輸出數(shù)組的shape為(6,5)。

由于b的第0軸上的長(zhǎng)度為1,而a的第0軸上的長(zhǎng)度為6,因此為了讓它們?cè)诘?軸上能夠相加,需要將b在第0軸上的長(zhǎng)度擴(kuò)展為6,這相當(dāng)于:

b = b.repeat(6,axis=0)  #復(fù)制第0軸(縱向↓)
#b = array([[0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4]])

由于a的第1軸的長(zhǎng)度為1,而b的第一軸長(zhǎng)度為5,因此為了讓它們?cè)诘?軸上能夠相加,需要將a在第1軸上的長(zhǎng)度擴(kuò)展為5,這相當(dāng)于:

a = a.repeat(5, axis=1)  #復(fù)制第1軸(橫軸→)
#a = array([[ 0,  0,  0,  0,  0],
            [10, 10, 10, 10, 10],
            [20, 20, 20, 20, 20],
            [30, 30, 30, 30, 30],
            [40, 40, 40, 40, 40],
            [50, 50, 50, 50, 50]])

經(jīng)過(guò)上述處理之后,a和b就可以按對(duì)應(yīng)元素進(jìn)行相加運(yùn)算了。

ogrid對(duì)象

numpy提供了一個(gè)快速產(chǎn)生一對(duì)數(shù)組的方法: ogrid對(duì)象:

x,y = np.ogrid[0:5,0:5]
#x = array([[0],
            [1],
            [2],
            [3],
            [4]])
#y = array([[0, 1, 2, 3, 4]])

ogrid是一個(gè)很有趣的對(duì)象,它像一個(gè)多維數(shù)組一樣,用切片組元作為下標(biāo)進(jìn)行存取,返回的是一組可以用來(lái)廣播計(jì)算的數(shù)組。其切片下標(biāo)有兩種形式:

1.開(kāi)始值:結(jié)束值:步長(zhǎng),和np.arange(開(kāi)始值, 結(jié)束值, 步長(zhǎng))類(lèi)似

2.開(kāi)始值:結(jié)束值:長(zhǎng)度j,當(dāng)?shù)谌齻€(gè)參數(shù)為虛數(shù)時(shí),它表示返回的數(shù)組的長(zhǎng)度,和np.linspace(開(kāi)始值, 結(jié)束值, 長(zhǎng)度)類(lèi)似:

x, y = np.ogrid[0:1:4j, 0:1:3j]
#x = array([[ 0.        ],
            [ 0.33333333],
            [ 0.66666667],
            [ 1.        ]])
#y = array([[ 0. ,  0.5,  1. ]])

ufuns方法

reduce方法

reduce 方法沿著axis軸對(duì)array進(jìn)行操作,相當(dāng)于將<op>運(yùn)算符插入到沿axis軸的所有子數(shù)組或者元素當(dāng)中。

一維
>>> np.add.reduce([1,2,3])  # 1 + 2 + 3
6

二維
>>> np.add.reduce([[1,2,3],[4,5,6]], axis=0) # 1+4, 2+5, 3+6
array([5, 7, 9])     
>>> np.add.reduce([[1,2,3],[4,5,6]], axis=1) # 1,4 + 2,5 + 3,6
array([6, 15])       

accumulate 方法

和reduce方法類(lèi)似,只是它返回的數(shù)組和輸入的數(shù)組的shape相同,保存所有的中間計(jì)算結(jié)果:

一維
>>> np.add.accumulate([1,2,3])  # 1 + 2 + 3
array([1, 3, 6])

二維
>>> np.add.accumulate([[1,2,3],[4,5,6]], axis=0) # 1+4, 2+5, 3+6
array([[ 1,  3,  6],
       [ 5,  7, 9]])      
>>> np.add.accumulate([[1,2,3],[4,5,6]], axis=1) # 1,4 + 2,5 + 3,6
array([[ 1,  3,  6],
       [ 4,  9, 15]])      

reduceat 方法

reduceat 方法通過(guò)indices參數(shù)指定一系列reduce的起始和終了位置
對(duì)于indices中的每個(gè)元素都會(huì)調(diào)用reduce函數(shù)計(jì)算出一個(gè)值來(lái),因此最終計(jì)算結(jié)果的長(zhǎng)度和indices的長(zhǎng)度相同。結(jié)果result數(shù)組中除最后一個(gè)元素之外,都按照如下計(jì)算得出:

最后一個(gè)元素前面的元素
if indices[i] < indices[i+1]:
    result[i] = np.reduce(a[indices[i]:indices[i+1]])
else:
    result[i] = a[indices[i]]

最后一個(gè)元素如下計(jì)算:
np.reduce(a[indices[-1]:])

例子

>>> a = np.array([1,2,3,4])
>>> result = np.add.reduceat(a,indices=[0,1,0,2,0,3,0])
>>> result
array([ 1,  2,  3,  3,  6,  4, 10]

結(jié)果的每個(gè)元素如下計(jì)算而得:
1 : a[0] = 1    result[0] = np.add.reduce(a[0:1]) = a[0]
2 : a[1] = 2     result[0] = a[1]
3 : a[0] + a[1] = 1 + 2   result[2] = np.add.reduce(a[0:2]) = a[0] + a[1]
3 : a[2] = 3     result[0] = a[2]
6 : a[0] + a[1] + a[2] =  1 + 2 + 3 = 6    result[4] = np.add.reduce(a[0:3]) = a[0] + a[1] + a[2]
4 : a[3] = 4     result[0] = a[3]
10: a[0] + a[1] + a[2] + a[4] = 1+2+3+4 = 10    result[0] = np.add.reduce(a[0:]) = a[0] + a[1] + a[2] + a[4]

outer 方法

outer 方法,<op>.outer(a,b)方法的計(jì)算等同于如下程序:
例子

>>> np.multiply.outer([1,2,3,4,5],[2,3,4])
array([[ 2,  3,  4],
       [ 4,  6,  8],
       [ 6,  9, 12],
       [ 8, 12, 16],
       [10, 15, 20]])

outer方法相當(dāng)于對(duì)a,b進(jìn)行如下操作

>>> a.shape += (1,)*b.ndim  
#a.shape = (5,) b.ndim=1(b的維數(shù)) (1,)*1=(1,) (5,)+(1,) = (5,1)
#進(jìn)行完這步后a = array([[1],
                      [2],
                      [3],
                      [4],
                      [5]])
>>> <op>(a,b)  
#a*b
>>> a = a.squeeze()
#squeeze的功能是剔除數(shù)組a中長(zhǎng)度為1的軸。

如果將這兩個(gè)數(shù)組按照等同程序一步一步的計(jì)算的話,就會(huì)發(fā)現(xiàn)乘法表最終是通過(guò)廣播的方式計(jì)算出來(lái)的。

文件讀取

文件存取的格式分為兩類(lèi):二進(jìn)制和文本。而二進(jìn)制格式的文件又分為NumPy專(zhuān)用的格式化二進(jìn)制類(lèi)型和無(wú)格式類(lèi)型。

tofile,fromfile方法

使用數(shù)組的方法函數(shù)tofile可以方便地將數(shù)組中數(shù)據(jù)以二進(jìn)制的格式寫(xiě)進(jìn)文件。tofile輸出的數(shù)據(jù)沒(méi)有格式,因此用numpy.fromfile讀回來(lái)的時(shí)候需要自己格式化數(shù)據(jù)(設(shè)定shape和dtype),并且tofile函數(shù)不管數(shù)組的排列順序是C語(yǔ)言格式的還是Fortran語(yǔ)言格式的,統(tǒng)一使用C語(yǔ)言格式輸出。:

>>> a = np.arange(0,12)
>>> a.shape = 3,4
>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> a.tofile("a.bin")
>>> b = np.fromfile("a.bin", dtype=np.float) # 按照f(shuō)loat類(lèi)型讀入數(shù)據(jù)
>>> b # 讀入的數(shù)據(jù)是錯(cuò)誤的
array([  2.12199579e-314,   6.36598737e-314,   1.06099790e-313,
         1.48539705e-313,   1.90979621e-313,   2.33419537e-313])
>>> a.dtype # 查看a的dtype
dtype('int32')
>>> b = np.fromfile("a.bin", dtype=np.int32) # 按照int32類(lèi)型讀入數(shù)據(jù)
>>> b # 數(shù)據(jù)是一維的
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
>>> b.shape = 3, 4 # 按照a的shape修改b的shape
>>> b # 這次終于正確了
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

此外如果fromfile和tofile函數(shù)調(diào)用時(shí)指定了sep關(guān)鍵字參數(shù)的話,數(shù)組將以文本格式輸入輸出。

load,save方法

numpy.load和numpy.save函數(shù)以NumPy專(zhuān)用的二進(jìn)制類(lèi)型保存數(shù)據(jù),會(huì)自動(dòng)處理dtype和shape等信息,但是numpy.save輸出的文件很難和其它語(yǔ)言編寫(xiě)的程序讀入:

>>> np.save("a.npy", a)
>>> c = np.load( "a.npy" )
>>> c
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

如果你想將多個(gè)數(shù)組保存到一個(gè)文件中的話,可以使用numpy.savez函數(shù)。savez函數(shù)的第一個(gè)參數(shù)是文件名,其后的參數(shù)都是需要保存的數(shù)組,也可以使用關(guān)鍵字參數(shù)為數(shù)組起一個(gè)名字,非關(guān)鍵字參數(shù)傳遞的數(shù)組會(huì)自動(dòng)起名為arr_0, arr_1, ...。savez函數(shù)輸出的是一個(gè)壓縮文件(擴(kuò)展名為npz),其中每個(gè)文件都是一個(gè)save函數(shù)保存的npy文件,文件名對(duì)應(yīng)于數(shù)組名。load函數(shù)自動(dòng)識(shí)別npz文件,并且返回一個(gè)類(lèi)似于字典的對(duì)象,可以通過(guò)數(shù)組名作為關(guān)鍵字獲取數(shù)組的內(nèi)容:

>>> a = np.array([[1,2,3],[4,5,6]])
>>> b = np.arange(0, 1.0, 0.1)
>>> c = np.sin(b)
>>> np.savez("result.npz", a, b, sin_array = c)
>>> r = np.load("result.npz")
>>> r["arr_0"] # 數(shù)組a
array([[1, 2, 3],
       [4, 5, 6]])
>>> r["arr_1"] # 數(shù)組b
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])
>>> r["sin_array"] # 數(shù)組c
array([ 0.        ,  0.09983342,  0.19866933,  0.29552021,  0.38941834,
        0.47942554,  0.56464247,  0.64421769,  0.71735609,  0.78332691])
如果你用解壓軟件打開(kāi)result.npz文件的話,會(huì)發(fā)現(xiàn)其中有三個(gè)文件:arr_0.npy, arr_1.npy, sin_array.npy,其中分別保存著數(shù)組a, b, c的內(nèi)容。

使用numpy.savetxt和numpy.loadtxt可以讀寫(xiě)1維和2維的數(shù)組:

>>> a = np.arange(0,12,0.5).reshape(4,-1)
>>> np.savetxt("a.txt", a) # 缺省按照'%.18e'格式保存數(shù)據(jù),以空格分隔
>>> np.loadtxt("a.txt")
array([[  0. ,   0.5,   1. ,   1.5,   2. ,   2.5],
       [  3. ,   3.5,   4. ,   4.5,   5. ,   5.5],
       [  6. ,   6.5,   7. ,   7.5,   8. ,   8.5],
       [  9. ,   9.5,  10. ,  10.5,  11. ,  11.5]])
>>> np.savetxt("a.txt", a, fmt="%d", delimiter=",") #改為保存為整數(shù),以逗號(hào)分隔
>>> np.loadtxt("a.txt",delimiter=",") # 讀入的時(shí)候也需要指定逗號(hào)分隔
array([[  0.,   0.,   1.,   1.,   2.,   2.],
       [  3.,   3.,   4.,   4.,   5.,   5.],
       [  6.,   6.,   7.,   7.,   8.,   8.],
       [  9.,   9.,  10.,  10.,  11.,  11.]])

文件名和文件對(duì)象

本節(jié)介紹所舉的例子都是傳遞的文件名,也可以傳遞已經(jīng)打開(kāi)的文件對(duì)象,例如對(duì)于load和save函數(shù)來(lái)說(shuō),如果使用文件對(duì)象的話,可以將多個(gè)數(shù)組儲(chǔ)存到一個(gè)npy文件中:

>>> a = np.arange(8)
>>> b = np.add.accumulate(a)
>>> c = a + b
>>> f = open("result.npy", "wb")
>>> np.save(f, a) # 順序?qū),b,c保存進(jìn)文件對(duì)象f
>>> np.save(f, b)
>>> np.save(f, c)
>>> f.close()
>>> f = open("result.npy", "rb")
>>> np.load(f) # 順序從文件對(duì)象f中讀取內(nèi)容
array([0, 1, 2, 3, 4, 5, 6, 7])
>>> np.load(f)
array([ 0,  1,  3,  6, 10, 15, 21, 28])
>>> np.load(f)
array([ 0,  2,  5,  9, 14, 20, 27, 35])
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容