繁体   English   中英

加速此Python代码以进行大输入

[英]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的列表,并通过在每个条目中添加零来对其进行初始化。 然后,我选择一个介于0N之间的随机数,如果列表的索引为零,则将其替换为1并将其相邻的索引替换为2以指示它们未被1填充,但无法再次填充。 我一直这样做,直到用12填充整个列表,然后计算多少个条目包含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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM