1

このスクリプトをより速く実行するための提案はありますか? 通常、このスクリプトには 200 万から 1000 万行以上の行があります。

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

あなたのコードの意図はわかりませんが、一般的なアプローチは次のとおりです。

  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 に答える
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 に答える
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もおそらく良いでしょう。

于 2012-05-06T19:59:02.260 に答える
0

これらすべてのバリアントよりも約 2 倍高速です (少なくとも 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 に答える