为大输入加速此Python代码
我写这段Python代码是为了在一个更大的项目中进行一个特定的计算,它对为大输入加速此Python代码,python,arrays,loops,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] =
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=50000
,目前在我的计算机上,一次迭代填充数组需要略多于一分钟的时间。所以如果我想模拟这个,比方说,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
会快得多(在我的旧笔记本上的次数):
我们可以通过矢量化更多的计算来改进这一点,但根据您的约束条件,这可能已经足够了 首先,我将把这个问题从三变量重新表述为二变量。你要做的是把长度为N的向量在随机点k分成两个更小的向量 让我们假设你从一个零向量开始,然后把“1”放在随机选择的k上,从那里取两个更小的零向量-[0..k-2]&[k+2..N-1]。不需要第三状态。你重复这个过程直到精疲力竭-当你剩下的向量只包含一个元素 使用recusion,即使在我的iPad mini上使用Pythonista,速度也相当快
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)
将numpy导入为np
从随机导入randint
def拆分阵列(左、右):
而(l
然而,如果您想让它变得非常快,那么二元问题可以非常有效地自然地编码为位数组,而不是在整数数组中存储1和0,或者在numpy数组中存储更糟糕的浮点。钻头操纵应该很快,在某些情况下,你可以很容易地接近机器水平的速度
大致如下:(这是一个想法,不是最佳代码)
从bitarray导入bitarray
从随机导入randint
将numpy作为np导入
def拆分阵列(左、右):
而(l
使用
解决方案收敛得非常好,因此,也许花半个小时寻找分析解决方案会使整个MC练习变得不必要?那么它应该做什么呢?据我所知,当数组中有0时,你需要一个随机索引,希望它将是0值的索引,从而将其更改为其他值。显然,这不能很好地扩展…@SylvainLeroux抱歉,我忘了在代码中解释我在做什么。我已经在编辑1中解释过了,这是有道理的。我应该在数组被填充时减小它的大小,然后在进一步的迭代中只填充数组的其余部分。每次检查整个阵列肯定会减慢速度。你能给我一些关于进一步矢量化的提示吗?因为它可能对我的其他项目有所帮助。@Karan:完整的故事太长了,无法在这里的评论中解释(numpy教程将介绍它),但基本上,Python循环比以C速度作用于numpy数组的numpy方法慢得多。事实上,速度足够慢,因此有时值得以C速度进行额外的工作,以避免Python循环。通过一些工作,我们可以在零位置删除zloc的
:
循环,但要确保我们仍然得到正确的统计数据,还需要一些思考。我很懒。:-)不过,有时使用pypy或numba可以帮助处理此类算法代码。我将做一些尝试,看看是否可以正确删除for
循环,并检查pypy和numba。再次感谢您的帮助:)
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)
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)