我有一个脚本,它读取不同的文件并在大型sdf数据库中搜索分子ID(每个大约4.0 GB)。
这个脚本的想法是将每个分子从我的原始数据库中的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()
它完美地运作,但它非常慢......对于我需要的东西来说太慢了。有没有办法以减少计算时间的方式重写此脚本?
非常感谢你。答案 0 :(得分:1)
主要问题是你有三个嵌套循环:分子文档,分子和文本解析在内循环。那味道很麻烦 - 我的意思是,quadratic complexity。你应该移动大量文件解析内部循环之外,并使用集合或字典分析。 像这样:
这样,您将对每个sdf文件进行一次解析,并且对于每个找到的分子,速度将进一步提高。
答案 1 :(得分:0)
让past_mol
成为一个集合,而不是列表。那会加快
filine[i][0:-1] not in past_mol
因为检查集合中的成员资格是O(1),所以检查列表中的成员资格是O(n)。
尽量不要一次写入一行文件。相反,在列表中保存行,将它们连接成一个字符串,然后将一次调用写入filout.write
。
通常最好不要允许函数修改全局变量。 sdf_grep
修改全局变量past_mol
。
将past_mol
添加到sdf_grep
的参数中,您明确指出sdf_grep
取决于past_mol
的存在(否则,sdf_grep
并非如此一个独立的功能)。
如果将past_mol
作为第三个参数传递给sdf_grep
,那么Python将创建一个名为past_mol
的新局部变量,该变量将指向与全局变量{{相同的对象1}}。由于该对象是一个集合而一个集合是一个可变对象,past_mol
也会影响全局变量past_mol.add(sline)
。
作为一个额外的好处,Python比全局变量更快地查找局部变量:
past_mol
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_grep
。 (“行数”是指以found
开头,以molname
结尾的行:
"$$$$"