1

有什么建议可以让这个脚本运行得更快吗?这个脚本我通常有两到千万行。

while True:
    line=f.readline()
    if not line:break
    linker='CTGTAGGCACCATCAAT'
    line_1=line[:-1]
    for i in range(len(linker)):
        if line_1[-i:]==linker[:i]:
            new_line='>\n'+line_1[:-i]+'\n'
            seq_1.append(new_line_1)
            if seq_2.count(line)==0:
                seq_2.append(line)
            else:pass
        else:pass
4

4 回答 4

3

首先,您似乎在内循环中创建了许多字符串对象。您可以先尝试构建前缀列表:

linker = 'CTGTAGGCACCATCAAT'
prefixes = []
for i in range(len(linker)):
    prefixes.append(linker[:i])

此外,您可以使用string' 方法endswith而不是在内循环的条件中创建新对象:

while True:
    line=f.readilne()
    if not line:
        break
    for prefix in prefixes:
        if line_1.endswith(prefix):
             new_line='>\n%s\n' % line_1[:-len(prefix)]
             seq_1.append(new_line_1)
             if seq_2.count(line)==0:
                 seq_2.append(line)  

我不确定那里的索引(例如len(prefix))。也不知道能快多少。

于 2012-05-06T19:58:21.870 回答
3

我不确定您的代码是做什么的,但一般方法是:

  1. 避免不必要的操作、条件等。
  2. 将所有可能的东西移出循环。
  3. 尝试做尽可能少的循环级别。
  4. 尽可能使用常见的 Python 实践(它们通常更有效)。

但最重要的是:尽量简化和优化算法,不一定是实现它的代码。

从代码来看,应用上面的一些规则,代码可能是这样的:

seq_2 = set()  # seq_2 is a set now (maybe seq_1 should be also?)
linker = 'CTGTAGGCACCATCAAT'  # assuming same linker for every line
linker_range = range(len(linker))  # result of the above assumption
for line in f:
    line_1=line[:-1]
    for i in linker_range:
        if line_1[-i:] == linker[:i]:
            # deleted new_line_1
            seq_1.append('>\n' + line_1[:-i] + '\n')  # do you need this line?
            seq_2.add(line)  # will ignore if already in set
于 2012-05-06T20:04:20.667 回答
2

问题的很大一部分可能是seq_2.count(line) == 0测试是否lineseq_2. 这将遍历每个元素seq_2并测试它是否等于line- 随着增长,这将花费越来越长的时间seq_2。您应该改用一个集合,这将为您提供恒定时间测试,以确定它是否通过散列存在。这将丢弃seq_2- 如果您需要保持顺序,您可以同时使用集合和列表(测试它是否在集合中,如果不在,则添加到两者中)。

这可能不会影响速度,但是循环for line in f而不是while True循环line = f.readline()和测试何时中断要好得多。此外,这些else: pass语句是完全不必要的,可以删除。

的定义linker应该移到循环之外,因为它不会被改变。@uhz 关于预构建前缀和使用的建议endswith也可能很好。

于 2012-05-06T19:59:02.260 回答
0

比所有这些变体快大约两倍(至少在 python 2.7.2 上)

seq_2 = set()
# Here I use generator. So I escape .append lookup and list resizing
def F(f):
    # local memory
    local_seq_2 = set()
    # lookup escaping
    local_seq_2_add = local_seq_2.add
    # static variables
    linker ='CTGTAGGCACCATCAAT'
    linker_range = range(len(linker))
    for line in f:
        line_1=line[:-1]
        for i in linker_range:
            if line_1[-i:] == linker[:i]:
                local_seq_2_add(line)
                yield '>\n' + line_1[:-i] + '\n'
    # push local memory to the global
    global seq_2
    seq_2 = local_seq_2
# here we consume all data
seq_1 = tuple(F(f))

是的,它丑陋且非pythonic,但它是完成这项工作的最快方法。

您还可以使用with open('file.name') as f:内部生成器升级此代码或添加一些其他逻辑。

注意:这个地方'>\n' + line_1[:-i] + '\n'- 值得怀疑。在某些机器上,这是连接字符串的最快方法。在某些机器上,最快的方法是 '>\n'%s'\n'%line_1[:-i]or ''.join(('>\n',line_1[:-i],'\n'))(当然,在没有查找的版本中)。我不知道什么对你最好。这很奇怪,但'{}'.format(..)我电脑上的新格式化程序显示最慢的结果。

于 2012-05-07T00:02:58.750 回答