0

さまざまなファイルを読み取り、大きな sdf データベース (それぞれ約 4.0 GB) で分子 ID を検索するスクリプトを作成しました。

このスクリプトのアイデアは、id のリスト (約 287212 分子) からすべての分子を元のデータベースから新しいデータベースにコピーして、各分子のコピーを 1 つだけ持つようにすることです (この場合、最初に検出されたコピー)。

私はこのスクリプトを書きました:

import re
import sys
import os

def sdf_grep (molname,files):
    filin = open(files, 'r')
    filine= filin.readlines()
    for i in range(0,len(filine)):
        if filine[i][0:-1] == molname and filine[i][0:-1] not in past_mol:
            past_mol.append(filine[i][0:-1])
            iterate = 1
            while iterate == 1:
                if filine[i] == "$$$$\n":
                    filout.write(filine[i])
                    iterate = 0
                    break
                else:
                    filout.write(filine[i])
                i = i+1
        else:
            continue
    filin.close()

mol_dock = os.listdir("test")
listmol = []
past_mol = []
imp_listmol = open("consensus_sorted_surflex.txt", 'r')
filout = open('test_ini.sdf','wa')

for line in imp_listmol:
    listmol.append(line.split('\t')[0])
print 'list ready... reading files'
imp_listmol.close()

for f in mol_dock:
    print 'reading '+f
    for molecule in listmol:
        if molecule not in past_mol:
            sdf_grep(molecule , 'test/'+f) 

print len(past_mol)
filout.close()

それは完全に機能しますが、非常に遅いです...必要なものには遅すぎます。計算時間を短縮できる方法でこのスクリプトを書き直す方法はありますか?

どうもありがとうございます。

4

2 に答える 2

1

past_molリストではなくセットにしましょう。そりゃ加速するわ

filine[i][0:-1] not in past_mol

セット内のメンバーシップのチェックは O(1) であるのに対し、リスト内のメンバーシップのチェックは O(n) であるためです。


一度に 1 行ずつファイルに書き込まないようにしてください。代わりに、行をリストに保存し、それらを 1 つの文字列に結合してから、 1 回の呼び出しで書き出しますfilout.write


一般に、関数がグローバル変数を変更できないようにする方がよいでしょう。sdf_grepグローバル変数を変更しますpast_mol

past_molの引数に追加することで、 の存在に依存sdf_grepすることを明示的にします(それ以外の場合は、実際にはスタンドアロン関数ではありません)。sdf_greppast_molsdf_grep

past_molに 3 番目の引数として渡すと、Python は、グローバル変数と同じオブジェクトを指すsdf_grep名前の新しいローカル変数を作成します。そのオブジェクトはセットであり、セットは可変オブジェクトであるため、グローバル変数にも影響します。past_molpast_molpast_mol.add(sline)past_mol

追加のボーナスとして、Python はローカル変数をグローバル変数よりも高速に検索します。

def using_local():
    x = set()
    for i in range(10**6):
        x

y = set
def using_global():
    for i in range(10**6):
        y

In [5]: %timeit using_local()
10 loops, best of 3: 33.1 ms per loop

In [6]: %timeit using_global()
10 loops, best of 3: 41 ms per loop

sdf_grepfound保持したい行のチャンクの 1 つに含まれているかどうかを追跡する変数 ( と呼びましょう) を使用すると、大幅に簡略化できます。(「行のチャンク」とは、で始まり、molnameで終わるものを意味します"$$$$"):

import re
import sys
import os

def sdf_grep(molname, files, past_mol):
    chunk = []
    found = False
    with open(files, 'r') as filin:
        for line in filin:
            sline = line.rstrip()
            if sline == molname and sline not in past_mol:
                found = True
                past_mol.add(sline)
            elif sline == '$$$$':
                chunk.append(line)                
                found = False
            if found:
                chunk.append(line)
    return '\n'.join(chunk)


def main():
    past_mol = set()
    with open("consensus_sorted_surflex.txt", 'r') as imp_listmol:
        listmol = [line.split('\t')[0] for line in imp_listmol]
        print 'list ready... reading files'

    with open('test_ini.sdf', 'wa') as filout:
        for f in os.listdir("test"):
            print 'reading ' + f
            for molecule in listmol:
                if molecule not in past_mol:
                    filout.write(sdf_grep(molecule, os.path.join('test/', f), past_mol))

        print len(past_mol)

if __name__ == '__main__':
    main()
于 2013-04-02T13:26:34.357 に答える
1

主な問題は、3 つのネストされたループがあることです:内部ループでの分子ドキュメント、分子、およびファイルの解析です。それは問題の匂いがします - つまり、二次複雑度です。巨大なファイルの解析を内側のループの外に移動し、分子にはセットまたは辞書を使用する必要があります。このようなもの:

  1. SDF ファイルごとに
  2. 行ごとに、分子定義なら
  3. 未知の分子の辞書をチェック
  4. 存在する場合は、それを処理し、未知の分子の辞書から削除します

このようにして、各 sdf ファイルを正確に 1 回解析し、見つかった分子ごとに速度がさらに向上します。

于 2013-04-02T13:48:58.210 に答える