[英]Avoiding nested for loops in Python
我有一個尺寸為1024 * 307200
的矩陣A
和另一個尺寸為1024 * 50
矩陣B
我在嵌套的for循環中對這兩個矩陣執行L2_norm
,以使最終矩陣C
為307200 * 50
。
您可以在下面找到代碼:
for i in range(307200):
for l in range(50):
C[i,l] = numpy.linalg.norm(A[:,i] - B[:,l]))
如您所見,我的變量的維數很大,這導致非常高的延遲。 我想避免這種嵌套循環,因為對於i
和l
每個值,我都使用相同的函數。
有什么方法可以優化上述循環嗎?
也許您可以用這些矩陣運算來替換內部循環和函數?
for i in range(307200):
temp = A[:,i,np.newaxis] - B[:]
C[i,:] = np.linalg.norm(temp, axis=0)
對於較小的陣列,我的運行時間縮短了約20倍。 也許您會收獲更多。 無論如何,請確保您收到的效果不錯(使用較小的電視機)。
更新:通過OP的更新和說明,事情變得簡單得多:
>>> def f_pp(A, B):
... return np.sqrt(np.add.outer(np.einsum('ij,ij->j', A, A), np.einsum('il,il->l', B, B)) - 2*np.einsum('ij,il->jl', A, B))
...
結束更新
您可以使用np.einsum
和實數運算來大幅提高速度:
>>> def f_pp(A, B):
... Ar = A.view(float).reshape(*A.shape, 2)
... Br = B.view(float).reshape(*B.shape, 2)
... return np.sqrt(np.add.outer(np.einsum('ijk,ijk->j', Ar, Ar), np.einsum('ilk,ilk->l', Br, Br)) - 2*np.einsum('ijk,ilk->jl', Ar, Br))
...
對於形狀(1024, 3072)
和(1024, 50)
(1024, 3072)
,我得到的系數約為40
。
一些解釋:
實數運算:除非numpy進行一些令人難以置信的智能優化,否則我希望像x*x.conj()
這樣的復雜乘積使用4個實數乘法。 知道結果是真實的,我們保存其中兩個。
將|AB|^2
為|A|^2 + |B|^2 - 2|A*B|
。 這樣可以避免直接廣播方法將使用的巨大中間AB
形狀(1024, 3072, 50)
(1024, 307200, 50)
(在完整示例中為(1024, 307200, 50)
節省了內存。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.