適用於 MATLAB 使用者的 NumPy#
簡介#
MATLAB® 和 NumPy 有許多共通之處,但 NumPy 的創建是為了與 Python 協同運作,而非成為 MATLAB 的複製品。本指南將協助 MATLAB 使用者開始使用 NumPy。
一些主要差異#
在 MATLAB 中,即使是純量,基本類型也是多維陣列。除非您指定維度和類型,否則 MATLAB 中的陣列賦值會儲存為雙精度浮點數的 2D 陣列。在這些陣列的 2D 實例上的運算是以線性代數中的矩陣運算為模型。 |
在 NumPy 中,基本類型是多維 |
MATLAB 從 1 開始編號索引; |
NumPy 與 Python 一樣,從 0 開始編號索引; |
MATLAB 的腳本語言是為線性代數而創建的,因此某些陣列操作的語法比 NumPy 更簡潔。另一方面,用於新增 GUI 和建立完整應用程式的 API 或多或少是事後才考慮的。 |
NumPy 基於通用語言 Python。NumPy 的優勢在於可以存取 Python 函式庫,包括:SciPy、Matplotlib、Pandas、OpenCV 等等。此外,Python 通常嵌入為腳本語言在其他軟體中,也允許在那裡使用 NumPy。 |
MATLAB 陣列切片使用傳值語義,並採用延遲寫入時複製方案,以防止在需要之前建立副本。切片操作會複製陣列的部分內容。 |
NumPy 陣列切片使用傳參考,這不會複製引數。切片操作是陣列的視圖。 |
大致對等項目#
下表列出了一些常見 MATLAB 表達式的大致對等項目。這些是相似的表達式,而非完全對等。如需詳細資訊,請參閱文件。
在下表中,假設您已在 Python 中執行以下命令
import numpy as np
from scipy import io, integrate, linalg, signal
from scipy.sparse.linalg import cg, eigs
也假設在下方,如果註解談論「矩陣」,則引數是二維實體。
通用對等項目#
MATLAB |
NumPy |
註解 |
---|---|---|
|
|
取得函數 func 的說明 |
|
找出 func 的定義位置 |
|
|
|
印出 func 的原始碼(如果不是原生函數) |
|
|
使用文字 |
for i=1:3
fprintf('%i\n',i)
end
|
for i in range(1, 4):
print(i)
|
使用 for 迴圈印出數字 1、2 和 3,使用 |
|
|
短路邏輯 AND 運算子 (Python 原生運算子);僅限純量引數 |
|
|
短路邏輯 OR 運算子 (Python 原生運算子);僅限純量引數 |
>> 4 == 4
ans = 1
>> 4 == 5
ans = 0
|
>>> 4 == 4
True
>>> 4 == 5
False
|
Python 中的布林物件是 |
a=4
if a==4
fprintf('a = 4\n')
elseif a==5
fprintf('a = 5\n')
end
|
a = 4
if a == 4:
print('a = 4')
elif a == 5:
print('a = 5')
|
建立 if-else 陳述式以檢查 |
|
|
複數 |
|
|
從 1 到雙精度中下一個較大可表示實數的距離 |
|
|
載入儲存到檔案 |
|
|
使用 Runge-Kutta 4,5 積分 ODE |
|
|
使用 BDF 方法積分 ODE |
線性代數對等項目#
MATLAB |
NumPy |
註解 |
---|---|---|
|
|
陣列 |
|
|
陣列 |
|
|
陣列 |
|
|
取得陣列 |
|
|
定義一個 2x3 2D 陣列 |
|
|
從區塊 |
|
|
存取 MATLAB 向量 (1xn 或 nx1) 或 1D NumPy 陣列 |
|
|
存取 2D 陣列 |
|
|
2D 陣列 |
|
|
2D 陣列 |
|
|
2D 陣列 |
|
|
2D 陣列 |
|
|
第 2、4 和 5 列以及第 1 和 3 行。這允許修改矩陣,且不需要規則切片。 |
|
|
陣列 |
|
|
陣列 |
|
|
列反轉順序的 |
|
|
將第一列副本附加到末尾的 |
|
|
|
|
|
|
|
|
矩陣乘法 |
|
|
逐元素乘法 |
|
|
逐元素除法 |
|
|
逐元素指數運算 |
|
|
其 i,jth 元素為 (a_ij > 0.5) 的矩陣。MATLAB 結果是一個邏輯值 0 和 1 的陣列。NumPy 結果是一個布林值 |
|
|
找出 ( |
|
|
擷取向量 v > 0.5 的 |
|
|
擷取行向量 v > 0.5 的 |
|
|
將元素小於 0.5 的 |
|
|
將元素小於 0.5 的 |
|
|
將所有值設定為相同的純量值 |
|
|
NumPy 以傳參考方式賦值 |
|
|
NumPy 切片以傳參考方式進行 |
|
|
將陣列轉換為向量(請注意,這會強制複製)。若要取得與 MATLAB 相同的資料排序,請使用 |
|
|
建立遞增向量(請參閱註解 RANGES) |
|
|
建立遞增向量(請參閱註解 RANGES) |
|
|
建立行向量 |
|
|
充滿 64 位元浮點零的 3x4 二維陣列 |
|
|
充滿 64 位元浮點零的 3x4x5 三維陣列 |
|
|
充滿 64 位元浮點一的 3x4 二維陣列 |
|
|
3x3 單位矩陣 |
|
|
傳回 2D 陣列 |
|
|
傳回一個方形對角矩陣,其非零值是向量 |
rng(42,'twister')
rand(3,4)
|
from numpy.random import default_rng
rng = default_rng(42)
rng.random((3, 4))
或舊版本: |
使用預設亂數產生器和種子 = 42 產生 3x4 隨機陣列 |
|
|
1 到 3 之間(含)的 4 個等距樣本 |
|
|
兩個 2D 陣列:一個是 x 值,另一個是 y 值 |
|
在網格上評估函數的最佳方法 |
|
|
|
|
|
在網格上評估函數的最佳方法 |
|
|
|
建立 |
|
|
串聯 |
|
|
串聯 |
|
|
|
|
|
陣列 |
|
|
陣列 |
|
|
逐元素比較 |
|
|
向量 |
|
|
逐元素 AND 運算子 (NumPy ufunc) 請參閱註解 LOGICOPS |
|
|
逐元素 OR 運算子 (NumPy ufunc) 請參閱註解 LOGICOPS |
|
|
位元 AND 運算子 (Python 原生和 NumPy ufunc) |
|
|
位元 OR 運算子 (Python 原生和 NumPy ufunc) |
|
|
方形 2D 陣列 |
|
|
2D 陣列 |
|
|
2D 陣列 |
|
|
求解 a x = b 的 x |
|
改為求解 |
求解 x a = b 的 x |
|
|
|
|
|
2D 陣列的 Cholesky 分解 |
|
|
|
|
|
|
|
|
找出 2D 陣列 |
|
|
QR 分解 |
|
|
帶有部分樞軸的 LU 分解(注意:P(MATLAB) == transpose(P(NumPy))) |
|
|
共軛梯度求解器 |
|
|
|
|
|
|
|
|
排序 2D 陣列 |
|
|
排序 2D 陣列 |
|
|
將陣列 |
|
|
執行 \(\mathbf{Zx}=\mathbf{y}\) 形式的線性迴歸 |
|
|
使用低通濾波進行降採樣 |
|
|
陣列 |
|
|
移除陣列 |
註解#
子矩陣:可以使用索引列表和 ix_
命令來完成子矩陣的賦值。例如,對於 2D 陣列 a
,可以執行以下操作:ind=[1, 3]; a[np.ix_(ind, ind)] += 100
。
HELP:沒有與 MATLAB 的 which
命令直接對應的命令,但 help
命令通常會列出函數所在檔案的檔名。Python 也有一個 inspect
模組(執行 import inspect
),它提供了一個通常有效的 getfile
。
INDEXING:MATLAB 使用從 1 開始的索引,因此序列的初始元素索引為 1。Python 使用從 0 開始的索引,因此序列的初始元素索引為 0。由於每種索引都有優點和缺點,因此會產生混淆和爭論。從 1 開始的索引與常見的人類語言用法一致,其中序列的「第一個」元素索引為 1。從 0 開始的索引簡化了索引。另請參閱 prof.dr. Edsger W. Dijkstra 的文章。
RANGES:在 MATLAB 中,0:5
可以同時用作範圍文字和「切片」索引(在括號內);但是,在 Python 中,0:5
之類的結構*只能*用作切片索引(在方括號內)。因此,創建了有點奇怪的 r_
物件,以允許 NumPy 具有類似簡潔的範圍建構機制。請注意,r_
不是像函數或建構子那樣呼叫,而是使用方括號進行*索引*,這允許在引數中使用 Python 的切片語法。
LOGICOPS:NumPy 中的 &
或 |
是位元 AND/OR,而在 MATLAB 中,& 和 |
是邏輯 AND/OR。兩者看起來可能工作方式相同,但存在重要差異。如果您曾經使用過 MATLAB 的 &
或 |
運算子,則應使用 NumPy ufunc logical_and
/logical_or
。MATLAB 和 NumPy 的 &
和 |
運算子之間值得注意的差異是
非邏輯 {0,1} 輸入:NumPy 的輸出是輸入的位元 AND。MATLAB 將任何非零值視為 1,並傳回邏輯 AND。例如,NumPy 中的
(3 & 4)
為0
,而在 MATLAB 中,3
和4
都被視為邏輯真,且(3 & 4)
傳回1
。優先順序:NumPy 的 & 運算子的優先順序高於
<
和>
等邏輯運算子;MATLAB 的則相反。
如果您知道您有布林引數,則可以使用 NumPy 的位元運算子,但請小心括號,例如:z = (x > 1) & (x < 2)
。NumPy 運算子沒有 logical_and
和 logical_or
形式是 Python 設計的一個不幸後果。
RESHAPE 和線性索引:MATLAB 始終允許使用純量或線性索引存取多維陣列,而 NumPy 則不允許。線性索引在 MATLAB 程式中很常見,例如,矩陣上的 find()
會傳回它們,而 NumPy 的 find 行為則不同。轉換 MATLAB 程式碼時,可能需要先將矩陣重塑為線性序列,執行一些索引操作,然後再重塑回來。由於 reshape(通常)會產生對相同儲存體的視圖,因此應該可以相當有效率地執行此操作。請注意,NumPy 中 reshape 使用的掃描順序預設為 ‘C’ 順序,而 MATLAB 使用 Fortran 順序。如果您只是轉換為線性序列並返回,這並不重要。但是,如果您要從依賴掃描順序的 MATLAB 程式碼轉換 reshape,則此 MATLAB 程式碼:z = reshape(x,3,4);
應在 NumPy 中變為 z = x.reshape(3,4,order='F').copy()
。
「array」還是「matrix」?我應該使用哪個?#
從歷史上看,NumPy 提供了一種特殊的矩陣類型 np.matrix,它是 ndarray 的子類別,它使二元運算成為線性代數運算。您可能會在一些現有程式碼中看到它被使用,而不是 np.array。那麼,應該使用哪個呢?
簡短回答#
使用陣列.
它們支援 MATLAB 中支援的多維陣列代數
它們是 NumPy 的標準向量/矩陣/張量類型。許多 NumPy 函數傳回陣列,而不是矩陣。
逐元素運算和線性代數運算之間有明顯的區別。
如果您願意,可以使用標準向量或行/列向量。
在 Python 3.5 之前,使用陣列類型的唯一缺點是您必須使用 dot
而不是 *
來乘法(縮減)兩個張量(純量積、矩陣向量乘法等)。自 Python 3.5 以來,您可以使用矩陣乘法 @
運算子。
鑑於以上所述,我們打算最終棄用 matrix
。
詳細回答#
NumPy 包含 array
類別和 matrix
類別。array
類別旨在作為適用於多種數值計算的通用 n 維陣列,而 matrix
則旨在專門促進線性代數計算。實際上,兩者之間只有少數幾個關鍵差異。
運算子
*
和@
、函數dot()
和multiply()
對於
array
,``*`` 代表逐元素乘法,而 ``@`` 代表矩陣乘法;它們具有相關的函數multiply()
和dot()
。(在 Python 3.5 之前,@
尚不存在,必須使用dot()
進行矩陣乘法)。對於
matrix
,``*`` 代表矩陣乘法,而對於逐元素乘法,則必須使用multiply()
函數。
向量(一維陣列)的處理
對於
array
,向量形狀 1xN、Nx1 和 N 都是不同的事物。像是A[:,1]
的操作會回傳形狀為 N 的一維陣列,而不是形狀為 Nx1 的二維陣列。對一維array
進行轉置沒有作用。對於
matrix
,一維陣列總是向上轉換為 1xN 或 Nx1 矩陣(行向量或列向量)。A[:,1]
回傳形狀為 Nx1 的二維矩陣。
高維陣列(ndim > 2)的處理
array
物件可以具有大於 2 的維度數量;matrix
物件總是恰好有兩個維度。
便利屬性
array
具有 .T 屬性,它會回傳資料的轉置。matrix
也具有 .H、.I 和 .A 屬性,它們分別回傳矩陣的共軛轉置、逆矩陣和asarray()
。
便利建構子
array
建構子接受(巢狀)Python 序列作為初始化器。例如,array([[1,2,3],[4,5,6]])
。matrix
建構子還接受便利的字串初始化器。例如matrix("[1 2 3; 4 5 6]")
。
使用兩者各有優缺點
array
:)
逐元素乘法很簡單:A*B
。:(
你必須記得矩陣乘法有自己的運算子@
。:)
你可以將一維陣列視為行或列向量。A @ v
將v
視為行向量,而v @ A
將v
視為列向量。這可以省去你輸入大量轉置的時間。:)
array
是 NumPy 的「預設」類型,因此它獲得最多的測試,並且是最有可能被使用 NumPy 的第三方程式碼回傳的類型。:)
非常擅長處理任何維度數量的資料。:)
如果你對張量代數很熟悉,那麼在語義上更接近張量代數。:)
所有運算(*
、/
、+
、-
等)都是逐元素的。:(
來自scipy.sparse
的稀疏矩陣與陣列的互動性較差。
matrix
:\\
行為更像 MATLAB 矩陣。<:(
最大二維。為了容納三維資料,你需要array
或許是 Python 的matrix
列表。<:(
最小二維。你不能有向量。它們必須轉換為單列或單行矩陣。<:(
由於陣列是 NumPy 中的預設值,因此即使你給它們一個矩陣作為參數,某些函數也可能會回傳一個陣列。這不應該發生在 NumPy 函數中(如果發生了,那就是一個錯誤),但基於 NumPy 的第三方程式碼可能不會像 NumPy 那樣遵守類型保留。:)
A*B
是矩陣乘法,所以它看起來就像你在線性代數中寫的那樣(對於 Python >= 3.5,普通陣列使用@
運算子具有相同的便利性)。<:(
逐元素乘法需要呼叫函數multiply(A,B)
。<:(
運算子多載的使用有點不合邏輯:*
不進行逐元素運算,但/
卻進行。與
scipy.sparse
的互動性稍微更乾淨。
array
因此更建議使用。實際上,我們打算最終棄用 matrix
。
自訂您的環境#
在 MATLAB 中,您可使用的主要工具是修改搜尋路徑,以包含您常用函數的位置。您可以將此類自訂設定放入 MATLAB 將在啟動時執行的啟動腳本中。
NumPy,或者更確切地說是 Python,也具有類似的功能。
若要修改您的 Python 搜尋路徑以包含您自己模組的位置,請定義
PYTHONPATH
環境變數。若要在啟動互動式 Python 直譯器時執行特定的腳本檔案,請定義
PYTHONSTARTUP
環境變數以包含您的啟動腳本名稱。
不像 MATLAB,路徑上的任何東西都可以立即呼叫,使用 Python,您需要先執行 ‘import’ 語句才能使特定檔案中的函數可存取。
例如,您可以建立一個像這樣的啟動腳本(注意:這只是一個範例,並非「最佳實踐」的陳述)
# Make all numpy available via shorter 'np' prefix
import numpy as np
#
# Make the SciPy linear algebra functions available as linalg.func()
# e.g. linalg.lu, linalg.eig (for general l*B@u==A@u solution)
from scipy import linalg
#
# Define a Hermitian function
def hermitian(A, **kwargs):
return np.conj(A,**kwargs).T
# Make a shortcut for hermitian:
# hermitian(A) --> H(A)
H = hermitian
若要使用已棄用的 matrix 和其他 matlib 函數
# Make all matlib functions accessible at the top level via M.func()
import numpy.matlib as M
# Make some matlib functions accessible directly at the top level via, e.g. rand(3,3)
from numpy.matlib import matrix,rand,zeros,ones,empty,eye
連結#
另一個有些過時的 MATLAB/NumPy 交叉參考可以在 http://mathesaurus.sf.net/ 找到
在 主題軟體頁面 中可以找到使用 Python 進行科學工作的廣泛工具列表。
請參閱 Python 軟體列表:腳本 以取得使用 Python 作為腳本語言的軟體列表
MATLAB® 和 SimuLink® 是 The MathWorks, Inc. 的註冊商標。