[英]Speeding up this Python code for large input
我編寫了此Python代碼,以便在較大的項目中進行特定的計算,並且對於較小的N
值也可以正常工作,但是對於較大的值,即使我運行了幾個小時來收集數據,它也無法很好地擴展,我想知道是否有一種方法可以加快速度
import numpy as np
def FillArray(arr):
while(0 in arr):
ind1 = np.random.randint(0,N)
if(arr[ind1]==0):
if(ind1==0):
arr[ind1] = 1
arr[ind1+1] = 2
elif(ind1==len(arr)-1):
arr[ind1] = 1
arr[ind1-1] = 2
else:
arr[ind1] = 1
arr[ind1+1] = 2
arr[ind1-1] = 2
else:
continue
return arr
N=50000
dist = []
for i in range(1000):
arr = [0 for x in range(N)]
dist.append(Fillarr(arr).count(2))
對於N = 50,000
,當前在我的計算機上需要一分鍾多的時間才能進行一次迭代以填充陣列。 因此,如果我要模擬這個,可以說是1000次,那要花很多小時。 我可以做些什么來加快速度嗎?
編輯1:我忘記提及它的實際作用。 我有一個長度為N
的列表,並通過在每個條目中添加零來對其進行初始化。 然后,我選擇一個介於0
和N
之間的隨機數,如果列表的索引為零,則將其替換為1
並將其相鄰的索引替換為2
以指示它們未被1
填充,但無法再次填充。 我一直這樣做,直到用1
和2
填充整個列表,然后計算多少個條目包含2
,這是此計算的結果。 因此,我想找出是否使用此約束隨機填充數組,將不填充多少個條目。
顯然,我並不認為這是找到此數字的最有效方法,因此我希望,如果無法加快此代碼的速度,也許會有更好的選擇。
正如@SylvainLeroux在評論中指出的那樣,當您開始用盡零位時,試圖通過繪制隨機位置來找到要更改的零並希望其為零的方法將會變慢。 只需從您知道將為零的值中進行選擇,即可大大加快速度。 就像是
def faster(N):
# pad on each side
arr = np.zeros(N+2)
arr[0] = arr[-1] = -1 # ignore edges
while True:
# zeros left
zero_locations = np.where(arr == 0)[0]
if not len(zero_locations):
break # we're done
np.random.shuffle(zero_locations)
for zloc in zero_locations:
if arr[zloc] == 0:
arr[zloc-1:zloc+2] = [2, 1, 2]
return arr[1:-1] # remove edges
將更快(在我的舊筆記本上的時間):
>>> %timeit faster(50000)
10 loops, best of 3: 105 ms per loop
>>> %time [(faster(50000) == 2).sum() for i in range(1000)]
CPU times: user 1min 46s, sys: 4 ms, total: 1min 46s
Wall time: 1min 46s
我們可以通過對更多計算進行矢量化來改善此情況,但是根據您的約束,這可能已經足夠。
首先,我將把問題從三變量重新表述為雙變量。 您正在做的是在隨機點k處將長度為N的向量分成兩個較小的向量。
假設您從零的向量開始,然后在隨機選擇的k處放置“ 1”,然后從中選取兩個較小的零向量-[0..k-2]和[k + 2 .. N-1] 。 不需要第三狀態。 重復此過程,直到用盡為止-剩下的向量僅包含一個元素。
使用recusion,即使在帶Pythonista的iPad mini上,這也相當快。
import numpy as np
from random import randint
def SplitArray(l, r):
while(l < r):
k = randint(l, r)
arr[k] = 1
return SplitArray(l, k-2) + [k] + SplitArray(k+2, r)
return []
N = 50000
L = 1000
dist=np.zeros(L)
for i in xrange(L):
arr = [0 for x in xrange(N)]
SplitArray(0, N-1)
dist[i] = arr.count(0)
print dist, np.mean(dist), np.std(dist)
但是,如果您想使其變快,則可以非常有效且自然地將雙變量問題編碼為位數組,而不是將1和0存儲在整數數組中,或更糟糕的是將其存儲在numpy數組中。 鑽頭操作應該很快,在某些情況下,您很容易接近機器水平的速度。
大致思路:(這是一個主意,而不是最佳代碼)
from bitarray import BitArray
from random import randint
import numpy as np
def SplitArray(l, r):
while(l < r):
k = randint(l, r)
arr.set_bit(k)
return SplitArray(l, k-2) + [k] + SplitArray(k+2, r)
return []
def count0(ba):
i = 0
for n in xrange(1, N):
if ba.get_bit(n) == 0:
i += 1
return i
N = 50000
L = 1000
dist = np.zeros(L)
for i in xrange(L):
arr = BitArray(N, initialize = 0)
SplitArray(1, N)
dist[i] = count0(arr)
print np.mean(dist), np.std(dist)
使用位數組
該解決方案收斂非常好,所以也許花半小時尋找一種分析解決方案將使整個MC職位變得不必要?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.