加快这个Python代码的大量输入

时间:2015-01-31 14:01:12

标签: python arrays loops

我编写了这个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,这是此计算的结果。因此,我想知道是否使用此约束随机填充数组,将不会填充多少条目。

显然,我并不是说这是找到这个号码的最有效方式,所以我希望如果不能加速这个代码,或许还有更好的替代方法。

2 个答案:

答案 0 :(得分: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

我们可以通过矢量化更多的计算来改进这一点,但是根据你的约束,这可能已经足够了。

答案 1 :(得分:0)

首先,我将问题从三变量重新定为双变量。你正在做的是将长度为N的矢量在随机点k处分成两个较小的矢量。

让我们假设你从一个零向量开始,然后你把'1'放在随机选择的k上,从那里取两个较小的零向量 - [0..k-2]& [k + 2 .. N-1]。不需要第三州。你重复这个过程直到筋疲力尽 - 当你留下只包含一个元素的向量时。

即使在我的带有Pythonista的iPad mini上,使用recusion也相当快。

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)

使用bitarray

解决方案收敛得非常好所以花费大约半小时寻找分析解决方案会使整个MC练习变得不必要吗?