NumPy與 Matlab 比較
介紹
MATLAB?和NumPy / SciPy有很多共同之處。但是有很多不同之處。創(chuàng)建NumPy和SciPy是為了用Python最自然的方式進(jìn)行數(shù)值和科學(xué)計算,而不是MATLAB?克隆。本頁面旨在收集有關(guān)差異的智慧,主要是為了幫助熟練的MATLAB?用戶成為熟練的NumPy和SciPy用戶。
一些關(guān)鍵的差異
MATLAB | NumPy |
---|---|
在MATLAB?中,基本數(shù)據(jù)類型是雙精度浮點(diǎn)數(shù)的多維數(shù)組。大多數(shù)表達(dá)式采用這樣的數(shù)組并返回這樣的數(shù) 對這些數(shù)組的2-D實(shí)例的操作被設(shè)計成或多或少地像線性代數(shù)中的矩陣運(yùn)算。 | 在NumPy中,基本類型是多維的array。包括2D在內(nèi)的所有維度中對這些數(shù)組的操作是逐元素操作。人們需要使用線性代數(shù)的特定函數(shù)(盡管對于矩陣乘法,可以@在python 3.5及更高版本中使用運(yùn)算符)。 |
MATLAB?使用基于1(一)的索引。使用(1)找到序列的初始元素。 請參閱備注 | Python使用基于0(零)的索引。使用[0]找到序列的初始元素。 |
MATLAB?的腳本語言是為執(zhí)行線性代數(shù)而創(chuàng)建的?;揪仃嚥僮鞯恼Z法很好而且干凈,但是用于添加GUI和制作完整應(yīng)用程序的API或多或少都是事后的想法。 | NumPy基于Python,它從一開始就被設(shè)計成一種優(yōu)秀的通用編程語言。雖然Matlab的一些數(shù)組操作的語法比NumPy更緊湊,但NumPy(由于是Python的附加組件)可以做許多Matlab不能做的事情,例如正確處理矩陣堆棧。 |
在MATLAB?中,數(shù)組具有按值傳遞的語義,并具有惰性寫入時復(fù)制方案,以防止在實(shí)際需要之前實(shí)際創(chuàng)建副本。切片操作復(fù)制數(shù)組的一部分。 | 在NumPy數(shù)組中有傳遞引用語義。切片操作是對數(shù)組的視圖。 |
'array'或'matrix'?我應(yīng)該使用哪個?
從歷史上看,NumPy提供了一種特殊的矩陣類型 np.matrix ,它是ndarray的子??類,它使二進(jìn)制運(yùn)算成為線性代數(shù)運(yùn)算。您可能會在某些現(xiàn)有代碼中看到它而不是 np.array 。那么,使用哪一個?
簡答
使用數(shù)組。
- 它們是numpy的標(biāo)準(zhǔn)矢量/矩陣/張量類型。許多numpy函數(shù)返回數(shù)組,而不是矩陣。
- 元素操作和線性代數(shù)操作之間有明顯的區(qū)別。
- 如果您愿意,可以使用標(biāo)準(zhǔn)向量或行/列向量。
在Python 3.5之前,使用數(shù)組類型的唯一缺點(diǎn)是你必須使用dot
而不是*
乘法(減少)兩個張量(標(biāo)量乘積,矩陣向量乘法等)。從Python 3.5開始,您可以使用矩陣乘法@
運(yùn)算符。
鑒于上述情況,我們打算matrix
最終棄用。
長答案
NumPy包含array
類和matrix
類。所述
array
類旨在是對許多種數(shù)值計算的通用n維數(shù)組中,而matrix
意在具體促進(jìn)線性代數(shù)計算。在實(shí)踐中,兩者之間只有少數(shù)關(guān)鍵差異。
- 運(yùn)算符
*
和@
函數(shù)dot()
,以及multiply()
:- 對于
數(shù)組
,*
表示逐元素乘法,而@
表示矩陣乘法; 它們具有相關(guān)的函數(shù)multiply()
和dot()
。(在python 3.5之前,@
不存在,并且必須使用dot()
進(jìn)行矩陣乘法)。 - 對于
矩陣
,*
表示矩陣乘法,對于逐元素乘法,必須使用multiply()
函數(shù)。
- 對于
- 矢量處理(一維數(shù)組)
- 對于
數(shù)組
,向量形狀1xN,Nx1和N都是不同的東西。 像A[:, 1]
這樣的操作返回形狀N的一維數(shù)組,而不是形狀Nx1的二維數(shù)組。 在一維數(shù)組上轉(zhuǎn)置什么都不做。 - 對于
矩陣
,一維數(shù)組總是被上變頻為1xN或Nx1矩陣(行或列向量)。A[:, 1]
返回形狀為Nx1的二維矩陣。
- 對于
- 處理更高維數(shù)組(ndim> 2)
數(shù)組
對象的維數(shù)可以 > 2 ;矩陣
對象總是有兩個維度。
- 便利屬性
array
有一個.T屬性,它返回數(shù)據(jù)的轉(zhuǎn)置。matrix
還有.H,.I和.A屬性,分別返回共軛轉(zhuǎn)置,反轉(zhuǎn)和asarray()
矩陣。
- 便利構(gòu)造函數(shù)
- 該
array
構(gòu)造采用(嵌套)的Python序列初始化。如:array([[1,2,3],[4,5,6]])
。 - 該
matrix
構(gòu)造還需要一個方便的字符串初始化。如:matrix("[1 2 3; 4 5 6]")
。
- 該
使用兩者有利有弊:
array
:)
元素乘法很容易:A*B
。:(
你必須記住,矩陣乘法有自己的運(yùn)算符@
。:)
可以將一維數(shù)組視為行向量或列向量。A @ v
將v
視為列向量,而v @ A
將v
視為行向量。這可以節(jié)省您鍵入許多轉(zhuǎn)置。:)
array
是“默認(rèn)”NumPy類型,因此它獲得的測試最多,并且是使用NumPy的第三方代碼最有可能返回的類型。:)
非常擅長處理任何維度的數(shù)據(jù)。:)
如果你熟悉那么語義學(xué)更接近張量代數(shù)。:)
所有 操作(*
,/
,+
,-
等)逐元素。:(
稀疏矩陣scipy.sparse
不與數(shù)組交互。
matrix
:\\
行為更像MATLAB?矩陣。<:(
最大二維。要保存您需要的三維數(shù)據(jù),array
或者可能是Python列表matrix
。<:(
最小二維。你不能有載體。它們必須作為單列或單行矩陣進(jìn)行轉(zhuǎn)換。<:(
由于array
是NumPy中的默認(rèn)值,因此array
即使您將它們matrix
作為參數(shù)給出,某些函數(shù)也可能返回。這不應(yīng)該發(fā)生在NumPy函數(shù)中(如果它確實(shí)是一個錯誤),但基于NumPy的第三方代碼可能不像NumPy那樣遵守類型保存。:)
A*B
是矩陣乘法,所以它看起來就像你在線性代數(shù)中寫的那樣(對于Python> = 3.5普通數(shù)組與@
運(yùn)算符具有相同的便利性)。<:(
元素乘法需要調(diào)用函數(shù),multiply(A,B)
。<:(
運(yùn)算符重載的使用有點(diǎn)不合邏輯:*
不能按元素操作,但/
確實(shí)如此。- 與之互動
scipy.sparse
有點(diǎn)清潔。
因此,使用 數(shù)組(array)
要明智得多。事實(shí)上,我們打算最終廢除 矩陣(matrix)
。
MATLAB 和 NumPy粗略的功能對應(yīng)表
下表給出了一些常見MATLAB?表達(dá)式的粗略等價物。這些不是確切的等價物,而應(yīng)該作為提示讓你朝著正確的方向前進(jìn)。有關(guān)更多詳細(xì)信息,請閱讀NumPy函數(shù)的內(nèi)置文檔。
在下表中,假設(shè)您已在Python中執(zhí)行以下命令:
from numpy import *
import scipy.linalg
另外如果下表中的注釋這一列的內(nèi)容是和 “matrix” 有關(guān)的話,那么參數(shù)一定是二維的形式。
一般功能的對應(yīng)表
MATLAB | NumPy | 注釋 |
---|---|---|
help func | info(func)或者h(yuǎn)elp(func)或func?(在IPython的) | 獲得函數(shù)func的幫助 |
which func | 請參閱備注 | 找出func定義的位置 |
type func | source(func)或者func??(在Ipython中) | func的打印源(如果不是本機(jī)函數(shù)) |
a && b | a and b | 短路邏輯AND運(yùn)算符(Python本機(jī)運(yùn)算符); 只有標(biāo)量參數(shù) |
a | b | |
1*i,1*j, 1i,1j | 1j | 復(fù)數(shù) |
eps | np.spacing(1) | 1與最近的浮點(diǎn)數(shù)之間的距離。 |
ode45 | scipy.integrate.solve_ivp(f) | 將ODE與Runge-Kutta 4,5集成 |
ode15s | scipy.integrate.solve_ivp(f, method='BDF') | 將ODE與BDF方法集成 |
線性代數(shù)功能對應(yīng)表
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]]) | 從塊構(gòu)造一個矩陣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的第一至第三行與第五至第九列交叉的元素。這提供了只讀訪問權(quán)限。 |
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 | 轉(zhuǎn)置 a |
a' | a.conj().transpose() 要么 a.conj().T | 共軛轉(zhuǎn)置 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結(jié)果是一個0和1的數(shù)組。NumPy結(jié)果是布爾值的數(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的對應(yīng)的列 |
a(:,find(v>0.5)) | a[:,v.T>0.5] | 提取a中向量v> 0.5的對應(yīng)的列 |
a(a<0.5)=0 | a[a<0.5]=0 | a中小于0.5的元素賦值為0 |
a .* (a>0.5) | a * (a>0.5) | 返回一個數(shù)組,若a中對應(yīng)位置元素大于0.5,取該元素的值;若a中對應(yīng)元素<=0.5,取值0 |
a(: ) = 3 | a[:] = 3 | 將所有值設(shè)置為相同的標(biāo)量值 |
y=x | y = x.copy() | numpy通過引用分配 |
y=x(2,:) | y = x[1,:].copy() | numpy切片是參考 |
y=x(: ) | y = x.flatten() | 將數(shù)組轉(zhuǎn)換為向量(請注意,這會強(qiáng)制復(fù)制) |
1:10 | arange(1.,11.)或r_[1.:11.]或 r_[1:10:10j] | 創(chuàng)建一個增加的向量,步長為默認(rèn)值1(參見備注) |
0:9 | arange(10.)或 r_[:10.]或 r_[:9:10j] | 創(chuàng)建一個增加的向量,步長為默認(rèn)值1(參見注釋范圍) |
[1:10]' | arange(1.,11.)[:, newaxis] | 創(chuàng)建列向量 |
zeros(3,4) | zeros((3,4)) | 3x4二維數(shù)組,充滿64位浮點(diǎn)零 |
zeros(3,4,5) | zeros((3,4,5)) | 3x4x5三維數(shù)組,全部為64位浮點(diǎn)零 |
ones(3,4) | ones((3,4)) | 3x4二維數(shù)組,充滿64位浮點(diǎn)數(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)) | 隨機(jī)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.] | 在網(wǎng)格上評估函數(shù)的最佳方法 | |
[x,y]=meshgrid([1,2,4],[2,4,5]) | meshgrid([1,2,4],[2,4,5]) | |
ix_([1,2,4],[2,4,5]) | 在網(wǎng)格上評估函數(shù)的最佳方法 | |
repmat(a, m, n) | tile(a, (m, n)) | 用n份副本創(chuàng)建m a |
[a b] | concatenate((a,b),1)或者h(yuǎn)stack((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運(yùn)算符(NumPy ufunc)請參閱備注LOGICOPS |
a | b | logical_or(a,b) |
bitand(a,b) | a & b | 按位AND運(yùn)算符(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)==轉(zhuǎn)置(P(numpy))) |
conjgrad | scipy.sparse.linalg.cg | 共軛漸變求解器 |
fft(a) | fft(a) | 傅立葉變換 a |
ifft(a) | ifft(a) | 逆傅立葉變換 a |
sort(a) | sort(a) 要么 a.sort() | 對矩陣進(jìn)行排序 |
[b,I] = sortrows(a,i) | I = argsort(a[:,i]), b=a[I,:] | 對矩陣的行進(jìn)行排序 |
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
的命令,但命令help
和source
通常會列出其中函數(shù)所在的文件名。Python還有一個inspect
模塊(do import inspect
),它提供了一個getfile
經(jīng)常工作的模塊。
索引:MATLAB?使用一個基于索引,因此序列的初始元素具有索引1.Python使用基于零的索引,因此序列的初始元素具有索引0.出現(xiàn)混淆和火焰,因為每個元素都有優(yōu)點(diǎn)和缺點(diǎn)。一種基于索引的方法與常見的人類語言使用一致,其中序列的“第一”元素具有索引1.基于零的索引簡化了索引
。另見prof.dr的文本。Edsger W. Dijkstra。
范圍:在MATLAB?中,0:5
可以用作范圍文字和“切片”索引(括號內(nèi)); 然而,在Python,構(gòu)建體等0:5
可以 僅 被用作切片指數(shù)(方括號內(nèi))。因此,r_
創(chuàng)建了一些有點(diǎn)古怪的對象,以使numpy具有類似的簡潔范圍構(gòu)造機(jī)制。請注意,r_
它不像函數(shù)或構(gòu)造函數(shù)那樣
被調(diào)用,而是
使用方括號進(jìn)行 索引 ,這允許在參數(shù)中使用Python的切片語法。
邏輯運(yùn)算:&或| 在NumPy中是按位AND / OR,而在Matlab&和|中 是邏輯AND / OR。任何具有重要編程經(jīng)驗的人都應(yīng)該清楚這種差異。這兩者似乎工作原理相同,但存在重要差異。如果您使用過Matlab的&或| 運(yùn)算符,您應(yīng)該使用NumPy ufuncs logical_and / logical_or。Matlab和NumPy的&和|之間的顯著差異 運(yùn)營商是:
- 非邏輯{0,1}輸入:NumPy的輸出是輸入的按位AND。Matlab將任何非零值視為1并返回邏輯AND。例如,NumPy中的(3和4)是0,而在Matlab中,3和4都被認(rèn)為是邏輯真,而(3和4)返回1。
- 優(yōu)先級:NumPy的&運(yùn)算符優(yōu)先于<和>之類的邏輯運(yùn)算符; Matlab是相反的。
如果你知道你有布爾參數(shù),你可以使用NumPy的按位運(yùn)算符,但要注意括號,如:z =(x> 1)&(x <2)。缺少NumPy運(yùn)算符形式的logical_and和logical_or是Python設(shè)計的一個不幸結(jié)果。
重塑與線性索引:Matlab總是允許使用標(biāo)量或線性索引訪問多維數(shù)組,而NumPy則不然。線性索引在Matlab程序中很常見,例如矩陣上的find()返回它們,而NumPy的查找行為則不同。在轉(zhuǎn)換Matlab代碼時,可能需要首先將矩陣重新整形為線性序列,執(zhí)行一些索引操作然后重新整形。由于重塑(通常)會在同一存儲上生成視圖,因此應(yīng)該可以相當(dāng)有效地執(zhí)行此操作。請注意,在NumPy中重新整形使用的掃描順序默認(rèn)為'C'順序,而Matlab使用Fortran順序。如果您只是簡單地轉(zhuǎn)換為線性序列,那么這無關(guān)緊要。但是如果要從依賴于掃描順序的Matlab代碼轉(zhuǎn)換重構(gòu),那么這個Matlab代碼:z = reshape(x,3,4) 應(yīng)該變成 z = x.reshape(3,4,order=’F’).copy() 。
自定義您的環(huán)境
在MATLAB?中,可用于自定義環(huán)境的主要工具是使用您喜歡的功能的位置修改搜索路徑。您可以將此類自定義項放入MATLAB將在啟動時運(yùn)行的啟動腳本中。
NumPy,或者更確切地說是Python,具有類似的功能。
- 要修改Python搜索路徑以包含您自己的模塊的位置,請定義
PYTHONPATH
環(huán)境變量。 - 要在啟動交互式Python解釋器時執(zhí)行特定的腳本文件,請定義
PYTHONSTARTUP
環(huán)境變量以包含啟動腳本的名稱。
與MATLAB?不同,可以立即調(diào)用路徑上的任何內(nèi)容,使用Python,您需要先執(zhí)行“import”語句,以使特定文件中的函數(shù)可訪問。
例如,您可能會創(chuàng)建一個如下所示的啟動腳本(注意:這只是一個示例,而不是“最佳實(shí)踐”的聲明):
# 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
鏈接
有關(guān)另一個MATLAB?/ NumPy交叉引用,請參見http://mathesaurus.sf.net/
。
可以在主題軟件頁面中
找到用于python科學(xué)工作的廣泛工具列表。
MATLAB?和SimuLink?是The MathWorks的注冊商標(biāo)。
作者:柯廣的網(wǎng)絡(luò)日志 ? NumPy與 Matlab 比較
微信公眾號:Java大數(shù)據(jù)與數(shù)據(jù)倉庫