NumPy與 Matlab 比較

介紹

MATLAB?和NumPy / SciPy有很多共同之處。但是有很多不同之處。創(chuàng)建NumPy和SciPy是為了用Python最自然的方式進行數(shù)值和科學計算,而不是MATLAB?克隆。本頁面旨在收集有關差異的智慧,主要是為了幫助熟練的MATLAB?用戶成為熟練的NumPy和SciPy用戶。

一些關鍵的差異

MATLAB NumPy
在MATLAB?中,基本數(shù)據類型是雙精度浮點數(shù)的多維數(shù)組。大多數(shù)表達式采用這樣的數(shù)組并返回這樣的數(shù) 對這些數(shù)組的2-D實例的操作被設計成或多或少地像線性代數(shù)中的矩陣運算。 在NumPy中,基本類型是多維的array。包括2D在內的所有維度中對這些數(shù)組的操作是逐元素操作。人們需要使用線性代數(shù)的特定函數(shù)(盡管對于矩陣乘法,可以@在python 3.5及更高版本中使用運算符)。
MATLAB?使用基于1(一)的索引。使用(1)找到序列的初始元素。 請參閱備注 Python使用基于0(零)的索引。使用[0]找到序列的初始元素。
MATLAB?的腳本語言是為執(zhí)行線性代數(shù)而創(chuàng)建的?;揪仃嚥僮鞯恼Z法很好而且干凈,但是用于添加GUI和制作完整應用程序的API或多或少都是事后的想法。 NumPy基于Python,它從一開始就被設計成一種優(yōu)秀的通用編程語言。雖然Matlab的一些數(shù)組操作的語法比NumPy更緊湊,但NumPy(由于是Python的附加組件)可以做許多Matlab不能做的事情,例如正確處理矩陣堆棧。
在MATLAB?中,數(shù)組具有按值傳遞的語義,并具有惰性寫入時復制方案,以防止在實際需要之前實際創(chuàng)建副本。切片操作復制數(shù)組的一部分。 在NumPy數(shù)組中有傳遞引用語義。切片操作是對數(shù)組的視圖。

'array'或'matrix'?我應該使用哪個?

從歷史上看,NumPy提供了一種特殊的矩陣類型 np.matrix ,它是ndarray的子??類,它使二進制運算成為線性代數(shù)運算。您可能會在某些現(xiàn)有代碼中看到它而不是 np.array 。那么,使用哪一個?

簡答

使用數(shù)組。

  • 它們是numpy的標準矢量/矩陣/張量類型。許多numpy函數(shù)返回數(shù)組,而不是矩陣。
  • 元素操作和線性代數(shù)操作之間有明顯的區(qū)別。
  • 如果您愿意,可以使用標準向量或行/列向量。

在Python 3.5之前,使用數(shù)組類型的唯一缺點是你必須使用dot而不是*乘法(減少)兩個張量(標量乘積,矩陣向量乘法等)。從Python 3.5開始,您可以使用矩陣乘法@運算符。

鑒于上述情況,我們打算matrix最終棄用。

長答案

NumPy包含array類和matrix類。所述
array類旨在是對許多種數(shù)值計算的通用n維數(shù)組中,而matrix意在具體促進線性代數(shù)計算。在實踐中,兩者之間只有少數(shù)關鍵差異。

  • 運算符*@函數(shù)dot(),以及multiply()
    • 對于數(shù)組,*表示逐元素乘法,而 @ 表示矩陣乘法; 它們具有相關的函數(shù) multiply()dot() 。(在python 3.5之前,@ 不存在,并且必須使用dot() 進行矩陣乘法)。
    • 對于矩陣,* 表示矩陣乘法,對于逐元素乘法,必須使用 multiply() 函數(shù)。
  • 矢量處理(一維數(shù)組)
    • 對于數(shù)組,向量形狀1xN,Nx1和N都是不同的東西。 像 A[:, 1] 這樣的操作返回形狀N的一維數(shù)組,而不是形狀Nx1的二維數(shù)組。 在一維數(shù)組上轉置什么都不做。
    • 對于矩陣,一維數(shù)組總是被上變頻為1xN或Nx1矩陣(行或列向量)。A[:, 1] 返回形狀為Nx1的二維矩陣。
  • 處理更高維數(shù)組(ndim> 2)
    • 數(shù)組對象的維數(shù)可以 > 2 ;
    • 矩陣對象總是有兩個維度
  • 便利屬性
    • array 有一個.T屬性,它返回數(shù)據的轉置。
    • matrix 還有.H,.I和.A屬性,分別返回共軛轉置,反轉和asarray()矩陣。
  • 便利構造函數(shù)
    • array構造采用(嵌套)的Python序列初始化。如:array([[1,2,3],[4,5,6]])
    • matrix構造還需要一個方便的字符串初始化。如:matrix("[1 2 3; 4 5 6]")

使用兩者有利有弊:

  • array
    • :) 元素乘法很容易:A*B。
    • :( 你必須記住,矩陣乘法有自己的運算符@。
    • :) 可以將一維數(shù)組視為行向量或列向量。 A @ vv 視為列向量,而 v @ Av 視為行向量。這可以節(jié)省您鍵入許多轉置。
    • :) array 是“默認”NumPy類型,因此它獲得的測試最多,并且是使用NumPy的第三方代碼最有可能返回的類型。
    • :) 非常擅長處理任何維度的數(shù)據。
    • :) 如果你熟悉那么語義學更接近張量代數(shù)。
    • :) 所有 操作(*/,+-等)逐元素。
    • :( 稀疏矩陣scipy.sparse不與數(shù)組交互。
  • matrix
    • :\\ 行為更像MATLAB?矩陣。
    • <:( 最大二維。要保存您需要的三維數(shù)據,array或者可能是Python列表matrix。
    • <:( 最小二維。你不能有載體。它們必須作為單列或單行矩陣進行轉換。
    • <:( 由于array是NumPy中的默認值,因此array即使您將它們matrix作為參數(shù)給出,某些函數(shù)也可能返回。這不應該發(fā)生在NumPy函數(shù)中(如果它確實是一個錯誤),但基于NumPy的第三方代碼可能不像NumPy那樣遵守類型保存。
    • :) A*B是矩陣乘法,所以它看起來就像你在線性代數(shù)中寫的那樣(對于Python> = 3.5普通數(shù)組與@運算符具有相同的便利性)。
    • <:( 元素乘法需要調用函數(shù), multiply(A,B)。
    • <:( 運算符重載的使用有點不合邏輯:* 不能按元素操作,但 / 確實如此。
    • 與之互動scipy.sparse有點清潔。

因此,使用 數(shù)組(array) 要明智得多。事實上,我們打算最終廢除 矩陣(matrix)。

MATLAB 和 NumPy粗略的功能對應表

下表給出了一些常見MATLAB?表達式的粗略等價物。這些不是確切的等價物,而應該作為提示讓你朝著正確的方向前進。有關更多詳細信息,請閱讀NumPy函數(shù)的內置文檔。

在下表中,假設您已在Python中執(zhí)行以下命令:

from numpy import *
import scipy.linalg

另外如果下表中的注釋這一列的內容是和 “matrix” 有關的話,那么參數(shù)一定是二維的形式。

一般功能的對應表

MATLAB NumPy 注釋
help func info(func)或者help(func)或func?(在IPython的) 獲得函數(shù)func的幫助
which func 請參閱備注 找出func定義的位置
type func source(func)或者func??(在Ipython中) func的打印源(如果不是本機函數(shù))
a && b a and b 短路邏輯AND運算符(Python本機運算符); 只有標量參數(shù)
a
b
1*i,1*j, 1i,1j 1j 復數(shù)
eps np.spacing(1) 1與最近的浮點數(shù)之間的距離。
ode45 scipy.integrate.solve_ivp(f) 將ODE與Runge-Kutta 4,5集成
ode15s scipy.integrate.solve_ivp(f, method='BDF') 將ODE與BDF方法集成

線性代數(shù)功能對應表

MATLAB NumPy 注釋
ndims(a) ndim(a) 要么 a.ndim 獲取數(shù)組的維數(shù)
numel(a) size(a) 要么 a.size 獲取數(shù)組的元素數(shù)
size(a) shape(a) 要么 a.shape 得到矩陣的“大小”
size(a,n) a.shape[n-1] 獲取數(shù)組第n維元素的數(shù)量a。(請注意,MATLAB?使用基于1的索引,而Python使用基于0的索引,請參閱備注
[ 1 2 3; 4 5 6 ] array([[1.,2.,3.], [4.,5.,6.]]) 2x3矩陣文字
[ a b; c d ] block([[a,b], [c,d]]) 從塊構造一個矩陣a,b,c,和d
a(end) a[-1] 訪問1xn矩陣中的最后一個元素 a
a(2,5) a[1,4] 訪問第二行,第五列中的元素
a(2,:) a[1] 或者 a[1,:] a的第二行
a(1:5,:) a[0:5]或a[:5]或a[0:5,:] 前五行 a
a(end-4:end,:) a[-5:] a的最后五行
a(1:3,5:9) a[0:3][:,4:9] a的第一至第三行與第五至第九列交叉的元素。這提供了只讀訪問權限。
a([2,4,5],[1,3]) a[ix_([1,3,4],[0,2])] 第2,4,5行與第1,3列交叉的元素。這允許修改矩陣,并且不需要常規(guī)切片。
a(3:2:21,:) a[ 2:21:2,:] 返回a的第3行與第21行之間每隔一行的行,即第3行與第21行之間的a的奇數(shù)行
a(1:2:end,:) a[ ::2,:] 返回a的奇數(shù)行
a(end: -1:1,:) 要么 flipud(a) a[ ::-1,:] 以相反的順序排列的a的行
a([1:end 1],: ) a[r_[:len(a),0]] a 的第一行添加到a的末尾行的副本
a.' a.transpose() 要么 a.T 轉置 a
a' a.conj().transpose() 要么 a.conj().T 共軛轉置 a
a * b a @ b 矩陣乘法
a .* b a * b 元素乘法
a./b a/b 元素除法
a.^3 a**3 元素取冪
(a>0.5) (a>0.5) 其i,jth元素為(a_ij> 0.5)的矩陣。Matlab結果是一個0和1的數(shù)組。NumPy結果是布爾值的數(shù)組False和True。
find(a>0.5) nonzero(a>0.5) 找到a中所有大于0.5的元素的線性位置
a(:,find(v>0.5)) a[:,nonzero(v>0.5)[0]] 提取a中向量v> 0.5的對應的列
a(:,find(v>0.5)) a[:,v.T>0.5] 提取a中向量v> 0.5的對應的列
a(a<0.5)=0 a[a<0.5]=0 a中小于0.5的元素賦值為0
a .* (a>0.5) a * (a>0.5) 返回一個數(shù)組,若a中對應位置元素大于0.5,取該元素的值;若a中對應元素<=0.5,取值0
a(: ) = 3 a[:] = 3 將所有值設置為相同的標量值
y=x y = x.copy() numpy通過引用分配
y=x(2,:) y = x[1,:].copy() numpy切片是參考
y=x(: ) y = x.flatten() 將數(shù)組轉換為向量(請注意,這會強制復制)
1:10 arange(1.,11.)或r_[1.:11.]或 r_[1:10:10j] 創(chuàng)建一個增加的向量,步長為默認值1(參見備注
0:9 arange(10.)或 r_[:10.]或 r_[:9:10j] 創(chuàng)建一個增加的向量,步長為默認值1(參見注釋范圍)
[1:10]' arange(1.,11.)[:, newaxis] 創(chuàng)建列向量
zeros(3,4) zeros((3,4)) 3x4二維數(shù)組,充滿64位浮點零
zeros(3,4,5) zeros((3,4,5)) 3x4x5三維數(shù)組,全部為64位浮點零
ones(3,4) ones((3,4)) 3x4二維數(shù)組,充滿64位浮點數(shù)
eye(3) eye(3) 3x3單位矩陣
diag(a) diag(a) 返回a的對角元素
diag(a,0) diag(a,0) 方形對角矩陣,其非零值是元素 a
rand(3,4) random.rand(3,4) 要么 random.random_sample((3, 4)) 隨機3x4矩陣
linspace(1,3,4) linspace(1,3,4) 4個等間距的樣本,介于1和3之間
[x,y]=meshgrid(0:8,0:5) mgrid[0:9.,0:6.] 要么 meshgrid(r_[0:9.],r_[0:6.] 兩個2D數(shù)組:一個是x值,另一個是y值
ogrid[0:9.,0:6.] 要么 ix_(r_[0:9.],r_[0:6.] 在網格上評估函數(shù)的最佳方法
[x,y]=meshgrid([1,2,4],[2,4,5]) meshgrid([1,2,4],[2,4,5])
ix_([1,2,4],[2,4,5]) 在網格上評估函數(shù)的最佳方法
repmat(a, m, n) tile(a, (m, n)) 用n份副本創(chuàng)建m a
[a b] concatenate((a,b),1)或者hstack((a,b))或 column_stack((a,b))或c_[a,b] 連接a和的列b
[a; b] concatenate((a,b))或vstack((a,b))或r_[a,b] 連接a和的行b
max(max(a)) a.max() 最大元素a(對于matlab,ndims(a)<= 2)
max(a) a.max(0) 每列矩陣的最大元素 a
max(a,[],2) a.max(1) 每行矩陣的最大元素 a
max(a,b) maximum(a, b) 比較a和b逐個元素,并返回每對中的最大值
norm(v) sqrt(v @ v) 要么 np.linalg.norm(v) L2矢量的規(guī)范 v
a & b logical_and(a,b) 逐個元素AND運算符(NumPy ufunc請參閱備注LOGICOPS
a b logical_or(a,b)
bitand(a,b) a & b 按位AND運算符(Python native和NumPy ufunc)
bitor(a,b) a b
inv(a) linalg.inv(a) 方陣的逆 a
pinv(a) linalg.pinv(a) 矩陣的偽逆 a
rank(a) linalg.matrix_rank(a) 二維數(shù)組/矩陣的矩陣秩 a
a\b linalg.solve(a,b)如果a是正方形; linalg.lstsq(a,b) 除此以外 ax = b的解為x
b/a 解決aT xT = bT xa = b的解為x
[U,S,V]=svd(a) U, S, Vh = linalg.svd(a), V = Vh.T 奇異值分解 a
chol(a) linalg.cholesky(a).T 矩陣的cholesky分解(chol(a)在matlab中返回一個上三角矩陣,但linalg.cholesky(a)返回一個下三角矩陣)
[V,D]=eig(a) D,V = linalg.eig(a) 特征值和特征向量 a
[V,D]=eig(a,b) D,V = scipy.linalg.eig(a,b) 特征值和特征向量a,b
[V,D]=eigs(a,k)
找到k最大的特征值和特征向量a
[Q,R,P]=qr(a,0) Q,R = scipy.linalg.qr(a) QR分解
[L,U,P]=lu(a) L,U = scipy.linalg.lu(a) 要么 LU,P=scipy.linalg.lu_factor(a) LU分解(注:P(Matlab)==轉置(P(numpy)))
conjgrad scipy.sparse.linalg.cg 共軛漸變求解器
fft(a) fft(a) 傅立葉變換 a
ifft(a) ifft(a) 逆傅立葉變換 a
sort(a) sort(a) 要么 a.sort() 對矩陣進行排序
[b,I] = sortrows(a,i) I = argsort(a[:,i]), b=a[I,:] 對矩陣的行進行排序
regress(y,X) linalg.lstsq(X,y) 多線性回歸
decimate(x, q) scipy.signal.resample(x, len(x)/q) 采用低通濾波的下采樣
unique(a) unique(a)
squeeze(a) a.squeeze()

備注

子矩陣:使用該ix_命令可以使用索引列表完成對子矩陣的分配。例如,對于2D數(shù)組a,可能會做:ind=[1,3]; a[np.ix_(ind,ind)]+=100。

幫助:有MATLAB的沒有直接等價which的命令,但命令helpsource通常會列出其中函數(shù)所在的文件名。Python還有一個inspect模塊(do import inspect),它提供了一個getfile經常工作的模塊。

索引:MATLAB?使用一個基于索引,因此序列的初始元素具有索引1.Python使用基于零的索引,因此序列的初始元素具有索引0.出現(xiàn)混淆和火焰,因為每個元素都有優(yōu)點和缺點。一種基于索引的方法與常見的人類語言使用一致,其中序列的“第一”元素具有索引1.基于零的索引簡化了索引

。另見prof.dr的文本。Edsger W. Dijkstra

。

范圍:在MATLAB?中,0:5可以用作范圍文字和“切片”索引(括號內); 然而,在Python,構建體等0:5可以 被用作切片指數(shù)(方括號內)。因此,r_創(chuàng)建了一些有點古怪的對象,以使numpy具有類似的簡潔范圍構造機制。請注意,r_它不像函數(shù)或構造函數(shù)那樣
被調用,而是
使用方括號進行 索引 ,這允許在參數(shù)中使用Python的切片語法。

邏輯運算:&或| 在NumPy中是按位AND / OR,而在Matlab&和|中 是邏輯AND / OR。任何具有重要編程經驗的人都應該清楚這種差異。這兩者似乎工作原理相同,但存在重要差異。如果您使用過Matlab的&或| 運算符,您應該使用NumPy ufuncs logical_and / logical_or。Matlab和NumPy的&和|之間的顯著差異 運營商是:

  • 非邏輯{0,1}輸入:NumPy的輸出是輸入的按位AND。Matlab將任何非零值視為1并返回邏輯AND。例如,NumPy中的(3和4)是0,而在Matlab中,3和4都被認為是邏輯真,而(3和4)返回1。
  • 優(yōu)先級:NumPy的&運算符優(yōu)先于<和>之類的邏輯運算符; Matlab是相反的。

如果你知道你有布爾參數(shù),你可以使用NumPy的按位運算符,但要注意括號,如:z =(x> 1)&(x <2)。缺少NumPy運算符形式的logical_and和logical_or是Python設計的一個不幸結果。

重塑與線性索引:Matlab總是允許使用標量或線性索引訪問多維數(shù)組,而NumPy則不然。線性索引在Matlab程序中很常見,例如矩陣上的find()返回它們,而NumPy的查找行為則不同。在轉換Matlab代碼時,可能需要首先將矩陣重新整形為線性序列,執(zhí)行一些索引操作然后重新整形。由于重塑(通常)會在同一存儲上生成視圖,因此應該可以相當有效地執(zhí)行此操作。請注意,在NumPy中重新整形使用的掃描順序默認為'C'順序,而Matlab使用Fortran順序。如果您只是簡單地轉換為線性序列,那么這無關緊要。但是如果要從依賴于掃描順序的Matlab代碼轉換重構,那么這個Matlab代碼:z = reshape(x,3,4) 應該變成 z = x.reshape(3,4,order=’F’).copy() 。

自定義您的環(huán)境

在MATLAB?中,可用于自定義環(huán)境的主要工具是使用您喜歡的功能的位置修改搜索路徑。您可以將此類自定義項放入MATLAB將在啟動時運行的啟動腳本中。

NumPy,或者更確切地說是Python,具有類似的功能。

  • 要修改Python搜索路徑以包含您自己的模塊的位置,請定義PYTHONPATH環(huán)境變量。
  • 要在啟動交互式Python解釋器時執(zhí)行特定的腳本文件,請定義PYTHONSTARTUP環(huán)境變量以包含啟動腳本的名稱。

與MATLAB?不同,可以立即調用路徑上的任何內容,使用Python,您需要先執(zhí)行“import”語句,以使特定文件中的函數(shù)可訪問。

例如,您可能會創(chuàng)建一個如下所示的啟動腳本(注意:這只是一個示例,而不是“最佳實踐”的聲明):

# Make all numpy available via shorter 'np' prefix
import numpy as np
# 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 rand,zeros,ones,empty,eye
# Define a Hermitian function
def hermitian(A, **kwargs):
    return np.transpose(A,**kwargs).conj()
# Make some shortcuts for transpose,hermitian:
#    np.transpose(A) --> T(A)
#    hermitian(A) --> H(A)
T = np.transpose
H = hermitian

鏈接

有關另一個MATLAB?/ NumPy交叉引用,請參見http://mathesaurus.sf.net/

。

可以在主題軟件頁面中

找到用于python科學工作的廣泛工具列表。

MATLAB?和SimuLink?是The MathWorks的注冊商標。

作者:柯廣的網絡日志 ? NumPy與 Matlab 比較


微信公眾號:Java大數(shù)據與數(shù)據倉庫