Python:我可以更快地从大文件中获取特定行吗?

时间:2015-08-04 09:55:38

标签: algorithm python-2.7 bioinformatics large-files

我有两个大文件。其中一个是信息文件(大约270MB和16,000,000行),如下所示:

1101:10003:17729
1101:10003:19979
1101:10003:23319
1101:10003:24972
1101:10003:2539
1101:10003:28242
1101:10003:28804

另一种是标准的FASTQ格式(约27G和280,000,000行),如下所示:

@ST-E00126:65:H3VJ2CCXX:7:1101:1416:1801 1:N:0:5
NTGCCTGACCGTACCGAGGCTAACCCTAATGAGCTTAATCAAGATGATGCTCGTTATGG
+
AAAFFKKKKKKKKKFKKKKKKKFKKKKAFKKKKKAF7AAFFKFAAFFFKKF7FF<FKK
@ST-E00126:65:H3VJ2CCXX:7:1101:10003:75641:N:0:5
TAAGATAGATAGCCGAGGCTAACCCTAATGAGCTTAATCAAGATGATGCTCGTTATGG
+
AAAFFKKKKKKKKKFKKKKKKKFKKKKAFKKKKKAF7AAFFKFAAFFFKKF7FF<FKK

FASTQ文件每个序列使用四行。第1行以“@”字符开头,后跟序列标识。对于每个序列,第1行的这一部分是唯一的。

1101:1416:1801 and 1101:10003:75641

我想根据信息文件从FASTQ文件中获取第1行和后3行。这是我的代码:

import gzip
import re

count = 0
with open('info_path') as info, open('grab_path','w') as grab:
        for i in info:
                sample = i.strip()
                with gzip.open('fq_path') as fq:
                        for j in fq:
                                count += 1
                                if count%4 == 1:
                                        line = j.strip()
                                        m = re.search(sample,j)
                                        if m != None:
                                                grab.writelines(line+'\n'+fq.next()+fq.next()+fq.next())
                                                count = 0
                                                break

并且它有效,但由于这两个文件都有数百万行,因此效率低(运行一天只能获得20,000行)。

7月6日更新:

我发现信息文件可以读入内存(感谢@tobias_k提醒我),所以我创建了一个字典,键是信息行,值都是0.之后,我读了FASTQ文件每4行,使用标识符部分作为键,如果值为0则返回4行。这是我的代码:

import gzip

dic = {}
with open('info_path') as info:
        for i in info:
                sample = i.strip()
                dic[sample] = 0
with gzip.open('fq_path') as fq, open('grap_path',"w") as grab:
        for j in fq:
                if j[:10] == '@ST-E00126':
                        line = j.split(':')
                        match = line[4] +':'+line[5]+':'+line[6][:-2]
                        if dic.get(match) == 0:
                                grab.writelines(j+fq.next()+fq.next()+fq.next())

这种方式要快得多,需要20分钟才能获得所有匹配的行(约64,000,000行)。我已经考虑过首先通过外部排序对FASTQ文件进行排序。拆分可以读入内存的文件是可以的,我的麻烦是如何在排序时将下三行保留在标识符行之后。谷歌的答案是首先将这四行线性化,但这需要40分钟。

无论如何,谢谢你的帮助。

1 个答案:

答案 0 :(得分:2)

您可以按标识符(1101:1416:1801)部分对这两个文件进行排序。即使文件不适合内存,也可以使用external sorting

在此之后,您可以应用简单的类似合并的策略:同时读取两个文件并在此期间进行匹配。像这样的东西(伪代码):

entry1 = readFromFile1()
entry2 = readFromFile2()
while (none of the files ended)
    if (entry1.id == entry2.id)
        record match
    else if (entry1.id < entry2.id)
        entry1 = readFromFile1()
    else 
        entry2 = readFromFile2()

这种方式entry1.identry2.id总是彼此靠近,你不会错过任何比赛。同时,这种方法需要迭代每个文件一次。