首页 > 解决方案 > 优化大型级联文件/循环的脚本以从文件列表中丢弃有缺陷的项目

问题描述

编辑:用真实示例替换示例文件;nbratoms将变量替换为nbrbonds.

初学者问题。

我想针对大文件(100G+)优化以下脚本。我昨天发现了 itertools 的存在,但没有任何线索。

f = open(sys.argv[1], "r")
out = open(sys.argv[2], 'w')

lines = f.read().split('\n@<TRIPOS>MOLECULE')

for i in lines: 
    ii=i.split('\n@<TRIPOS>',4) 
    header=ii[0]
    infos=header.split('\n')[2]
    nbrbonds=infos.split(' ')[2]
    if str(nbrbonds) in ii[2]:
        out.write('\n@<TRIPOS>MOLECULE'+str(i))

out.close()
f.close()

处理后的文件由串联的 200,000+ 个 MOL2 文件组成(下面的最后一个示例)。该脚本的想法是首先将输入文件拆分为由两个分隔的项目@<TRIPOS>MOLECULE(=新 MOL2 文件的第一行);然后根据以开头的行将这些项目拆分为 4个@<TRIPOS>部分(即@<TRIPOS>MOLECULE@<TRIPOS>ATOM和)。对于每个单个 MOL2 文件,我想检查标题中(第二个)位置的值是否(在每个单个 MOL2 文件中不同) @<TRIPOS>BOND@<TRIPOS>ALT_TYPE14

@<TRIPOS>MOLECULE
Z1198223644
14 14 0 0 0
USER_CHARGES

出现在单个文件的第三部分(下):

@<TRIPOS>BOND
1       1       2 1
2       2       3 1
3       2       4 1
4       2       5 1
5       5       6 ar
6       5      11 ar
 ...

如果确实如此-> 将其\n@<TRIPOS>MOLECULE作为第一行打印到输出文件(基本上只是单个 MOL2 文件的外观)。它似乎按原样工作,但我担心它太业余了。此外,我不知道如何实现一个步骤,以避免输出文件以这样的双标头标记开头

@<TRIPOS>MOLECULE@<TRIPOS>MOLECULE
Z1198223644
...

欢迎任何帮助!我加入了一个包含 6 个串联 MOL2 文件的文件奇数文件是正确的;甚至文件- 错误。

@<TRIPOS>MOLECULE
Z1198223644
14 14 0 0 0
USER_CHARGES
@<TRIPOS>ATOM
  1 F1         23.5932    2.0831  -52.2012 F      1 LIG      -0.15900
  2 C2         22.4195    1.3866  -52.4217 C.3    1 LIG       0.88300
  3 F3         22.5324    0.1265  -51.8643 F      1 LIG      -0.15900
  4 F4         21.3805    2.0570  -51.7993 F      1 LIG      -0.15900
  5 C5         22.1912    1.2555  -53.9016 C.ar   1 LIG       0.04500
  6 C6         21.0466    1.7681  -54.5284 C.ar   1 LIG      -0.13400
  7 C7         20.8964    1.6126  -55.9046 C.ar   1 LIG      -0.19400
  8 C8         21.8881    0.9505  -56.6271 C.ar   1 LIG       0.20700
  9 O9         21.7710    0.7997  -57.8724 O.2    1 LIG      -0.49500
 10 N10        22.9825    0.4691  -55.9778 N.ar   1 LIG       0.11300
 11 N11        23.1254    0.6186  -54.6592 N.ar   1 LIG      -0.68800
 12 H12        20.2773    2.2819  -53.9665 H      1 LIG       0.21400
 13 H13        20.0176    2.0033  -56.4027 H      1 LIG       0.20000
 14 H14        23.7285   -0.0277  -56.5143 H      1 LIG       0.32600
@<TRIPOS>BOND
  1       1       2 1
  2       2       3 1
  3       2       4 1
  4       2       5 1
  5       5       6 ar
  6       5      11 ar
  7       6       7 ar
  8       7       8 ar
  9       8       9 2
 10       8      10 ar
 11      10      11 ar
 12       6      12 1
 13       7      13 1
 14      10      14 1
@<TRIPOS>ALT_TYPE
CGenFF_4.0_ALT_TYPE_SET
CGenFF_4.0 1 FGA3 2 CG302 3 FGA3 4 FGA3 5 CG2R62 6 CG2R62 7 CG2R62 8 CG2R63 9 OG2D4 10 NG2R61 11 NG2R62 12 HGR62 13 HGR62 14 HGP1

标签: pythonsplititertools

解决方案


对于文件行的内存有效读取(即拆分\n或特定于操作系统的行结尾),您可以使用:

with open(sys.argv[1], "r") as f, open(sys.argv[2], 'w') as out:
    for i in f:
        ...

但你需要拆分'\n@<TRIPOS>MOLECULE',所以我建议创建你自己的生成器(一个函数yield)来生成 MOLECULE 块,只将 1 个块加载到内存中(懒惰读取大文件,而不是使用贪婪read()):

def mol_reader(file_stream):
    chunk = []
    for line in file_stream:
        line = line.strip()
        if line == "@<TRIPOS>MOLECULE":
            if chunk:
                yield chunk
            chunk = []
        else:
            chunk.append(line)
    yield chunk


with open(sys.argv[1], "r") as f, open(sys.argv[2], 'w') as out:
    for mol_file in mol_reader(f):
        ...

例如https://repl.it/@PeterAprillion/chunk-iterator


推荐阅读