Python中加速双重循环

4

有没有一种方法可以加快双重循环的速度,以便从上一次迭代中更新其值?

代码示例:

def calc(N, m):
    x = 1.0
    y = 2.0
    container = np.zeros((N, 2))
    for i in range(N):
      for j in range(m):
        x=np.random.gamma(3,1.0/(y*y+4))
        y=np.random.normal(1.0/(x+1),1.0/sqrt(x+1))
      container[i, 0] = x
      container[i, 1] = y
    return container

calc(10, 5)

正如你所看到的,内循环在更新变量x和y的同时,外循环每次以不同的x值开始。我认为这不能进行向量化处理,但也许有其他可能的改进方法。

谢谢!


“第二个循环正在更新变量x和y,而第一个循环每次都以不同的x值开始” - 我不确定您的意思。特别是,“每次以不同的x值开始”,“第一个”或“第二个”循环相对于“内部”或“外部”而言不太清楚。我不完全确定哪个是哪个。 - user2357112
抱歉,我想不到比将“range”替换为“xrange”更好的解决方法。也许您应该在问题上设置赏金以吸引一个“numpy”专家。 - inspectorG4dget
抱歉,你是对的。我会更改第一个或第二个循环的内容。当我说“每次以不同的x值开始”时,我是指外部循环的第一次迭代从x = 1.0开始。但是,在内部循环中修改了x的值。因此,在外部循环的第二次迭代中,x是另一个值。 - r_31415
2个回答

1
我认为这不会带来任何重要的加速,但是如果你一次性生成所有伽马函数和正态分布随机值,你可以节省一些函数调用。
伽马函数具有缩放属性,因此,如果从伽马(k, 1)分布中绘制一个值x,那么c*x将是从伽马(k, c)分布中绘制的值。同样地,对于正态分布,您可以从正态(0, 1)分布中取出一个y值,并通过执行x*s + m将其转换为从正态(m, s)分布中取出的值。因此,您可以按以下方式重写函数:
def calc(N, m):
    x = 1.0
    y = 2.0
    container = np.zeros((N, 2))
    nm = N*m
    gamma_vals = np.random.gamma(3, 1, size=(nm,))
    norm_vals = np.random.normal(0, 1, size=(nm,))
    for i in xrange(N):
        for j in xrange(m):
            ij = i*j
            x = gamma_vals[ij] / (y*y+4)
            y = norm_vals[ij]/np.sqrt(x+1) + 1/(x+1)
        container[i, 0] = x
        container[i, 1] = y
    return container

如果您的分布的实际参数有更简单的表达式,您可能实际上能够使用一些复杂形式的np.cumprod或类似的函数,并避免使用循环。我无法想出一种这样做的方法...

不幸的是,这种方法比在内部循环中使用np.random.gamma和np.random.normal要慢2倍。也许有错误,因为它没有给出相同的结果。 - r_31415
你正在生成随机数,因此结果不同并不奇怪。即使你种子了随机数生成器,你也在不同的顺序中使用它们,所以这也是非常正常的。至于性能,如果可以消除循环,那么这将是一种巧妙的技巧,但在你的问题中似乎不可能。 - Jaime
1+. 你说得对。谢谢。你觉得没有更进一步优化的方法了吗? - r_31415

0

这个可以工作吗?

for i in xrange(N): 
   # xrange is an iterator, range makes a new list.
   # You save linear space and `malloc`ing time by doing this

    x += m*y # a simple algebra hack. Compute this line of the loop just once instead of `m` times
    y -= m*x
    y *= -1 # another simple algebra hack. Compute this line of the loop just once instead of `m` times
    container[i,0] = x
    container[i,1] = y
return container

谢谢你的回答。xrange是一个好主意。然而,代数部分并不适用于我正在尝试优化的实际循环(它涉及伽玛函数)。 - r_31415
@RobertSmith:抱歉,我现在想不出其他的了。 - inspectorG4dget

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接