正在分析sdf文件,性能问题

2024-10-01 15:30:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我编写了一个脚本,可以读取不同的文件并在大型sdf数据库(每个数据库大约4.0 GB)中搜索分子ID。在

这个脚本的想法是从我的原始数据库中复制id列表(大约287212个分子)中的每个分子到一个新的数据库,这样每个分子只有一个副本(在本例中,是遇到的第一个副本)

我写了这个剧本:

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()

它工作得很好,但速度很慢。。。我需要的太慢了。有没有办法重写这个脚本,以减少计算时间?在

非常感谢。在


Tags: inimport脚本数据库forfilesopen分子
2条回答

past_mol成为一个集合,而不是一个列表。那会加速的

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

因为检查集合中的成员身份是O(1),而检查列表中的成员身份是O(n)。在


尽量不要一次只写一行。相反,将行保存在一个列表中,将它们连接成一个字符串,然后用一个调用filout.write将其写出。在


通常最好不要让函数修改全局变量。sdf_grep修改全局变量{}。在

通过将past_mol添加到sdf_grep的参数中,可以明确地表明sdf_grep依赖于{}的存在(否则,sdf_grep不是真正的独立函数)。在

如果将past_mol作为第三个参数传递给sdf_grep,那么Python将生成一个名为past_mol的新局部变量,它将指向与全局变量past_mol相同的对象。因为该对象是一个集,而一个集是一个可变对象,past_mol.add(sline)也会影响全局变量{}。在

另外,Python查找局部变量的速度比全局变量快:

^{pr2}$

如果您使用一个变量(我们称之为found),它可以大大简化sdf_grep,它可以跟踪我们是否在我们想要保留的行块中。(我所说的“行块”是指以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()

主要的问题是有三个嵌套的循环:分子文档、分子和文件解析在内部循环中。听起来有点麻烦-我是说,quadratic complexity。您应该将解析大型文件移到内部循环之外,并对分子使用set或dictionary。 像这样:

  1. 对于每个sdf文件
  2. 对于每一行,如果是分子定义的话
  3. 查阅未找到的分子词典
  4. 如果存在,处理它并从字典中删除未找到的分子

通过这种方式,您将精确地解析每个sdf文件一次,并且随着每个找到的分子,速度将进一步提高。在

相关问题 更多 >

    热门问题