我认为我的代码效率太低。我猜测它与使用字符串有关,尽管我不确定。这是代码:
genome = FASTAdata[1]
genomeLength = len(genome);
# Hash table holding all the k-mers we will come across
kmers = dict()
# We go through all the possible k-mers by index
for outer in range (0, genomeLength-1):
for inner in range (outer+2, outer+22):
substring = genome[outer:inner]
if substring in kmers: # if we already have this substring on record, increase its value (count of num of appearances) by 1
kmers[substring] += 1
else:
kmers[substring] = 1 # otherwise record that it's here once
这是为了搜索长度最多为20的所有子串。现在这段代码似乎永远不会终止,所以这里有些错误。在字符串上使用[:]会导致巨大的开销吗?如果是这样,我可以用什么替换它?
为了清楚起见,有问题的文件接近200mb,非常大。
答案 0 :(得分:1)
我建议使用动态编程算法。问题是,对于所有未找到的inner
字符串,您再次使用附加的字符重新搜索它们,因此当然也找不到这些字符串。我没有考虑特定的算法,但这肯定是动态编程的一种情况,你记住你已经搜索过的内容。作为一个非常糟糕的例子,记住所有未找到的长度为1,2,3的substrings
,并且永远不会在下一次迭代中扩展这些基数,其中字符串只会更长。
答案 1 :(得分:1)
您应该使用memoryview来避免创建子字符串,因为[:]
将返回“视图”而不是副本,但是您必须使用Python 3.3或更高版本(在此之前,它们不是哈希的)。
此外,Counter会简化您的代码。
from collections import Counter
genome = memoryview("abcdefghijkrhirejtvejtijvioecjtiovjitrejabababcd".encode('ascii'))
genomeLength = len(genome)
minlen, maxlen = 2, 22
def fragments():
for start in range (0, genomeLength-minlen):
for finish in range (start+minlen, start+maxlen):
if finish <= genomeLength:
yield genome[start:finish]
count = Counter(fragments())
for (mv, n) in count.most_common(3):
print(n, mv.tobytes())
产生
4 b'ab'
3 b'jt'
3 b'ej'
我的笔记本电脑上有一个1,000,000字节的随机数组需要45秒,但2,000,000会导致交换(超过8GB内存使用)。但是,由于您的片段大小很小,您可以轻松地将问题分解为数百万个子序列,然后在最后组合结果(只需注意重叠)。这将为200MB阵列提供约3小时的总运行时间,幸运。
PS要明确的是,通过“在最后组合结果”,我假设您只需要为每个1M子序列保存最流行的,例如,将它们写入文件。你不能将计数器保留在内存中 - 这就是使用8GB的内存。如果你有数千次出现的碎片,这很好,但显然不适用于较小的数字(你可能会在每个200 1M的子序列中看到一个碎片,所以永远不要保存它,例如)。换句话说,结果将是下限 不完整,特别是在较低频率下(仅当在每个子序列中找到并记录片段时,值才完整)。如果您需要确切的结果,这是不合适的。