Python的NumPy优化:n维投影

3
我相对于Python比较新,希望能得到任何优化和加速此函数的想法。我必须调用它数万到数十万次以进行数字计算,而且它占据了代码整体计算时间的主要部分。我已经用C语言编写了这个函数,但是我很想看看有没有什么诀窍可以让它在Python中运行得更快。
这段代码根据http://en.wikipedia.org/wiki/Stereographic_projection,将一个长度为bigD的向量投影到一个长度为littleD的向量上。变量a是一个长度约为96的numpy数组。
import numpy as np 
def nsphere(a):
    bigD = len(a)
    littleD = 3
    temp = a
# normalize before calculating projection
    temp = temp/np.sqrt(np.dot(temp,temp))
# calculate projection
    for i in xrange(bigD-littleD + 2,2,-1 ):
        temp = temp[0:-1]/(1.0 - temp[-1])
    return temp
#USAGE:
q = np.random.rand(96)
b = nsphere(q)
print b

3
我有点困惑——在你的for循环中,你没有使用索引i。所以你只是不断地将temp除以1.0-temp[-1]很多次吗? - tpg2114
@tpg2114 - 在每次循环迭代中,temp 的大小会缩小 1,因为 [0:-1] 不包括最后一项。所以这个操作并不像你所建议的那样简单。但我同意,当 i 从未被引用时,显式控制 i 的起始和停止值是很奇怪的。 - DaveP
嗨 - 是的,i没有被使用,这确实是一种有点愚蠢的重复96-3次这个过程的方式,但事实上就是这样。我想知道每次将temp[]重新分配为一个比原来短1个元素的向量是否很慢,如果预先分配一个长度为96-3的向量列表,其长度为96、95、94...到3,会更快吗?我不知道在Python中这是如何工作的细节。 - user1850461
1个回答

2
这应该会更快:
def nsphere(a, littleD=3):
    a = a / np.sqrt(np.dot(a, a))
    z = a[littleD:].sum()
    return a[:littleD] / (1. - z)

请进行数学运算以确保这确实与您的迭代算法相同。
显然,这里的主要加速将来自于这是一个O(n)算法,它替换了您用于计算投影的O(n ** 2)算法。但是要特别加速Python中的代码,请“向量化内部循环”。也就是说,在代码的性能关键部分尽量避免循环和其他会产生高Python开销的操作,而是尝试使用高度优化的Python和Numpy内置函数。希望这可以帮到您。

@ Bi Rico - 谢谢,这的确运行得更快,但它没有计算同样的东西,并且结果不同。这必然是一个N^2问题。我需要提供更多关于如何工作的细节吗? - user1850461
如果你仔细看一下数学,我相信你会发现这与你在问题中提供的函数是相同的。我还测试了这个函数和你问题中的函数,结果是一样的。当然,如果你提供了一个简化版本的真实函数来优化,这可能并不那么有用。 - Bi Rico
好的,问题解决了。我的函数(这里没有展示,在实际代码中是我的错导致了混淆)在返回结果之前对其进行了归一化处理,而你的函数没有进行处理,我添加了一行代码来返回已经归一化的结果,现在它们在真实数据上完全一致。非常感谢您提供的解决方案,它可以根据输入数据的维度运行40~100倍更快,这对我来说非常有帮助! - user1850461

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