快速觀察告訴我們,函數代碼中迭代之間存在數據依賴關係。現在,有不同種類的數據依賴關係。您正在查看的數據依賴性的類型是索引依賴性,即在任何迭代中的數據選擇取決於先前的迭代計算。這種依賴似乎很難在迭代之間進行追蹤,所以本文不是真正的矢量化解決方案。相反,我們會盡量預先計算將在循環中使用的值。基本的想法是在循環中做最低限度的工作。
下面是我們如何能夠帶預計算進行,因而具有更有效的解決方案的簡要說明:
考慮的p
相對較小的形狀從哪一行元素被提取基於輸入row
,您可以預先選擇p
與p[row]
中的所有行。
對於每次迭代,您正在計算一個隨機數。你可以用一個隨機數組替換它,你可以在循環之前設置它,因此,你也可以預先計算這些隨機數。
根據到目前爲止的預先計算的值,您將擁有p
中所有行的列索引。請注意,這些列索引將是一個包含所有可能的列索引的大型ndarray,而在我們的代碼中,只會根據每次迭代計算選擇一個列索引。使用每迭代列索引,您可以增加或減少X0
以獲取每次迭代輸出。
的實施應該是這樣的 -
randarr = np.random.rand(n)
p = np.array([[ 0.499, 0.419, 0.639],
[ 0.099, 0.749, 0.319]])
def play_game_partvect(row,n,randarr,p):
X0 = 100
Y0 = X0 % 3
signvals = 2*(randarr[:,None] < p[row]) - 1
col_idx = (signvals + np.arange(3)) % 3
Y = Y0
currval = X0
out = np.empty(n+1)
out[0] = X0
for j in range(n):
currval = currval + signvals[j,Y]
out[j+1] = currval
Y = col_idx[j,Y]
return out
爲針對原始代碼驗證,你會修改,像這樣的原碼 -
請注意,因爲這代碼會預先計算這些隨機值,所以這已經可以讓您對問題中的代碼加速很多。
運行測試和驗證輸出 -
In [2]: # Inputs
...: n = 1000
...: row = np.random.randint(0,2,(n))
...: randarr = np.random.rand(n)
...: p = np.array([[ 0.499, 0.419, 0.639],
...: [ 0.099, 0.749, 0.319]])
...:
In [3]: np.allclose(play_game_partvect(row,n,randarr,p),play_game(row,n,randarr,p))
Out[3]: True
In [4]: %timeit play_game(row,n,randarr,p)
100 loops, best of 3: 11.6 ms per loop
In [5]: %timeit play_game_partvect(row,n,randarr,p)
1000 loops, best of 3: 1.51 ms per loop
In [6]: # Inputs
...: n = 10000
...: row = np.random.randint(0,2,(n))
...: randarr = np.random.rand(n)
...: p = np.array([[ 0.499, 0.419, 0.639],
...: [ 0.099, 0.749, 0.319]])
...:
In [7]: np.allclose(play_game_partvect(row,n,randarr,p),play_game(row,n,randarr,p))
Out[7]: True
In [8]: %timeit play_game(row,n,randarr,p)
10 loops, best of 3: 116 ms per loop
In [9]: %timeit play_game_partvect(row,n,randarr,p)
100 loops, best of 3: 14.8 ms per loop
因此,我們看到大約7.5x+
的加速,還不錯!
如果你使用Python2,它可能會幫助一點點使用'xrange()'而不是'range()'。 – davejagoda
我正在使用Python 3. –