我有以下微小的Python方法 到目前为止 性能热点(根据我的分析器,>这里花费了95%的执行时间)在一个更大的计划中:
def topScore(self, seq):
ret = -1e9999
logProbs = self.logProbs # save indirection
l = len(logProbs)
for i in xrange(len(seq) - l + 1):
score = 0.0
for j in xrange(l):
score += logProbs[j][seq[j + i]]
ret = max(ret, score)
return ret
代码正在Python的Jython实现中运行,而不是CPython,如果这很重要的话。 seq
是一个DNA序列字符串,大约有1,000个元素。 logProbs
是一个词典列表,每个位置一个。目标是找到l
的任何长度seq
(大约10-20个元素)的最大分数。
我意识到所有这些循环由于解释开销而效率低下,并且在静态编译/ JIT语言中会快得多。但是,我不愿意切换语言。首先,我需要一个JVM语言用于我正在使用的库,这种约束我的选择。其次,我不想将此代码批量转换为较低级别的JVM语言。但是,如果有必要,我愿意用其他东西重写这个热点,虽然我不知道如何连接它或者开销会是什么。
除了这种方法的单线程缓慢之外,我还无法让程序在并行化方面超过4个CPU。鉴于它几乎把所有时间都花在我发布的10行热点上,我无法弄清楚这里的瓶颈是什么。
答案 0 :(得分:2)
它慢的原因是因为它是O(N * N)
maximum subsequence算法可以帮助您改进此
答案 1 :(得分:2)
如果为topScore
重复调用seq
,则可以memoize
其值{{1}}。
答案 2 :(得分:1)
我不知道我在做什么,但也许这有助于加快你的算法:
ret = -1e9999
logProbs = self.logProbs # save indirection
l = len(logProbs)
scores = collections.defaultdict(int)
for j in xrange(l):
prob = logProbs[j]
for i in xrange(len(seq) - l + 1):
scores[i] += prob[seq[j + i]]
ret = max(ret, max(scores.values()))
答案 3 :(得分:1)
如何在for i循环之外预先计算xrange(l)
?
答案 4 :(得分:0)
没有什么能像慢一样跳出来。我可能会像这样重写内部循环:
score = sum(logProbs[j][seq[j+i]] for j in xrange(l))
甚至:
seqmatch = zip(seq[i:i+l], logProbs)
score = sum(posscores[base] for base, posscores in seqmatch)
但我不知道要么节省很多时间。
将DNA碱基存储为整数0-3可能稍微快一些,并从元组而不是字典中查找分数。将字母翻译成数字会有性能影响,但只需要进行一次。
答案 5 :(得分:0)
绝对使用numpy并将logProbs存储为2D数组而不是字典列表。如上所述,还将seq存储为(短)整数的一维数组。如果您不必在每次调用函数时都进行这些转换,这将有所帮助(在函数内部进行这些转换不会为您节省太多)。你可以消除第二个循环:
import numpy as np
...
print np.shape(self.logProbs) # (20, 4)
print np.shape(seq) # (1000,)
...
def topScore(self, seq):
ret = -1e9999
logProbs = self.logProbs # save indirection
l = len(logProbs)
for i in xrange(len(seq) - l + 1):
score = np.sum(logProbs[:,seq[i:i+l]])
ret = max(ret, score)
return ret
之后您要做的事情取决于这两个数据元素中哪一个变化最频繁:
如果logProbs通常保持不变并且您希望通过它运行许多DNA序列,那么请考虑将DNA序列堆叠为2D阵列。 numpy可以非常快速地遍历2D阵列,所以如果你要处理200个DNA序列,它只需要比单个序列长一点。
最后,如果你真的需要加速,请使用scipy.weave。这是编写几行快速C以加速循环的一种非常简单的方法。但是,我建议使用scipy> 0.8。
答案 6 :(得分:0)
你可以尝试在循环之外提升不仅仅是self.logProbs:
def topScore(self, seq):
ret = -1e9999
logProbs = self.logProbs # save indirection
l = len(logProbs)
lrange = range(l)
for i in xrange(len(seq) - l + 1):
score = 0.0
for j in lrange:
score += logProbs[j][seq[j + i]]
if score > ret: ret = score # avoid lookup and function call
return ret
答案 7 :(得分:0)
我怀疑它会产生重大影响,但你可以尝试改变:
for j in xrange(l):
score += logProbs[j][seq[j + i]]
到
for j,lP in enumerate(logProbs):
score += lP[seq[j + i]]
甚至在seq循环之外提升枚举。