2017-05-31 191 views
3

在Python和Matlab中,我編寫了生成矩陣並使用索引函數填充它的代碼。 Python代碼的執行時間比Matlab代碼的執行時間長大約20倍。用同樣的結果有兩個函數都寫在Python中,bWay()基於this answernumpy vs Matlab速度 - arctan和power

下面是完整的Python代碼:

import numpy as np 
from timeit import timeit 

height = 1080 
width = 1920 
heightCm = 30 
distanceCm = 70 

centerY = height/2 - 0.5; 
centerX = width/2 - 0.5; 

constPart = height * heightCm/distanceCm 

def aWay(): 
    M = np.empty([height, width], dtype=np.float64); 
    for y in xrange(height): 
     for x in xrange(width): 
      M[y, x] = np.arctan(pow((pow((centerX - x), 2) + pow((centerY - y), 2)), 0.5)/constPart) 

def bWay(): 
    M = np.frompyfunc(
     lambda y, x: np.arctan(pow((pow((centerX - x), 2) + pow((centerY - y), 2)), 0.5)/constPart), 2, 1## Heading ## 
    ).outer(
     np.arange(height), 
     np.arange(width), 
    ).astype(np.float64) 

這裏是完整的Matlab代碼:

height = 1080; 
width = 1920; 
heightCm = 30; 
distanceCm = 70; 

centerY = height/2 + 0.5; 
centerX = width/2 + 0.5; 

constPart = height * heightCm/distanceCm; 
M = zeros(height, width); 
for y = 1 : height 
    for x = 1 : width 
     M(y, x) = atan(((centerX - x)^2 + (centerY - y)^2)^0.5/constPart); 
    end 
end 

Python的執行時間timeit.timeit:

aWay() - 6.34s 
bWay() - 6.68s 

抽動TOC測量Matlab的執行時間:

0.373s 

爲了縮小範圍予測arctan,平方和循環次

的Python:

>>> timeit('arctan(3)','from numpy import arctan', number = 1000000) 
1.3365135641797679 
>>> timeit('pow(3, 2)', number = 1000000) 
0.11460829719908361 
>>> timeit('power(3, 2)','from numpy import power', number = 1000000) 
1.5427879383046275 
>>> timeit('for x in xrange(10000000): pass', number = 1) 
0.18364813832704385 

Matlab的:

tic 
for i = 1 : 1000000 
    atan(3); 
end 
toc 
Elapsed time is 0.179802 seconds. 
tic 
for i = 1 : 1000000 
    3^2; 
end 
toc 
Elapsed time is 0.044160 seconds. 
tic 
for x = 1:10000000 
end 
toc 
Elapsed time is 0.034853 seconds. 

在所有3種情況下,Python代碼執行時間延長了幾倍。

有什麼我可以做的,以改善這種python代碼的性能?

+5

您不應該矢量化MATLAB和Python/NumPy代碼的性能嗎? – Divakar

+1

比較次優(或差)解決方案的性能並不真正有趣和/或有用。請嘗試優化每個解決方案的性能,然後比較性能:) – MSeifert

+0

謝謝,我會研究它,看看時間如何比較然後 – vbajcinovci

回答

6

我只關注Python部分,以及如何優化它(從未使用MATLAB,抱歉)。

如果我理解你的代碼正確,您可以使用:

def fastway(): 
    x, y = np.ogrid[:width, :height] # you may need to swap "x" and "y" here. 
    return np.arctan(np.hypot(centerX-x, centerY-y)/constPart) 

這是矢量,應該是驚人的快。

%timeit fastway() 
# 289 ms ± 9.62 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 
%timeit aWay() 
# 28.2 s ± 243 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 
%timeit bWay() 
# 29.3 s ± 790 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 

如果你想知道:np.hypot(x, y)等同於(x**2 + y**2)**0.5。它不一定更快,但更短,在一些邊緣情況下可以得到更精確的結果。

此外,如果你需要操作標量,你不應該使用NumPy函數。 NumPy函數具有如此高的開銷,以至於處理一個元素所需的時間與處理一千個元素的時間相同,例如參見my answer on the question "Performance in different vectorization method in numpy"

+1

乾杯的人,感謝您的時間+我喜歡函數名稱 – vbajcinovci

+0

@ViliamsBajčinovci不客氣:)我不確定是否按正確的順序具有'width'和'height'。你可能需要仔細檢查一下 - 如果它們被交換了,你可以使用'y,x = np.ogrid [:width,:height]' – MSeifert

4

爲了MSeifert的回答完整,這裏是矢量Matlab代碼:

height = 1080; 
width = 1920; 
heightCm = 30; 
distanceCm = 70; 

centerY = height/2 + 0.5; 
centerX = width/2 + 0.5; 

constPart = height * heightCm/distanceCm; 
[x, y] = meshgrid(1:width, 1:height); 
M = atan(hypot(centerX-x, centerY-y)/constPart); 

在我的機器,這需要0.057秒,而雙for循環需要0.20秒。

在同一臺機器上,MSeifert的python解決方案需要0.082秒。