【问题标题】:Trying to speed up python code by replacing loops with functions试图通过用函数替换循环来加速python代码
【发布时间】:2014-01-03 01:27:00
【问题描述】:

我正在尝试想出一种更快的方式来编写我想要的代码。这是我正在尝试加速的程序部分,希望使用更多内置功能:

num = 0
num1 = 0
rand1 = rand_pos[0:10]
time1 = time.clock() 
for rand in rand1:   
     for gal in gal_pos:
         num1 = dist(gal, rand)
         num = num + num1 
time2 = time.clock()
time_elap = time2-time1
print time_elap

这里,rand_pos 和 gal_pos 分别是长度为 900 和 100 万的列表。 这里 dist 是计算欧几里得空间中两点之间距离的函数。 我使用了 rand_pos 的 sn-p 来进行时间测量。 我的时间测量值约为 125 秒。这也太长了吧! 这意味着如果我在所有 rand_pos 上运行代码,大约需要三个小时! 有没有更快的方法可以做到这一点?

这里是 dist 函数:

def dist(pos1,pos2):
    n = 0
    dist_x = pos1[0]-pos2[0]
    dist_y = pos1[1]-pos2[1]
    dist_z = pos1[2]-pos2[2]
    if dist_x<radius and dist_y<radius and dist_z<radius:
        positions = [pos1,pos2]
        distance = scipy.spatial.distance.pdist(positions, metric = 'euclidean')
        if distance<radius:
            n = 1       
return n

【问题讨论】:

  • 可能,但发布实际代码,然后运行profiler 以查看导致瓶颈的原因。几乎可以肯定是你对dist 的实现应该受到责备。
  • 我们看不到 dist,这可能很重要
  • 我刚刚添加了 dist 函数@user3125280
  • 我已经在使用 pdist @BrenBarn

标签: python performance function loops


【解决方案1】:

虽然大部分优化可能需要在您的 dist 函数中进行,但这里有一些提示可以加快速度:

# Don't manually sum
for rand in rand1:
    num += sum([dist(gal, rand) for gal in gal_pos])


#If you can vectorize something, then do
import numpy as np
new_dist = np.vectorize(dist)
for rand in rand1:
    num += np.sum(new_dist(gal_pos, rand))

# use already-built code whenever possible (as already suggested)
scipy.spatial.distance.cdist(gal, rand1, metric='euclidean')

【讨论】:

    【解决方案2】:

    scipy 中有一个函数可以完全按照您的意愿进行操作:

    scipy.spatial.distance.cdist(gal, rand1, metric='euclidean')
    

    它可能比你用纯Python 编写的任何东西都要快,因为繁重的工作(循环数组之间的成对组合)是在C 中实现的。

    目前您的循环是在 Python 中发生的,这意味着每次迭代都会产生更多开销,然后您会多次调用 pdist。尽管pdist 非常优化,但对其进行如此多调用的开销会减慢您的代码速度。曾经有人用一个非常有用的类比向我描述过这种类型的性能问题:这就像试图通过电话与某人交谈,每次通话只说一个字,即使每个字都很快越过线路,但你的谈话会需要很长时间,因为您需要挂断并再次重复拨号。

    【讨论】:

    • 电话交谈的类比绝对精彩!无论如何, cdist 接受二维数组。我的列表格式如下:rand1 = [[1,2,3],[34,23,43],[23,34,23],[56,34,12]...[]]。这里每个子列表都包含一个点的 x、y 和 z 位置。我不知道如何将其表示为二维数组。
    • 我知道,我希望我能为此付出代价! RE你的问题,当然可以!只需使用arr = numpy.array(rand1)
    最近更新 更多