最近因為看計算物理學的書時, 發現要用到 Numpy 與 Scipy 這兩個計算套件, 前兩章靠之前的初學還看得下去, 但後面就吃力了, 於是下定決心認真學習資料科學, 這也是機器學習的蹲馬步基本功, 資料科學必須練得紮實, 機器學習才能學得好. 計算物理學就等資料科學學完再來吧!
這三個套件都是免費的開源軟體, 與 MATLAB 有相似度極高之 API 介面與運算效能, 其中 Numpy 是資料科學的第一課, 是用 Python 進行高維陣列大量運算的主要工具.
Python 內建資料型態 list 屬於動態型態 (C 語言的 struct 結構), 資料結構中含有指標群指向元素物件, 但可儲存異質資料這優點的代價是, 若使用 list 儲存同質性 (固定型態) 的數值資料, 在資料存取與運算上速度太慢缺乏效率. 雖然 Python 3.3 之後內建了 array 模組, 但它只支援一維陣列且陣列運算函數不多, 故 Python 內建資料型態均不適合用來做高維度陣列運算, 參考 :
(Anaconda 的創辦人與 Scipy 開發者) 分別在 1996 年與 2005 年相繼開發了 Python 的開源數學運算擴充函式庫 Numeric 與 Numarray, 後來於 2006 年結合發展成 Numpy 套件. Numpy 採用
線性代數函式庫 API, 透過底層以 C 與 Fortran 撰寫的程式碼來提升高維向量與陣列運算效能, 其函數介面與功能與 MATLAB 非常類似, 參考 :
Numpy 套件以 ndarray 物件為核心, 由資料本身與元資料 (metadata, 陣列維度與型別 dtype 等) 資訊構成, 其資料均為同質性 (homogeneous, 即元素的資料型別都一樣), 每一個元素在記憶體中都是緊密配置在連續的記憶體空間, 因此存取元素的效率比串列高; 此外, Numpy 提供了大量以 C 語言撰寫的 ufunc 函數 (universal function) 以進行高效運算.
陣列是一種資料結構, 用來儲存具有相同資料型態的有序 (ordered) 元素, 這些元素都是配置在連續的記憶體中. 在資料科學中, 一維的數值陣列稱為向量 (vector); 二維數值陣列稱為矩陣 (matrix); 三維以上的數值陣列則稱為張量 (tensor). 如以張量作為數值序列的一般化型態名稱, 向量可稱為一維張量; 矩陣是二維張量, 三維陣列則是三維張量.
最常用的陣列是二維的矩陣, EXCEL 試算表就是矩陣結構. 對於矩陣而言, 其維度 i*j 表示 "列*行", 意即此二維陣列元素有 i 列 j 行 (注意, 台灣習慣是
), 在 Python 與 Numpy 中, 陣列的索引都是 0 起始的.
通常使用元組來表示陣列的形狀 (shape), 例如形狀為 (2, 3, 4) 的陣列表示這是一個三維陣列, 它有三個軸 (axis), 依序是軸 0, 軸 1, 與軸 3 (axis 也是 0 起始的), 長度分別是 2, 3, 4.
Numpy 提供如下常用函數可用來建立陣列, 這些函數都是 Numpy 的全域方法 (即類別方法), 呼叫這些函數都會傳回一個 numpy.ndarray 陣列物件 :
其中 array(), arange(), linspace(), 用來建立特定元素值的陣列; random 模組的 rand() 等函式用來建立不特定 (隨機) 陣列, 其餘函數則用來建立預設內容之陣列.
查詢形狀 (內部結構) 除了可用物件的 shape 屬性外, 也可以呼叫全域方法 numpy.shape(a) 函數, 只要將陣列當參數傳進去即可.
陣列的形狀可以呼叫物件方法 reshape() 並傳入一個元組來改變, 它會傳回一個新陣列參考, 但此新陣列與原陣列元素共用記憶體空間, 新陣列只是陣列外觀 (view) 不同而已, 元素仍然是儲存在原來的記憶體位址不變, 因此若更改新陣列的元素值連帶舊陣列元素也會改變.
呼叫 arange() 與 linspace() 這兩個函數都可建立以等差數列為元素的一維陣列, 兩者的差別是 linspace() 預設有包含結束值, 而 arange() 則不包含, 即產生半開數列 [b, e); 其次是傳入三個參數時 arange(b, e, s) 第三個參數 s 是步階值 (即公差), 而 linspace(b, e, n) 的第三參數 n 則是指元素個數.
函數 arrange() 是 Python 內建函數 range() 的 Numpy 陣列版, 它可傳入 1~3 個參數, 當只有一個參數時 arange(e) 會建立一維陣列, 其元素為 0~e (但不包含 e) 步階為 1 的等差數列 (即公差=1), 介面如下 :
numpy.arange([start, ]stop, [step, ]dtype=None)
例如 :
array([1.2, 2. , 2.8, 3.6, 4.4, 5.2])
array([1.2, 1.4, 1.6, 1.8, 2. , 2.2]) #不含結束值 2.4
>>> np.arange(0.1, 0.4, 0.1) # 注意 0.4 有被包含在數列中
array([0.1, 0.2, 0.3, 0.4])
>>> np.arange(0.1, 0.5, 0.1)
array([0.1, 0.2, 0.3, 0.4])
>>> np.arange(0.1, 0.6, 0.1)
array([0.1, 0.2, 0.3, 0.4, 0.5])
>>> np.arange(1, 1.3, 0.1) # 注意 1.3 有被包含在數列中
array([1. , 1.1, 1.2, 1.3])
參考 :
(2). linespace() 函數 :
函數 linspace() 也可以建立元素是等差數列的一維陣列, 它
至少需傳入兩個參數, 分別為開始值與結束值, linspace(b, e) 會建立一個 50 個元素的一維陣列, 其元素為範圍 b~e (包含 e), 步階或公差為 (e-b)/49 的等差數列, 介面如下 :
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
例如 :
>>>
np.linspace(0, 10) #建立 [0, 10] 步階為 10/49 的一維陣列
array([ 0. , 0.20408163, 0.40816327, 0.6122449 , 0.81632653,
1.02040816, 1.2244898 , 1.42857143, 1.63265306, 1.83673469,
2.04081633, 2.24489796, 2.44897959, 2.65306122, 2.85714286,
3.06122449, 3.26530612, 3.46938776, 3.67346939, 3.87755102,
4.08163265, 4.28571429, 4.48979592, 4.69387755, 4.89795918,
5.10204082, 5.30612245, 5.51020408, 5.71428571, 5.91836735,
6.12244898, 6.32653061, 6.53061224, 6.73469388, 6.93877551,
7.14285714, 7.34693878, 7.55102041, 7.75510204, 7.95918367,
8.16326531, 8.36734694, 8.57142857, 8.7755102 , 8.97959184,
9.18367347, 9.3877551 , 9.59183673, 9.79591837, 10. ])
因為預設是 50 個元素, 中間有 49 段區間, 故步階值為 (10-0)/49=0.20408163.
如果傳入三個參數 linspace(b, e, n), 則第三參數 n 為元素個數, 它會將此 b~e 區段均分成 (n-1) 段 以產生元素, 因此步階值或公差為 (e-b)/(n-1), 例如 :
>>>
np.linspace(0, 10, 9) #[0~10] 分 8 段, 步階=10/8=1.25
array([ 0. , 1.25, 2.5 , 3.75, 5. , 6.25, 7.5 , 8.75, 10. ])
>>>
np.linspace(0, 10, 10) #[0~10] 分 9 段, 步階=10/9=1.1111
array([ 0. , 1.11111111, 2.22222222, 3.33333333, 4.44444444,
5.55555556, 6.66666667, 7.77777778, 8.88888889, 10. ])
>>>
np.linspace(0, 10, 11) #[0~10] 分 10 段, 步階=10/10=1
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])
3. 建立等比數列之陣列 :
呼叫 numpy.logspace() 可建立元素為
等比數列的陣列, 其介面如下 :
numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0)[source]
可見 logspace() 至少須傳入兩個參數 (
整數, 浮點數, 或複數均可), 注意,
這兩個參數是指數, 不是數列的首項與末項, 預設基底為 10, 等比數列起始值為 base**start (即 base 的 start 次方), 結束值為 base**stop, 預設會建立 50 個元素的等比數列陣列 (含結束值). 例如 np(0, 2) 會建立 [0, 100] 之間 50 個等比數列元素之陣列 :
>>>
np.logspace(0, 2) #建立 0~100 間 50 個等比數列元素之陣列
array([ 1. ,
1.09854114, 1.20679264, 1.32571137,
1.45634848, 1.59985872, 1.75751062, 1.93069773,
2.12095089, 2.32995181, 2.55954792, 2.8117687 ,
3.0888436 , 3.39322177, 3.72759372, 4.09491506,
4.49843267, 4.94171336, 5.42867544, 5.96362332,
6.55128557, 7.19685673, 7.90604321, 8.68511374,
9.54095476, 10.48113134, 11.51395399, 12.64855217,
13.89495494, 15.26417967, 16.76832937, 18.42069969,
20.23589648, 22.22996483, 24.42053095, 26.82695795,
29.47051703, 32.37457543, 35.56480306, 39.06939937,
42.9193426 , 47.14866363, 51.79474679, 56.89866029,
62.50551925, 68.6648845 , 75.43120063, 82.86427729,
91.0298178 , 100.])
可見 np.logspace(0, 2) 的公比為 1.09854114, 依據等比數列公式 :
np.logspace(0, 2) 的首項為 10**0=1, 末項為 10**2=100, 因此公比為末項除以首項後再開 49 次方根, 即 (100/1)**(1/49)=1.09854114.
可傳入第三參數 num 指定元素個數, 例如 :
>>>
np.logspace(0, 2, 10) #建立 [1, 100] 10 個元素等比陣列
array([ 1. ,
1.66810054, 2.7825594 , 4.64158883,
7.74263683, 12.91549665, 21.5443469 , 35.93813664,
59.94842503, 100. ])
首項與末項同樣是 1 與 100, 但元素為 10 個, 故公比要開 9 次方為 (100/1)**(1/9)=1.66810054.
可傳入 base 參數指定基底, 例如 :
>>>
np.logspace(0, 2, 10, base=2) #建立基底=10 的等比陣列
array([1. ,
1.16652904, 1.36079 , 1.58740105, 1.85174942,
2.16011948, 2.5198421 , 2.93946898, 3.42897593, 4.])
因基底為 2, 因此首項為 2**0=1, 末項=2**2=4, 所以公比為 (4/1)**(1/9)=1.16652904.
4. 建立預設內容陣列 :
呼叫 zeros(), ones(), full(), zeros_like(), ones_like(), eye(), diag(), identity() 等函數可建立預設內容之陣列, 例如零陣列, 壹陣列, 與對角陣列等, 它們都可以傳入 dtype 參數指定資料型態.
(1). 零陣列 :
zeros() 必須傳入一個參數, 當傳入一個正整數時, zeros(n) 表示要建立有 n 個元素的一維零陣列 (所有元素為 0, 若 n=0 則建立空陣列); 而傳入一個元組時 zeros((i, j)) 表示要建立一個 i 列 j 行的零陣列, 例如 :
>>>
np.zeros(5) #建立 5 個元素的一維零陣列
array([0., 0., 0., 0., 0.])
>>>
np.zeros(5, dtype=int) #指定元素資料型態為 int
array([0, 0, 0, 0, 0])
>>>
np.zeros((2, 3)) #建立 i 列 j 行的零陣列
array([[0., 0., 0.],
[0., 0., 0.]])
>>>
np.zeros(0) #建立空陣列 (預設資料型態為 float64)
array([], dtype=
float64)
zeros_like() 可依據傳入之陣列結構, 建立與其維度相同之零陣列, 例如 :
>>>
a=np.array([[1, 2 , 3], [4, 5 ,6]]) #建立一個 2*3 陣列
>>>
print(a)
[[1 2 3]
[4 5 6]]
>>>
b=np.zeros_like(a) #依據 a 陣列結構建立零陣列
>>>
print(b)
[[0 0 0]
[0 0 0]]
>>>
b.dtype #zeros_like() 建立之陣列預設型態為整數
dtype('int32')
可見 zeros() 建立元素之預設型態為 float 浮點數, 而 zeros_like() 則是整數.
(2). 壹陣列 :
ones() 與 zeros() 一樣必須傳入一個參數, 當傳入一個正整數時, ones(n) 表示要建立有 n 個元素的一維壹陣列 (所有元素為 1, 若 n=0 建立空陣列); 而傳入一個元組時 ones((i, j)) 表示要建立一個 i 列 j 行的壹陣列, 例如 :
>>>
np.ones(5) #建立 5 個元素的一維壹陣列
array([1., 1., 1., 1., 1.])
>>>
np.ones(5, dtype=int) #指定元素資料型態為 int
array([1, 1, 1, 1, 1])
>>>
np.ones((2, 3)) #建立 i 列 j 行的壹陣列
array([[1., 1., 1.],
[1., 1., 1.]])
>>>
np.ones(0) #建立空陣列
array([], dtype=float64)
ones_like() 可依據傳入之陣列結構, 建立與其維度相同之壹陣列, 例如 :
>>>
a=np.array([[1, 2 , 3], [4, 5 ,6]]) #建立一個 2*3 陣列
>>>
print(a)
[[1 2 3]
[4 5 6]]
>>>
b=np.ones_like(a) #依據 a 陣列結構建立壹陣列
>>>
print(b)
[[1 1 1]
[1 1 1]]
>>>
b.dtype #ones_like() 建立之陣列預設型態為整數
dtype('int32')
(4). 填滿陣列 :
呼叫 numpy.full() 可建立元素全為指定值的填滿陣列, 其介面為 :
numpy.full(shape, fill_value, dtype=None, order='C')
第一個參數為陣列外形, 可傳入一個正整數, 元組或串列; 第二個參數是要填入的元素值. 當第一參數是正整數時, full(n, k) 會建立一個具有 n 個元素值為 k 的一維陣列; 當第一參數是元組或串列時, full(shape, k) 會依據外形 shape 建立元素值為 k 的高維陣列, 例如 :
>>>
np.full(5, 3.14159) #用 pi 填滿一維陣列
array([3.14159, 3.14159, 3.14159, 3.14159, 3.14159])
>>>
np.full((2, 3), 3.14159) #用 pi 填滿二維陣列
array([[3.14159, 3.14159, 3.14159],
[3.14159, 3.14159, 3.14159]])
>>>
np.full([2, 3], 3.14159) #用 pi 填滿二維陣列
array([[3.14159, 3.14159, 3.14159],
[3.14159, 3.14159, 3.14159]])
>>>
np.full([2, 3, 4], 9) #用 9 填滿三維陣列
array([[[9, 9, 9, 9],
[9, 9, 9, 9],
[9, 9, 9, 9]],
[[9, 9, 9, 9],
[9, 9, 9, 9],
[9, 9, 9, 9]]])
(5). 對角陣列 (矩陣) :
呼叫 identity() 會建立一個中央對角線元素值為 1 的對角方陣, 介面如下 :
numpy.identity(n, dtype=None)
至少須傳入一個正整數參數以建立一個 n*n 方陣 :
>>>
np.identity(4) #建立 4*4 對角方陣 (浮點數)
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])
>>>
np.identity(4, dtype=int) #指定型態為整數
array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
呼叫 eye() 可建立一個指定對角線元素值為 1.0 (預設為中央對角線), 其餘元素為 0 的對角矩陣 (元素值預設為浮點數), 介面如下 :
numpy.eye(n, m=None, k=0, dtype=np.float, order='C')
第一參數 n 為矩陣的列數, 第二參數 m 為矩陣的行數, 第三參數 k 為元素值為 1 之對角線編號, 預設 0 為中央正對角線, k 為正整數時, 由中央往右上角第 k 條對角線元素全部為 1, 其餘為 0; k 為負整數時, 由中央往左下角第 k 條對角線元素全部為 1, 其餘為 0, 例如 :
>>>
np.eye(4) #建立 4*4 單位方陣
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])
>>>
np.eye(4, k=1) #建立 4*4 對角矩陣
array([[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.],
[0., 0., 0., 0.]])
>>>
np.eye(4, k=-1) #左下方第 1 條對角線填 1
array([[0., 0., 0., 0.],
[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.]])
>>>
np.eye(4, k=2) #右上方第 2 條對角線填 1
array([[0., 0., 1., 0.],
[0., 0., 0., 1.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
>>>
np.eye(4, k=3) #右上方第 3 條對角線填 1
array([[0., 0., 0., 1.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
>>>
np.eye(4, k=4) #右上方第 4 條對角線填 1 (超過了)
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
>>>
np.eye(4, 3) #4*3 矩陣 (非方陣)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.],
[0., 0., 0.]])
可見當 k 超過對角線總數時會變成建立零陣列.
另外一個與對角陣列有關的函數是 diag(), 其介面如下 :
numpy.diag(v, k=0)
第一個函數是一維或二維陣列, 第二個參數與 eye() 中的 k 參數一樣, 中央對角線 k 為 0 (預設值), 往右上走之對角線依序為 1, 2, ... ; 往左下走之對角線依序為 -1, -2, ... 等等. 若第一參數 v 傳入一個二維陣列, 則以一維陣列形式將其第 k 的對角線元素傳回 (getter); 若 v 傳入一個一維陣列, 則以該陣列元素取代第 k 個對角線.
首先建立一個 5*5 方陣如下 :
>>>
a=np.array(range(25)) #建立 [0, 1, 2, .... , 24] 一維陣列
>>>
x=a.reshape((5,5)) #調整形狀建立 5*5 方陣
>>>
print(x)
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]])
將此二維陣列傳給 diag() 會傳回其第 k 的對角線元素 :
>>>
np.diag(x) #傳回方陣 x 的中央對角線
array([ 0, 6, 12, 18, 24]) #傳回值為一維陣列
>>>
np.diag(x, k=1) #傳回方陣 x 的 k=1 對角線
array([ 1, 7, 13, 19])
>>>
np.diag(x, k=-1) #傳回方陣 x 的 k=-1 對角線
array([ 5, 11, 17, 23])
如果傳入一維陣列, 則會傳回一個指定對角線是該一維陣列的方陣, 例如 :
>>>
np.diag([1, 2, 3, 4, 5]) #建立指定中央對角線之方陣
array([[1, 0, 0, 0, 0],
[0, 2, 0, 0, 0],
[0, 0, 3, 0, 0],
[0, 0, 0, 4, 0],
[0, 0, 0, 0, 5]])
>>>
np.diag([1, 2, 3, 4, 5], k=1) #k=1 右上對角線方陣
array([[0, 1, 0, 0, 0, 0],
[0, 0, 2, 0, 0, 0],
[0, 0, 0, 3, 0, 0],
[0, 0, 0, 0, 4, 0],
[0, 0, 0, 0, 0, 5],
[0, 0, 0, 0, 0, 0]])
>>>
np.diag([1, 2, 3, 4, 5], k=-1) #k=-1 左下對角線方陣
array([[0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
[0, 2, 0, 0, 0, 0],
[0, 0, 3, 0, 0, 0],
[0, 0, 0, 4, 0, 0],
[0, 0, 0, 0, 5, 0]])
(6). 空陣列 :
呼叫 empty() 會建立一個指定形狀的未初始化陣列, 其元素值為所配置記憶體內原本的值, 其介面如下 :
numpy.empty(shape, dtype=float, order='C')
第一參數為陣列外形, 可以是正整數, 或元素為正整數之元組或串列 (通常用元組), 例如 :
>>>
np.empty(4) #建立 4 個元素的未初始化一維陣列
array([1., 1., 1., 1.])
>>>
np.empty((4,)) #建立 4 個元素的未初始化一維陣列
array([1., 1., 1., 1.])
>>>
np.empty((2, 3)) #建立 2*3 未初始化二維陣列
array([[3.14159, 3.14159, 3.14159],
[3.14159, 3.14159, 3.14159]])
>>>
np.empty((2, 3, 4)) #建立 2*3*4 未初始化三維陣列
array([[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]],
[[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]])
可見傳入 (4, ) 相當於傳入整數 4, 都是建立一維陣列.
5. 建立隨機內容之陣列 :
Numpy 底下的 random 模組提供了幾個方法可用來建立隨機陣列, 不過如果要讓隨機數可預測, 可以透過呼叫 np.random.seed() 設定隨機種子, 這樣在同一隨機種子下重複呼叫時, 傳回的隨機數列值與順序是一樣的 :
np.random.seed(i)
傳入參數 i 須為正整數.
(1). rand() 與 random() 函數 :
此函數會傳回 [0, 1) 區間均勻分布隨機陣列, 介面如下 :
numpy.random.rand(d0, d1, ..., dn)
rand() 的參數必須是正整數, 都是可選的, 未傳入參數時會傳回一個 0~1 之間的
均勻分布隨機浮點數 (純量); 傳入一個參數 n (須正整數) 時 random.rand(n) 會傳回 n 個元素的一維均勻分布隨機陣列, 這相當於 random.rand(
1, n); 傳入兩個參數 (須正整數) 時 random.rand(i, j) 會傳回一個 i*j 維度的均勻分布隨機隨機陣列, 更多參數則產生更高維的陣列, random.rand(i, j, k) 會傳回三維陣列, 例如 :
>>>
np.random.rand() #傳回 0~1 間的隨機數 (float 純量)
0.19644093345544167
>>>
type(np.random.rand()) #沒有傳入參數時傳回一個純量
<class 'float'>
>>>
np.random.rand(5) #傳回 1*5 一維隨機陣列
array([0.74998027, 0.78622133, 0.92885681, 0.18321391, 0.89496996])
>>>
np.random.rand(3, 4) #傳回 3*4 二維隨機陣列
array([[0.27912439, 0.73034461, 0.58826309, 0.59707398],
[0.44257555, 0.01745328, 0.59587659, 0.68253437],
[0.22404294, 0.19438719, 0.99749655, 0.49556471]])
>>>
np.random.rand(2, 3, 4) #傳回 2*3*4 三維隨機陣列
array([[[0.27131017, 0.40616805, 0.36128135, 0.75666407],
[0.40549157, 0.41149331, 0.30765576, 0.39208383],
[0.82069598, 0.60894839, 0.4239132 , 0.92491804]],
[[0.38630791, 0.36035005, 0.56409681, 0.15552691],
[0.74267144, 0.81580992, 0.8991233 , 0.34849928],
[0.37512254, 0.56358772, 0.60626021, 0.11272833]]])
可見 random.rand() 的元素值都是介於 0~1 之間.
另外 random.random() 功能與 random.rand() 一樣, 差別只是 random.random() 之參數為表示陣列形狀的物件, 通常是元組, 其介面如下 :
numpy.random.randdom(shape)
例如 :
>>>
np.random.random((2, 3, 4)) #傳回 2*3*4 三維隨機陣列
array([[[0.8636309 , 0.85336527, 0.17550813, 0.11426248],
[0.84716226, 0.7543792 , 0.24974123, 0.67595818],
[0.81296995, 0.5708457 , 0.35645387, 0.46249463]],
[[0.86340479, 0.20525588, 0.86448148, 0.67061865],
[0.78973599, 0.87887531, 0.85816169, 0.37024847],
[0.06263618, 0.10129474, 0.7355295 , 0.30408336]]])
參考 :
#
np.random.rand vs np.random.random
(2). randn() 函數 :
此函數與 rand() 一樣會傳回 [0, 1) 區間指定形狀之隨機陣列, 不同之處為 randn() 的隨機數為常態分布 (結尾的 n 表示 normal distribution), 而 rand() 為均勻分布, 介面如下 :
numpy.random.rand(d0, d1, ..., dn)
例如 :
>>>
np.random.randn() #傳回 0~1 間的隨機數 (float 純量)
0.3856502495158207
>>>
np.random.randn(5) #傳回 1*5 一維隨機陣列
array([ 0.1719701 , 0.30347725, -1.62440603, -0.2287934 , 0.8188689 ])
>>>
np.random.randn(3, 4) #傳回 3*4 二維隨機陣列
array([[ 0.42688578, 0.39268864, -0.3210757 , -0.59786833],
[ 0.62772359, 0.95096534, 0.47403366, 1.07871119],
[-0.46120767, 0.02107573, -1.12275642, -0.44598128]])
>>>
np.random.randn(2, 3, 4) #傳回 2*3*4 三維隨機陣列
array([[[ 0.65388739, -1.57062685, 1.29388902, -0.10002825],
[-1.34442224, -1.8373028 , 0.68837754, 0.13592657],
[-0.1309182 , -1.41535012, 0.2141069 , 1.30175303]],
[[ 1.83388743, 0.18719303, -1.58136535, 0.69444909],
[-1.20114114, -1.32826911, 0.16630603, -1.48900367],
[ 0.77561497, 0.18556015, 0.12806819, -0.70700624]]])
(3). randint() 函數 :
顧名思義, 此函數名結尾的 int 表示它會建立一個隨機整數陣列, 介面如下 :
numpy.random.randint(low, high=None, size=None, dtype='l')
可見 randint() 至少必須傳入一個參數 low, 表示傳回的隨機數最小值, 第二參數 high 為傳回的隨機數最大值 (不含), 第三參數為陣列維度, 可用元組或串列指定 (通常用元組), 例如 size=(2, 3) 表示建立 2*3 維度陣列, 預設傳回值型態為整數. 資料型態預設為 32 位元整數 'I', 也可以用其它整數型態例如 64 位元整數 'i8', 但不可指定為非整數型態.
總之, 此函數會傳回一個元素值大於等於 low, 小於 high, 維度為 size 的
均勻分布隨機數, 但實際測試發現,
當只傳入一個參數時, 它會被視為是 high 而不是 low, 例如 randint(4) 會傳回 [0, 4) 間隨機數, 必須同時傳入兩個參數時才會被解讀為前一個 low, 後一個 high, 例如 :
>>>
np.random.randint(4) #傳回小於 4 的隨機數
2
>>>
np.random.randint(low=4) #傳回小於 4 的隨機數
1
>>>
np.random.randint(1, 4) #傳回 [1, 4) 間的隨機數
3
>>>
np.random.randint(2, 31) #傳回 [2, 31) 間的隨機數
21
>>>
np.random.randint(2,10, [2,3]) #傳回 [2, 10) 間的隨機陣列
array([[5, 4, 8],
[2, 3, 9]])
參考 :
#
为什么你用不好Numpy的random函数?
6. 呼叫函數建立陣列 :
呼叫 numpy.fromfunction() 可透過函數呼叫來建立陣列, 介面如下 :
numpy.fromfunction(function, shape, **kwargs)
第一參數為建立陣列要呼叫的函數 (可用 lamda), 第二參數為輸入陣列的外形 (也是輸出陣列的外形), 通常是正整數元組 (tuple). 注意,
shape 並非傳入函數 function() 之參數, 傳入函數的參數是符合此外形的座標陣列 (coordinate array), 例如 shape=(2, 2) 時, 傳入參數為 [[0, 0], [1, 1]] 與 [[0, 1], [0, 1]] 這兩個陣列, 例如 :
>>>
def func(i, j): #呼叫的函數傳回兩陣列加 1 之乘積
...
return (i+1)*(j+1)
...
>>>
np.fromfunction(func, (2, 2))
array([[1., 2.],
[2., 4.]])
此處傳入函數 func(i, j) 的參數 i, j 分別為 [[0, 0], [1, 1]] 與 [[0, 1], [0, 1]] 這兩個陣列, 所以傳回 i+1=[[1, 1], [2, 2]] 與 j+1=[[1, 2], [1, 2]] 的陣列乘積為 [[1, 2], [2, 4]], 此可由下列陣列乘積印證 :
>>>
i=np.array([[1, 1], [2, 2]]) #二維陣列
>>>
j=np.array([[1, 2], [1, 2]]) #二維陣列
>>>
i*j
array([[1, 2],
[2, 4]])
與上面呼叫 fromfunction() 結果是一樣的. 如果傳入外形 shape=(9, 9) 就可以建立九九乘法表陣列, 例如 :
>>>
def func(i, j):
...
return (i+1)*(j+1)
...
>>>
np.fromfunction(func, (9, 9))
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.]]
參考 :
#
Numpy里的fromfunction()的问题?
#
Python資料分析(三)NumPy