![](/img/trans.png)
[英]Matrix multiplication of (n,n,M) and (n,n) matrix in numpy Python
[英]Python `expm` of an `(N,M,M)` matrix
設A
是(N,M,M)
矩陣( N
非常大),我想為n in range(N)
每個n in range(N)
計算scipy.linalg.expm(A[n,:,:])
。 我當然可以使用for
循環,但我想知道是否有一些技巧以更好的方式執行此操作(類似於np.einsum
)。
我對其他操作有相同的問題,例如反轉矩陣(反饋在注釋中解決)。
根據矩陣的大小和結構,您可以做得比循環更好。
假設您的矩陣可以對角化為A = VDV^(-1)
(其中D
在其對角線上具有特征值, V
包含相應的特征向量作為列),您可以將矩陣指數計算為
exp(A) = V exp(D) V^(-1)
其中exp(D)
只包含對角線中每個特征值lambda
exp(lambda)
。 如果我們使用指數函數的冪級數定義,這很容易證明。 如果矩陣A
是正常的,則矩陣V
是單一的,因此可以通過簡單地取其伴隨來計算其逆。
好消息是numpy.linalg.eig
和numpy.linalg.inv
都可以正常使用堆疊矩陣:
import numpy as np
import scipy.linalg
A = np.random.rand(1000,10,10)
def loopy_expm(A):
expmA = np.zeros_like(A)
for n in range(A.shape[0]):
expmA[n,...] = scipy.linalg.expm(A[n,...])
return expmA
def eigy_expm(A):
vals,vects = np.linalg.eig(A)
return np.einsum('...ik, ...k, ...kj -> ...ij',
vects,np.exp(vals),np.linalg.inv(vects))
請注意,在指定einsum
調用中的操作順序時,可能還有一些優化einsum
,但我沒有對此進行調查。
測試上面的隨機數組:
In [59]: np.allclose(loopy_expm(A),eigy_expm(A))
Out[59]: True
In [60]: %timeit loopy_expm(A)
824 ms ± 55.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [61]: %timeit eigy_expm(A)
138 ms ± 992 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
那已經很好了。 如果你足夠幸運,你的矩陣都是正常的(例如,因為它們是真正對稱的):
A = np.random.rand(1000,10,10)
A = (A + A.transpose(0,2,1))/2
def eigy_expm_normal(A):
vals,vects = np.linalg.eig(A)
return np.einsum('...ik, ...k, ...jk -> ...ij',
vects,np.exp(vals),vects.conj())
注意輸入矩陣的對稱定義和einsum
模式內的轉置。 結果:
In [80]: np.allclose(loopy_expm(A),eigy_expm_normal(A))
Out[80]: True
In [79]: %timeit loopy_expm(A)
878 ms ± 89.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [80]: %timeit eigy_expm_normal(A)
55.8 ms ± 868 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
對於上面的示例形狀,這是15倍的加速。
應該注意的是, scipy.linalg.eigm
根據文檔使用Padé近似。 這可能意味着如果你的矩陣是病態的,那么特征值分解可能會產生與scipy.linalg.eigm
不同的結果。 我不熟悉這個功能如何工作,但我希望它對病理輸入更安全。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.