如何使这个结束修剪python脚本更快?

时间:2012-05-06 19:41:26

标签: python trim

有什么建议让这个脚本运行得更快?对于这个脚本,我通常有两到一千万行。

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 个答案:

答案 0 :(得分: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))。也不知道它会有多快。

答案 1 :(得分:3)

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

  1. 避免不必要的操作,条件等。
  2. 将所有可能的东西移出循环。
  3. 尝试尽可能少的循环级别。
  4. 尽可能使用常见的Python实践(通常效率更高)。
  5. 但最重要的是:尝试简化和优化算法,而不一定是实现它的代码。

    从代码判断并应用上述一些规则代码可能如下所示:

    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
    

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:0)

比所有theese变种快两倍(至少在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]''.join(('>\n',line_1[:-i],'\n'))(当然,在没有查找的版本中)。我不知道什么对你最好。 这很奇怪,但我的计算机上的新格式化程序'{}'.format(..)显示最慢的结果。