如何在文件中保存列具有相同值的所有行

时间:2015-02-16 23:54:42

标签: python

我写了一个python脚本,它从CIF文件生成一个字典。我用像[1qpe这样的文件测试了它,有4105行 - >时间:383毫秒(毫秒)]或这个(1d66,有3274行 - >时间:225毫秒),但是当我尝试使用这个(4tvx,170925行)时,需要一个很长一段时间,我决定阻止这个过程。我当时想要拆分CIF文件,从中推断出以ATOM和HETATM开头的行:

实际上,从每个原始CIF文件开始,目的是获得4个文件,最初是:

  1. 包含我称之为header的文件=以ATOM和HETATM开头的行循环上方的所有行
  2. 包含循环的仅26行的文件
  3. 包含以ATOM和HETATM
  4. 开头的所有行的文件
  5. 包含所有剩余行的文件,我称之为页脚
  6. 在这里我解决了,1d66需要34ms,1qpe需要43ms,4tvx需要1.923s。 现在,得到了第三个文件(所有这个过程的目标,因为是字典的输入),我想从它中推断出具有相同第七列的所有行,将它们写在保存有值的专用文件中第7列作为文件名,对第7列的所有值重复此操作。

    这是我的代码:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import sys, os
    import os.path
    scriptdir = os.path.dirname(os.path.abspath(__file__))
    cif_dir = os.path.join(scriptdir, 'cif/')
    
    def get_line_number(phrase, file_name):
        with open(file_name) as f:
            for i, line in enumerate(f, 1):
                if phrase in line:
                    return i
    
    def my_header_splitfile(infilepath, chunksize):
        fname, ext = infilepath.rsplit('.',1)
        with open(infilepath) as infile:
            outfilepath = "{}_header.{}".format(fname, ext)
            with open(outfilepath, 'w') as outfile:
                for line in (infile.readline() for _ in range(0,(chunksize-2))):
                    outfile.write(line) # END
        temp_lines = open(infilepath).readlines()
        temp_outfilepath = "{}_temp.{}".format(fname, ext)
        atom_hetatm_header_outfilepath = "{}_atom_hetatm_header.{}".format(fname, ext)
        with open(atom_hetatm_header_outfilepath, 'w') as outfile:
            outfile.writelines(temp_lines[(chunksize-2):(chunksize+25)])
        with open(temp_outfilepath, 'w') as outfile:
            outfile.writelines(temp_lines[(chunksize+25):-1]) # END
        footer_lines = open(temp_outfilepath).readlines()
        footer_outfilepath = "{}_footer.{}".format(fname, ext)
        with open(footer_outfilepath, 'w') as outfile:
            for line in footer_lines:
                if not (line.startswith('ATOM') or line.startswith('HETATM')):
                    outfile.writelines(line) # END
        temp_atom_hetatm_lines = open(temp_outfilepath).readlines()
        temp_atom_hetatm_outfilepath = "{}_atom_hetatm.{}".format(fname, ext)
        with open(temp_atom_hetatm_outfilepath, 'w') as outfile:
            for line in temp_atom_hetatm_lines:
                if (line.startswith('ATOM') or line.startswith('HETATM')):
                    outfile.writelines(line) # END
        os.remove(temp_outfilepath) # FINISH
        """BEGIN TO SPLIT THE 'ATOM'"""
        """
        with open(temp_atom_hetatm_outfilepath,'r') as infile:
            lines = infile.readlines()
    
            rows_list = list()
            chains_list = list()
            for line in lines:
                col = line.split(None)
                rows_list.append(col)
                #print line
                #if col[0] == "HETATM":
                #   print "HETATM record"
                if col[0] == "ATOM":
                    #print col[0]
                    # FILTER FOR ONLY PROTEINS AND NUCLEIC ACIDS
                    if (col[3] == "N" or col[3] == "N1"):
                        chains_list.append(col[6])
                        chains_list_cleaned = list(set(chains_list))
                        for chain in chains_list_cleaned:
                            if col[6] == chain:
                                atom_chain_outfilepath = "{}_atom_chain_{}.{}".format(fname, chain, ext)
                                with open(atom_chain_outfilepath, 'w') as outfile:
                                    #outfile.writelines("Hello")
                                    outfile.writelines(line) # END
        """
    
    cif_code = '1d66'.upper() # CHANGE HERE THE PID CODE. i.e. 1D66, 1QPE, 4TVX
    
    filename = '%s%s.cif' % (cif_dir,cif_code.upper())
    
    begin_atom = get_line_number("_atom_site.group_PDB", filename)
    #print begin_atom
    my_header_splitfile(filename, begin_atom)
    

    如果取消注释最后一行:

    """ with open(temp_atom_hetatm_outfilepath,'r') as infile:
            lines = infile.readlines()
    
            rows_list = list()
            chains_list = list()
            for line in lines:
                col = line.split(None)
                rows_list.append(col)
                #print line
                #if col[0] == "HETATM":
                #   print "HETATM record"
                if col[0] == "ATOM":
                    #print col[0]
                    # LIMITO ALLE SOLE PROTEINE E ACIDI NUCLEICI
                    if (col[3] == "N" or col[3] == "N1"):
                        chains_list.append(col[6])
                        chains_list_cleaned = list(set(chains_list))
                        for chain in chains_list_cleaned:
                            if col[6] == chain:
                                atom_chain_outfilepath = "{}_atom_chain_{}.{}".format(fname, chain, ext)
                                with open(atom_chain_outfilepath, 'w') as outfile:
                                    #outfile.writelines("Hello")
                                    outfile.writelines(line) # END
    """
    

    您将看到我可以为每个链保存一个文件(例如,生成的' 1d66_atom_hetatm.cif'文件中的第七列),但在每个文件中只写入一行,而不是全部该链的线(第七列)。怎么做到这一点?

    谢谢,

    的Riccardo

    编辑1: 您只需要使用下载的cif文件更改第72行来测试它!

    ============================================ ========================== =============================================== =======================

    编辑2: 这是生成的" 1D66_atom_hetatm.cif"中的内容示例:

    ATOM   378  C  C8    . DG  A 1 19 ? 34.329 11.346 27.800 1.00 29.46 ? ? ? ? ? ? 19  DG  D C8    1 
    ATOM   379  N  N7    . DG  A 1 19 ? 34.046 11.420 26.537 1.00 31.63 ? ? ? ? ? ? 19  DG  D N7    1 
    ATOM   380  C  C5    . DG  A 1 19 ? 32.698 11.672 26.542 1.00 26.85 ? ? ? ? ? ? 19  DG  D C5    1 
    ATOM   381  C  C6    . DG  A 1 19 ? 31.860 11.863 25.447 1.00 26.53 ? ? ? ? ? ? 19  DG  D C6    1 
    ATOM   382  O  O6    . DG  A 1 19 ? 32.175 11.864 24.251 1.00 32.03 ? ? ? ? ? ? 19  DG  D O6    1 
    ATOM   383  N  N1    . DG  A 1 19 ? 30.569 12.079 25.868 1.00 23.18 ? ? ? ? ? ? 19  DG  D N1    1 
    ATOM   384  C  C2    . DG  A 1 19 ? 30.136 12.115 27.159 1.00 23.53 ? ? ? ? ? ? 19  DG  D C2    1 
    ATOM   385  N  N2    . DG  A 1 19 ? 28.819 12.261 27.325 1.00 19.29 ? ? ? ? ? ? 19  DG  D N2    1 
    ATOM   386  N  N3    . DG  A 1 19 ? 30.949 11.949 28.200 1.00 26.27 ? ? ? ? ? ? 19  DG  D N3    1 
    ATOM   387  C  C4    . DG  A 1 19 ? 32.213 11.729 27.819 1.00 25.75 ? ? ? ? ? ? 19  DG  D C4    1 
    ATOM   388  O  "O5'" . DC  B 2 1  ? 20.466 11.694 21.639 1.00 40.14 ? ? ? ? ? ? 20  DC  E "O5'" 1 
    ATOM   389  C  "C5'" . DC  B 2 1  ? 21.891 11.609 21.791 1.00 29.52 ? ? ? ? ? ? 20  DC  E "C5'" 1 
    ATOM   390  C  "C4'" . DC  B 2 1  ? 22.246 11.659 23.274 1.00 28.85 ? ? ? ? ? ? 20  DC  E "C4'" 1 
    ATOM   391  O  "O4'" . DC  B 2 1  ? 23.643 11.328 23.562 1.00 27.78 ? ? ? ? ? ? 20  DC  E "O4'" 1 
    ATOM   392  C  "C3'" . DC  B 2 1  ? 22.093 13.078 23.713 1.00 26.83 ? ? ? ? ? ? 20  DC  E "C3'" 1 
    ATOM   393  O  "O3'" . DC  B 2 1  ? 21.761 13.021 25.064 1.00 26.10 ? ? ? ? ? ? 20  DC  E "O3'" 1 
    ATOM   394  C  "C2'" . DC  B 2 1  ? 23.541 13.575 23.586 1.00 27.66 ? ? ? ? ? ? 20  DC  E "C2'" 1 
    ATOM   395  C  "C1'" . DC  B 2 1  ? 24.295 12.435 24.176 1.00 21.82 ? ? ? ? ? ? 20  DC  E "C1'" 1 
    

    我想在1d66_A.txt文件中保存第7列中的A(从0开始),以及1d66_B.txt文件中第7列中包含B的所有行,依此类推从脚本生成的该文件的第七列的值。

    最终输出应为:

    文件1D66_A.txt:

    ATOM   378  C  C8    . DG  A 1 19 ? 34.329 11.346 27.800 1.00 29.46 ? ? ? ? ? ? 19  DG  D C8    1 
    ATOM   379  N  N7    . DG  A 1 19 ? 34.046 11.420 26.537 1.00 31.63 ? ? ? ? ? ? 19  DG  D N7    1 
    ATOM   380  C  C5    . DG  A 1 19 ? 32.698 11.672 26.542 1.00 26.85 ? ? ? ? ? ? 19  DG  D C5    1 
    ATOM   381  C  C6    . DG  A 1 19 ? 31.860 11.863 25.447 1.00 26.53 ? ? ? ? ? ? 19  DG  D C6    1 
    ATOM   382  O  O6    . DG  A 1 19 ? 32.175 11.864 24.251 1.00 32.03 ? ? ? ? ? ? 19  DG  D O6    1 
    ATOM   383  N  N1    . DG  A 1 19 ? 30.569 12.079 25.868 1.00 23.18 ? ? ? ? ? ? 19  DG  D N1    1 
    ATOM   384  C  C2    . DG  A 1 19 ? 30.136 12.115 27.159 1.00 23.53 ? ? ? ? ? ? 19  DG  D C2    1 
    ATOM   385  N  N2    . DG  A 1 19 ? 28.819 12.261 27.325 1.00 19.29 ? ? ? ? ? ? 19  DG  D N2    1 
    ATOM   386  N  N3    . DG  A 1 19 ? 30.949 11.949 28.200 1.00 26.27 ? ? ? ? ? ? 19  DG  D N3    1 
    ATOM   387  C  C4    . DG  A 1 19 ? 32.213 11.729 27.819 1.00 25.75 ? ? ? ? ? ? 19  DG  D C4    1 
    

    文件1D66_B.txt:

    ATOM   388  O  "O5'" . DC  B 2 1  ? 20.466 11.694 21.639 1.00 40.14 ? ? ? ? ? ? 20  DC  E "O5'" 1 
    ATOM   389  C  "C5'" . DC  B 2 1  ? 21.891 11.609 21.791 1.00 29.52 ? ? ? ? ? ? 20  DC  E "C5'" 1 
    ATOM   390  C  "C4'" . DC  B 2 1  ? 22.246 11.659 23.274 1.00 28.85 ? ? ? ? ? ? 20  DC  E "C4'" 1 
    ATOM   391  O  "O4'" . DC  B 2 1  ? 23.643 11.328 23.562 1.00 27.78 ? ? ? ? ? ? 20  DC  E "O4'" 1 
    ATOM   392  C  "C3'" . DC  B 2 1  ? 22.093 13.078 23.713 1.00 26.83 ? ? ? ? ? ? 20  DC  E "C3'" 1 
    ATOM   393  O  "O3'" . DC  B 2 1  ? 21.761 13.021 25.064 1.00 26.10 ? ? ? ? ? ? 20  DC  E "O3'" 1 
    ATOM   394  C  "C2'" . DC  B 2 1  ? 23.541 13.575 23.586 1.00 27.66 ? ? ? ? ? ? 20  DC  E "C2'" 1 
    ATOM   395  C  "C1'" . DC  B 2 1  ? 24.295 12.435 24.176 1.00 21.82 ? ? ? ? ? ? 20  DC  E "C1'" 1 
    

    我试图以最好的方式解释自己,抱歉,谢谢你的帮助。

    这些步骤是连接起来的,所以我不能分割脚本:你可以尝试一下......问题只是我想要获得编辑2中所说的内容,即阅读第6列(从0开始,在那里读取AAAAAAABBBBBB,在该示例中),将包含A的所有行复制到名为" 1d66_A.txt"的文件中。以及包含B的所有行,在另一个文本文件" 1d66_B.txt"中,就像编辑2.要测试我所做的,只需将该脚本复制并粘贴到带有扩展名的文本文件中。 py(例如my_script.py);在该脚本的同一文件夹中,创建一个文件夹" cif"并从这些链接下载一个cif文件(例如,如果你不想编辑脚本的第72行,则为1d66);最后使用命令" python my_script.py"在shell中运行脚本。 (我使用Linux):该脚本生成四个文件。在本主题中,我将自己引用到生成的" 1d66_atom_hetatm.cif"文件,我想按照我的说法拆分," 1d66_A.txt"," 1d66_B.txt"," 1d66_C.txt"," 1d66_D .TXT" (4个文件,因为在1d66中,以ATOM开头的所有行的第6列(从0开始)有4个不同的字母),例如 EDIT 2

    ============================================ ========================== =============================================== =======================

    编辑3 - @qwwqwwq

    我会尝试用文字来解释剧本;假设这个序列:

      

    HHHHH LLLLL的 AAAAA BBBBB的 FFFFF

    这是一个CIF文件的起点和终点的方案,我已经对我做过,在cthon文件合理化之前在python中详细说明,其中:

    H = header
    L = loop for ATOM and HETATM rows
    A = chain A (= column 7) in ATOM 
    B = chain B (= column 7) in ATOM 
    F = footer
    

    现在,我需要拆分通用cif文件的所有这些部分;要做到这一点,我写这个脚本,现在可以生成:

    H
    L
    A+B
    F
    

    所以我需要将A从B中拆分掉! 为什么我使用临时文件?让我解释;这些步骤:

    1. 检查ATOM和HETATM行的LOOP在哪里。为此,我搜索字符串" _atom_site.group_PDB" (脚本中的最后三行)我得到了函数" get_line_number"的相对行号。我知道循环有26行的长度,所以现在我知道它的开始和结束位置(start = begin_atom =输出" get_line_number"函数; end =在begin_atom之后的26行,即25,因为& #34; range"从0开始,而get_line_number函数从1开始。所以,现在我可以将循环保存在一个单独的文件中。
    2. 我也可以保存标题(H),因为它从第0行开始到行" begin_atom" (" get_line_number"函数的输出)
    3. 现在,对于A,B和F,我使用了那个临时文件(临时文件,因为我最后删除了它)。我从循环结束时生成临时文件[=(" begin_atom" +26),即25,因为范围从0开始到文件末尾(行" -1& #34;),并将其保存为临时文件,用作写入页脚的输入(F);怎么做?使用构造:

      if not (line.startswith('ATOM') or line.startswith('HETATM'))

      所以我现在也可以保存页脚了!

    4. 现在仍然要拆分以ATOM和HETATM开头的记录中的所有链(列7),为此我打开了这个主题。我想我在编辑中编写的内容2.实际上,链(第7列)只能是一个(如文件1QPE中)或许多(如4TVX文件中,有22个链,即22个不同的字母)在以ATOM或HETATM开头的每一行的第7列中。

    5. 我在我的脚本中尝试了这种注释方式(参见编辑1 之前),它为每个链保存一个文件(第7列中的不同字母),但在每个文件中只有一个ATOM行是写的.....我希望我已经清楚而正确地表达了自己

      ============================================ ========================== =============================================== =======================

      已解决 - 感谢@qwwqwwq

      @qwwqwwq :-)谢谢。我一直在寻找" cif"输出文件夹,没有意识到,在对代码进行小编辑后(参见我的编辑),脚本将文件保存在同一文件夹中:-D。完美!

      最终版本:

      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      
      import sys, os
      import os.path
      scriptdir = os.path.dirname(os.path.abspath(__file__))
      cif_dir = os.path.join(scriptdir, 'cif/')
      
      def get_line_number(phrase, file_name):
          with open(file_name) as f:
              for i, line in enumerate(f, 1):
                  if phrase in line:
                      return i
      
      def my_header_splitfile(infilepath, chunksize):
          fname, ext = infilepath.rsplit('.',1)
          with open(infilepath) as infile:
              outfilepath = "{}_header.{}".format(fname, ext)
              with open(outfilepath, 'w') as outfile:
                  for line in (infile.readline() for _ in range(0,(chunksize-2))):
                      outfile.write(line) # END
          temp_lines = open(infilepath).readlines()
          temp_outfilepath = "{}_temp.{}".format(fname, ext)
          atom_hetatm_header_outfilepath = "{}_atom_hetatm_header.{}".format(fname, ext)
          with open(temp_outfilepath, 'w') as outfile:
              outfile.writelines(temp_lines[(chunksize+25):-1]) # END
          with open(atom_hetatm_header_outfilepath, 'w') as outfile:
              outfile.writelines(temp_lines[(chunksize-2):(chunksize+25)])
          footer_lines = open(temp_outfilepath).readlines()
          footer_outfilepath = "{}_footer.{}".format(fname, ext)
          with open(footer_outfilepath, 'w') as outfile:
              for line in footer_lines:
                  if not (line.startswith('ATOM') or line.startswith('HETATM')):
                      outfile.writelines(line) # END
          temp_atom_hetatm_lines = open(temp_outfilepath).readlines()
          temp_atom_hetatm_outfilepath = "{}_atom_hetatm.{}".format(fname, ext)
          with open(temp_atom_hetatm_outfilepath, 'w') as outfile:
              for line in temp_atom_hetatm_lines:
                  if (line.startswith('ATOM') or line.startswith('HETATM')):
                      outfile.writelines(line) # END
          """NEW ENTRY"""
          with open(temp_atom_hetatm_outfilepath) as infile:
              for line in infile:
                  if line.startswith("ATOM"):
                      atom_chain_outfilepath = "{}_atom_chain_{}.{}".format(fname, line.split()[6], ext)
                      with open(atom_chain_outfilepath, "a") as outfile:
                          outfile.write(line)
                  elif line.startswith("HETATM"):
                      atom_chain_outfilepath = "{}_hetatm_chain_{}.{}".format(fname, line.split()[6], ext)
                      with open(atom_chain_outfilepath, "a") as outfile:
                          outfile.write(line)
          os.remove(temp_outfilepath) # REMOVE "temp_outfilepath"
          os.remove(temp_atom_hetatm_outfilepath) # REMOVE "temp_atom_hetatm_outfilepath" - FINISH
      
      cif_code = '1d66'.upper() # CHANGE HERE THE PID CODE. i.e. 1D66, 1QPE, 4TVX
      
      filename = '%s%s.cif' % (cif_dir,cif_code.upper())
      
      begin_atom = get_line_number("_atom_site.group_PDB", filename)
      #print begin_atom
      my_header_splitfile(filename, begin_atom)
      

      现在您需要编辑PID条目的第55行(即1d66,1qpe,4tvx,...,从Protein Data Bank下载)。

1 个答案:

答案 0 :(得分:1)

很难说出你在这里问的是什么,对不起。提供适合您问题正文的样本输入和输出将有很长的路要走。

听起来您想要根据文件第六列中的值拆分文件。

我会做类似的事情:

def meets_criteria(line):
  return line.startswith("ATOM") or line.startswith("HETATM")

with open(large_file) as f:
    for line in f:
        if meets_criteria(line):
            with open(line.split()[6], "a") as of:
                of.write(line)

因此,您将拥有以第6列(0索引)中的值命名的文件。

您似乎正在使用.readlines方法,请注意这会将所有数据读入内存,没有理由这样做,这可能就是您的脚本挂在大输入上的原因。< / p>