Numpy模塊
導入
import numpy as np
創建
通過Python列表
直接傳入1層,2層嵌套列表,變為1維,2維數組
a = np.array([1,2,3,4])
b = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
通常,我們無法事先知道數組元素的具體值,但是數組大小是已知的。 這時可以用下面幾種方法生成數組。
zeros 函數生成元素全部為0的數組。
ones函數生成元素全部為1的數組。
empty函數生成元素沒有賦值的數組,這時元素值由內存中原來的內容決定。 默認生成的數組元素類型為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:數組的維數,也稱為rank
ndarray.shape:數組各維的大小tuple 類型,對一個n 行m 列的矩陣來說, shape 為 (n,m)。
ndarray.size:元素的總數。
ndarray.dtype:每個元素的類型,可以是 numpy.int32, numpy.int16, and numpy.float64 等。
ndarray.itemsize:每個元素占用的字節數。
ndarray.data:指向數據內存。
長度
訪問shape屬性得到數組長度
a.shape #(4,) #一維
b.shape #(4,3) #二維
修改shape屬性修改數組長度
b.shape = 3,4
#b = array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])
#當某個軸的元素為-1時,長度將自動計算
b.shape = 2,-1 #將計算為2x6
#b = array([[1,2],[3,4],[5,6],[7,8],[9,10],[11,12]])
#注意修改時元素總個數不能變 3x4 = 4x3 = 2x6
使用reshape創建新數組,原數組的shape不變
c = a.reshape((2,2))
#c = array([[1,2],[3,4]])
#a = array([1,2,3,4])
#注意,a和c指向相同地址空間,修改其中任意一個,另一個也會改變
a[1] = 100
#a = array([1,100,3,4])
#c = array([[1,100],[3,4]])
類型
dtype 屬性可以獲得數組元素的類型,該屬性也可以在創建數組時指定
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.]])
其他創建方法
arange()方法
指定開始值,終值和步長創建1維數組(注意不包括終值)
e = np.arange(0,1,0.1) #開始為0,結束為1(不包括1),每0.1算一個
#e = array([0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
linspace()方法
指定開始值,終值和元素個數創建1維數組,等差(可以用endpoint指定包不包括終值,默認包括)
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函數和linspace類似,不過它創建等比數列,下面的例子產生1(10的0次)到100(10的2次)、有20個元素的等比數列
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. ])
字節方法
frombuffer(), fromstring(), fromfile()等函數可以從字節序列創建數組,以fromstring為例:
s = "abcdefgh"
Python的字符串實際上是字節序列,每個字符占一個字節,因此如果從字符串s創建一個8bit的整數數組的話,所得到的數組正好就是字符串中每個字符的ASCII編碼:
h = np.fromstring(s, dtype=np.int8)
#h = array([ 97, 98, 99, 100, 101, 102, 103, 104], dtype=int8)
如果從字符串s創建16bit的整數數組,那么兩個相鄰的字節就表示一個整數,把字節98和字節97當作一個16位的整數,它的值就是98*256+97 = 25185。可以看出內存中是以little endian(低位字節在前)方式保存數據的。
j = np.fromstring(s, dtype=np.int16)
#j= array([25185, 25699, 26213, 26727], dtype=int16)
如果把整個字符串轉換為一個64位的雙精度浮點數數組,那么它的值是:
k = np.fromstring(s, dtype=np.float)
#k = array([ 8.54088322e+194])
顯然這個例子沒有什么意義,但是可以想象如果我們用C語言的二進制方式寫了一組double類型的數值到某個文件中,那們可以從此文件讀取相應的數據,并通過fromstring函數將其轉換為float64類型的數組。
函數方法
我們可以寫一個Python的函數,它將數組下標轉換為數組中對應的值,然后使用此函數創建數組(傳入下標,計算,傳出元素值):
fromfunction函數的第一個參數為計算函數,第二個參數為數組的大小(shape),因為它支持多維數組,所以第二個參數必須是一個序列,本例中用(10,)創建一個10元素的一維數組。
def func(i):
return i%4+1
l = np.fromfunction(func, (10,)) #下標0~9
#l = array([ 1., 2., 3., 4., 1., 2., 3., 4., 1., 2.])
下面的例子創建一個二維數組表示九九乘法表,輸出的數組a中的每個元素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.]])
存取(一維)
切片
數組元素存取和python切片操作一致
注意:通過下標范圍獲取的新的數組(b = a[3:7])是原始數組的一個視圖。它與原始數組共享同一塊數據空間(一個改變,都改變)
其他存取方法
使用整數序列
使用整數序列(列表或者數組)中的每個元素作為下標。這樣獲得的新數組不和原始數組共享數據空間。
x = np.arange(10,1,-1)
#x = array([10, 9, 8, 7, 6, 5, 4, 3, 2])
x[[3, 3, 1, 8]] # 獲取x中的下標為3, 3, 1, 8的4個元素,組成一個新的數組
#array([7, 7, 9, 2])
b = x[np.array([3,3,-3,8])] #下標可以是負數
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 # 整數序列下標也可以用來修改元素的值
#x = array([10, -3, 8, -1, 6, -2, 4, 3, 2])
使用布爾數組
當使用布爾數組b作為下標存取數組x中的元素時,將收集數組x中所有在數組b中對應下標為True的元素。使用布爾數組作為下標獲得的數組不和原始數組共享數據空間,注意只對應于布爾數組,不能使用布爾列表。(取True位置的元素)
x = np.arange(5,0,-1)
#x = array([5, 4, 3, 2, 1])
x[np.array([True, False, True, False, False])]
# 布爾數組中下標為0,2的元素為True,因此獲取x中下標為0,2的元素
#array([5, 3])
x[[True, False, True, False, False]]
# 如果是布爾列表,則把True當作1, False當作0,按照整數序列方式獲取x中的元素
#array([4, 5, 4, 5, 5])
x[np.array([True, False, True, True])]
# 布爾數組的長度不夠時,不夠的部分都當作False
#array([5, 3, 2])
x[np.array([True, False, True, True])] = -1, -2, -3
# 布爾數組下標也可以用來修改元素
#x = array([-1, 4, -2, -3, 1])
布爾數組一般不是手工產生,而是使用布爾運算的ufunc函數產生。
x = np.random.rand(10) # 產生一個長度為10,元素值為0-1的隨機數的數組
#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
# 數組x中的每個元素和0.5進行大小比較,得到一個布爾數組,True表示x中對應的值大于0.5
#array([ True, True, True, False, False, True, False, True, False, True], dtype=bool)
x[x>0.5]
# 使用x>0.5返回的布爾數組收集x中的元素,因此得到的結果是x中所有大于0.5的元素的數組
#array([ 0.72223939, 0.921226, 0.7770805, 0.95799412, 0.7627083, 0.91379859])
二維數組
注意:axis第0軸為縱y軸,第1軸為橫x軸
多維數組訪問
與一維類似,多維用,分割選取行,列,注意不要用'()'
a為6x6數組
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列的交叉元素
同樣也可用數組和布爾方法進行存取
a[(0,1,2,3,4),(1,2,3,4,5)] #(0,1),(1,2),(2,3),(3,4),(4,5)這五個位置的元素
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列的交叉元素
多維數組迭代
多維數組迭代時以第一個維度為迭代單位:
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]
如果我們想忽略維度,將所有元素迭代出來也是可以的
>>> 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運算
能對數組每個元素都進行操作
x = np.linspace(0, 2*np.pi, 10)
# 對數組x中的每個元素進行正弦計算,返回一個同樣大小的新數組
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])
計算之后x中的值并沒有改變,而是新創建了一個數組保存結果。如果我們希望將sin函數所計算的結果直接覆蓋到數組x上去的話,可以將要被覆蓋的數組作為第二個參數傳遞給ufunc函數。
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()同時支持數組和單個運算
但對于數組,np.sin()的速度很快,但對單個元素,np.sin()的速度還不如Python中的math.sin()
Python中可以用符號代替計算函數
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]), 如果兩個數組的元素為整數,那么用整數除法
y = x1 / x2: true divide (x1, x2 [, y]), 總是返回精確的商
y = x1 // x2: floor divide (x1, x2 [, y]), 總是對返回值取整
y = -x: negative(x [,y])
y = x1**x2: power(x1, x2 [, y])
y = x1 % x2: remainder(x1, x2 [, y]), mod(x1, x2, [, y])
自己創建ufunc
假設已知橫坐標,需要計算三角波縱坐標的數組
def triangle_wave(x, c, c0, hc):
x = x - int(x) # 三角波的周期為1,因此只取x坐標的小數部分進行計算
if x >= c: r = 0.0
elif x < c0: r = x / c0 * hc
else: r = (c-x) / (c-c0) * hc
return r
顯然triangle_wave函數只能計算單個數值,不能對數組直接進行處理。我們可以用下面的方法先使用列表包容(List comprehension),計算出一個list,然后用array函數將列表轉換為數組:
x = np.linspace(0, 2, 1000)
y = np.array([triangle_wave(t, 0.6, 0.4, 1.0) for t in x])
這種做法每次都需要使用列表包容語法調用函數,對于多維數組是很麻煩的。我們用frompyfunc函數來解決這個問題:
triangle_ufunc = np.frompyfunc( lambda x: triangle_wave(x, 0.6, 0.4, 1.0), 1, 1)
y2 = triangle_ufunc(x)
frompyfunc的調用格式為frompyfunc(func, nin, nout),其中func是計算單個元素的函數,nin是此函數的輸入參數的個數,nout是此函數的返回值的個數。
雖然triangle_wave函數有4個參數,但是由于后三個c, c0, hc在整個計算中值都是固定的,因此所產生的ufunc函數其實只有一個參數。為了滿足這個條件,我們用一個lambda函數對triangle_wave的參數進行一次包裝。這樣傳入frompyfunc的函數就只有一個參數了。這樣子做,效率并不是太高,另外還有一種方法:
def triangle_func(c, c0, hc):
def trifunc(x):
x = x - int(x) # 三角波的周期為1,因此只取x坐標的小數部分進行計算
if x >= c: r = 0.0
elif x < c0: r = x / c0 * hc
else: r = (c-x) / (c-c0) * hc
return r
# 用trifunc函數創建一個ufunc函數,可以直接對數組進行計算, 不過通過此函數
# 計算得到的是一個Object數組,需要進行類型轉換
return np.frompyfunc(trifunc, 1, 1)
y2 = triangle_func(0.6, 0.4, 1.0)(x)
我們通過函數triangle_func包裝三角波的三個參數,在其內部定義一個計算三角波的函數trifunc,trifunc函數在調用時會采用triangle_func的參數進行計算。最后triangle_func返回用frompyfunc轉換結果。
值得注意的是用frompyfunc得到的函數計算出的數組元素的類型為object,因為frompyfunc函數無法保證Python函數返回的數據類型都完全一致。因此還需要再次 y2.astype(np.float64)將其轉換為雙精度浮點數組
print(type(y2))
#object
y3 = y2.astype(np.float64)
print(type(y3))
#np.float64
廣播
兩個數組計算時,要求這兩個數組有相同的大小(shape相同)。如果兩個數組的shape不同的話,會進行如下的廣播(broadcasting)處理:
處理規則
1.讓所有輸入數組都向其中shape最長的數組看齊,shape中不足的部分都通過在前面加1補齊
2.輸出數組的shape是輸入數組shape的各個軸上的最大值
3.如果輸入數組的某個軸和輸出數組的對應軸的長度相同或者其長度為1時,這個數組能夠用來計算,否則出錯
4.當輸入數組的某個軸的長度為1時,沿著此軸運算時都用此軸上的第一組值
例子
先創建一個二維數組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)
再創建一維數組b,其shape為(5,):
b = np.arange(0, 5)
#b = array([0, 1, 2, 3, 4])
#b.shape = (5,)
計算a和b的和,得到一個加法表,它相當于計算a,b中所有元素組的和,得到一個shape為(6,5)的數組:
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長度(也就是ndim屬性)不同,根據規則1,需要讓b的shape向a對齊(維數對齊),于是將b的shape前面加1,補齊為(1,5)。相當于做了如下計算:
b.shape=1,5
#b = array([[0, 1, 2, 3, 4]])
這樣加法運算的兩個輸入數組的shape分別為(6,1)和(1,5),根據規則2,輸出數組的各個軸的長度為輸入數組各個軸上的長度的最大值,可知輸出數組的shape為(6,5)。
由于b的第0軸上的長度為1,而a的第0軸上的長度為6,因此為了讓它們在第0軸上能夠相加,需要將b在第0軸上的長度擴展為6,這相當于:
b = b.repeat(6,axis=0) #復制第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軸的長度為1,而b的第一軸長度為5,因此為了讓它們在第1軸上能夠相加,需要將a在第1軸上的長度擴展為5,這相當于:
a = a.repeat(5, axis=1) #復制第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]])
經過上述處理之后,a和b就可以按對應元素進行相加運算了。
ogrid對象
numpy提供了一個快速產生一對數組的方法: ogrid對象:
x,y = np.ogrid[0:5,0:5]
#x = array([[0],
[1],
[2],
[3],
[4]])
#y = array([[0, 1, 2, 3, 4]])
ogrid是一個很有趣的對象,它像一個多維數組一樣,用切片組元作為下標進行存取,返回的是一組可以用來廣播計算的數組。其切片下標有兩種形式:
1.開始值:結束值:步長,和np.arange(開始值, 結束值, 步長)類似
2.開始值:結束值:長度j,當第三個參數為虛數時,它表示返回的數組的長度,和np.linspace(開始值, 結束值, 長度)類似:
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軸對array進行操作,相當于將<op>運算符插入到沿axis軸的所有子數組或者元素當中。
一維
>>> 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方法類似,只是它返回的數組和輸入的數組的shape相同,保存所有的中間計算結果:
一維
>>> 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 方法通過indices參數指定一系列reduce的起始和終了位置
對于indices中的每個元素都會調用reduce函數計算出一個值來,因此最終計算結果的長度和indices的長度相同。結果result數組中除最后一個元素之外,都按照如下計算得出:
最后一個元素前面的元素
if indices[i] < indices[i+1]:
result[i] = np.reduce(a[indices[i]:indices[i+1]])
else:
result[i] = a[indices[i]]
最后一個元素如下計算:
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]
結果的每個元素如下計算而得:
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)方法的計算等同于如下程序:
例子
>>> 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方法相當于對a,b進行如下操作
>>> a.shape += (1,)*b.ndim
#a.shape = (5,) b.ndim=1(b的維數) (1,)*1=(1,) (5,)+(1,) = (5,1)
#進行完這步后a = array([[1],
[2],
[3],
[4],
[5]])
>>> <op>(a,b)
#a*b
>>> a = a.squeeze()
#squeeze的功能是剔除數組a中長度為1的軸。
如果將這兩個數組按照等同程序一步一步的計算的話,就會發現乘法表最終是通過廣播的方式計算出來的。
文件讀取
文件存取的格式分為兩類:二進制和文本。而二進制格式的文件又分為NumPy專用的格式化二進制類型和無格式類型。
tofile,fromfile方法
使用數組的方法函數tofile可以方便地將數組中數據以二進制的格式寫進文件。tofile輸出的數據沒有格式,因此用numpy.fromfile讀回來的時候需要自己格式化數據(設定shape和dtype),并且tofile函數不管數組的排列順序是C語言格式的還是Fortran語言格式的,統一使用C語言格式輸出。:
>>> 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) # 按照float類型讀入數據
>>> b # 讀入的數據是錯誤的
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類型讀入數據
>>> b # 數據是一維的
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函數調用時指定了sep關鍵字參數的話,數組將以文本格式輸入輸出。
load,save方法
numpy.load和numpy.save函數以NumPy專用的二進制類型保存數據,會自動處理dtype和shape等信息,但是numpy.save輸出的文件很難和其它語言編寫的程序讀入:
>>> np.save("a.npy", a)
>>> c = np.load( "a.npy" )
>>> c
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
如果你想將多個數組保存到一個文件中的話,可以使用numpy.savez函數。savez函數的第一個參數是文件名,其后的參數都是需要保存的數組,也可以使用關鍵字參數為數組起一個名字,非關鍵字參數傳遞的數組會自動起名為arr_0, arr_1, ...。savez函數輸出的是一個壓縮文件(擴展名為npz),其中每個文件都是一個save函數保存的npy文件,文件名對應于數組名。load函數自動識別npz文件,并且返回一個類似于字典的對象,可以通過數組名作為關鍵字獲取數組的內容:
>>> 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"] # 數組a
array([[1, 2, 3],
[4, 5, 6]])
>>> r["arr_1"] # 數組b
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
>>> r["sin_array"] # 數組c
array([ 0. , 0.09983342, 0.19866933, 0.29552021, 0.38941834,
0.47942554, 0.56464247, 0.64421769, 0.71735609, 0.78332691])
如果你用解壓軟件打開result.npz文件的話,會發現其中有三個文件:arr_0.npy, arr_1.npy, sin_array.npy,其中分別保存著數組a, b, c的內容。
使用numpy.savetxt和numpy.loadtxt可以讀寫1維和2維的數組:
>>> a = np.arange(0,12,0.5).reshape(4,-1)
>>> np.savetxt("a.txt", a) # 缺省按照'%.18e'格式保存數據,以空格分隔
>>> 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=",") #改為保存為整數,以逗號分隔
>>> np.loadtxt("a.txt",delimiter=",") # 讀入的時候也需要指定逗號分隔
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.]])
文件名和文件對象
本節介紹所舉的例子都是傳遞的文件名,也可以傳遞已經打開的文件對象,例如對于load和save函數來說,如果使用文件對象的話,可以將多個數組儲存到一個npy文件中:
>>> a = np.arange(8)
>>> b = np.add.accumulate(a)
>>> c = a + b
>>> f = open("result.npy", "wb")
>>> np.save(f, a) # 順序將a,b,c保存進文件對象f
>>> np.save(f, b)
>>> np.save(f, c)
>>> f.close()
>>> f = open("result.npy", "rb")
>>> np.load(f) # 順序從文件對象f中讀取內容
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])