Python检查两个巨大文本文件之间的一致性

2024-10-02 08:30:25 发布

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

所以,这件事让我很难过!
我正在处理巨大的文本文件,我指的是100Gb+。具体来说,它们在fastq format中。这种格式用于DNA测序数据,由四行记录组成,如下所示:

@REC1
GATTTGGGGTTCAAAGCAGTATCGATCAAATAGTAAATCCATTTGTTCAACTCACAGTTT  
+  
!''*((((***+))%%%++)(%%%%).1***-+*''))*55CCF>>>>>>CCCCCCC65  
@REC2
GATTTGGGGTTCAAAGCAGTATCGATCAAATAGTAAATCCATTTGTTCAACTCACAGTTT  
+  
!''*((((***+))%%%++)(%%%%).1***-+*''))**55CCF>>>>>>CCCCCCC65  
.  
.  
.

为了这个问题,只需关注标题行,从“@”开始。在

所以,出于QA的目的,我需要比较两个这样的文件。这些文件应该有匹配的头,因此另一个文件中的第一个记录也应该有头文件“@REC1”,下一个记录应该是“@REC2”,依此类推。在我进行大量的下游分析之前,我想确保情况确实如此。
由于文件太大,一个简单的迭代字符串比较会花费很长时间,但是这个QA步骤将运行很多次,我不能再等那么长时间。所以我认为一个更好的方法是从文件中的几个点取样记录,例如每10%的记录。如果记录顺序混乱,我很有可能发现它。
到目前为止,我已经能够通过估计文件大小来处理这些文件,而不是使用python的file.seek()访问文件中间的一条记录。例如,要访问大约在中间的一条线,我可以:

^{pr2}$

但现在问题更复杂了,因为我不知道如何在两个文件之间协调,因为字节位置不是文件中行索引的指示符。换句话说,如何访问两个文件中的10567311行,以确保它们是相同的,而不必检查整个文件?在

如有任何建议/提示,不胜感激。可能是并行迭代?但具体怎么办?
谢谢!在


Tags: 文件数据目的format标题格式记录qa
3条回答

您是否研究过使用rdiff命令。
RDIF的优点是:

  • 使用同样的4.5GB文件,rdiff只消耗了大约66MB的RAM,并且扩展得非常好。到目前为止它从未坠毁过。在
  • 它也比diff快得多
  • rdiff本身结合了diff和patch功能,因此您可以使用同一个程序创建增量并应用它们

RDIF的缺点是:

  • 它不是标准Linux/UNIX发行版的一部分–您必须 安装librsync包。在
  • rdiff生成的delta文件的格式与diff的略有不同
  • delta文件稍大一些(但不够大)。在
  • 使用rdiff生成delta时使用的方法稍有不同,这是好的也是坏的–需要两个步骤。这个 第一个生成一个特殊的签名文件。在第二步中,a delta是使用另一个rdiff调用创建的(如下所示)。同时 这两个步骤可能看起来很烦人,它的好处是 提供比使用diff时更快的增量

参见:http://beerpla.net/2008/05/12/a-better-diff-or-what-to-do-when-gnu-diff-runs-out-of-memory-diff-memory-exhausted/

取样是一种方法,但你得靠运气。另外,Python是执行此项工作的错误工具。您可以使用标准的Unix命令行工具,以仍然相当有效的方式执行不同的操作,并计算出准确的答案:

  1. 线性化你的FASTQ记录:用制表符替换前三行中的新行。在
  2. 对一对线性化文件运行diff。如果存在差异,diff将报告它。在

要线性化,可以通过awk运行FASTQ文件:

$ awk '\
    BEGIN { \
      n = 0; \
    } \
    { \
      a[n % 4] = $0; \
      if ((n+1) % 4 == 0) { \
        print a[0]"\t"a[1]"\t"a[2]"\t"a[3]; \
      } \
      n++; \
    }' example.fq > example.fq.linear 

要比较一对文件:

^{pr2}$

如果有任何差异,diff将找到它并告诉您哪个FASTQ记录不同。在

{1}你可以直接在两个文件上进行线性化,但是如果你不做线性化的话,那你就可以直接在这两个文件上运行线性化了。在

所以这些是大文件。写入新文件在时间和磁盘空间上都很昂贵。有一种方法可以改进这一点,使用streams。在

如果将awk脚本放入一个文件(例如,linearize_fq.awk),则可以这样运行它:

$ awk -f linearize_fq.awk example.fq > example.fq.linear

这对您的100+Gb文件很有用,因为现在您可以通过bashprocess substitutions设置两个Unix文件流,并直接在这些流上运行diff

$ diff <(awk -f linearize_fq.awk example_1.fq) <(awk -f linearize_fq.awk example_2.fq)

或者您可以使用named pipes

$ mkfifo example_1.fq.linear
$ mkfifo example_2.fq.linear
$ awk -f linearize_fq.awk example_1.fq > example_1.fq.linear &
$ awk -f linearize_fq.awk example_2.fq > example_2.fq.linear &
$ diff example_1.fq.linear example_2.fq.linear
$ rm example_1.fq.linear example_2.fq.linear

命名管道和进程替换都避免了创建额外(常规)文件的步骤,这对于您的输入可能是一个问题。将100+Gb文件的线性化副本写入磁盘可能需要一段时间,而且这些副本还可能占用您可能没有的磁盘空间。在

使用streams可以解决这两个问题,这使得它们对于以有效的方式处理生物信息学数据集非常有用。在

您可以用Python复制这些方法,但它几乎肯定会运行得慢得多,因为Python在处理像这样的重I/O任务时非常慢。在

在Python中,并行迭代可能是最好的方法。我不知道它的运行速度有多快(快速的SSD可能是加快速度的最佳方法),但由于无论如何,您都必须计算两个文件中的新行数,因此我看不到解决此问题的方法:

with open(file1) as f1, open(file2) as f2:
    for l1, l2 in zip(f1,f2):
        if l1.startswith("@REC"):
            if l1 != l2:
                print("Difference at record", l1)
                break
    else:
        print("No differences")

这是为python3编写的,其中zip返回一个迭代器;在python2中,您需要使用itertools.izip()。在

相关问题 更多 >

    热门问题