使用 dict.items() 为大型数据集优化字典查找

Posted

技术标签:

【中文标题】使用 dict.items() 为大型数据集优化字典查找【英文标题】:Optimizing dictionary look up using dict.items() for large dataset 【发布时间】:2019-06-10 02:17:27 【问题描述】:

我是新手,最近几个月开始使用 pyhton 进行编码。我有一个脚本,它需要一个蛋白质组(2850 个字符串的 800 Kb 文件)并根据一个大型数据集(2300 万个字符串的 8Gb 文件保存在代码中作为 id:protein_string 的字典)检查每个单独的蛋白质(protein_string)并报告 Ids所有相同的字符串(每个字符串最多可以报告 8500 个 ID)。当前脚本需要 4 小时才能运行。可以做些什么来加快整个过程,以及如何将我的脚本转换为多处理或多线程(不确定差异)以进行比较的代码部分?

import sys
from Bio import AlignIO
from Bio import SeqIO
from Bio.Seq import Seq
import time
start_time = time.time()

databasefile = sys.argv[1]
queryfile = sys.argv[2]

file_hits = "./" + sys.argv[2].split("_protein")[0] + "_ZeNovo_hits_v1.txt"
file_report = "./" + sys.argv[2].split("_protein")[0] + "_ZeNovo_report_v1.txt"
format = "fasta"
output_file = open(file_hits, 'w')
output_file_2 = open(file_report,'w')
sequences_dict = 

output_file.write("\t\n".format("protein_query", "hits"))
for record in SeqIO.parse(databasefile, format):
    sequences_dict[record.description] = str(record.seq)
print("processed database in --- :.3f seconds ---".format(time.time() - start_time))

processed_counter = 0
for record in SeqIO.parse(queryfile, format):
    query_seq = str(record.seq)
    count = 0
    output_file.write("\t".format(record.description))
    for id, seq in sequences_dict.items():
        if seq == query_seq:
            count += 1
            output_file.write("\t".format(id))
    processed_counter += 1
    output_file.write("\n")
    print("processed protein "+str(processed_counter))
    output_file_2.write(record.description+'\t'+str(count)+'\t'+str(len(record.seq))+'\t'+str(record.seq)+'\n')
output_file.close()
output_file_2.close()
print("Done in --- :.3f seconds ---".format(time.time() - start_time))

【问题讨论】:

从profiling your code 开始,找出其中最慢的部分。 【参考方案1】:

在我看来,将字典存储为 id : seq 而不是将其存储为 seq : [id_list] 可能更有意义。由于听起来每个序列有很多重复,这将节省访问特定序列的所有 ID 的时间。您可以在读取数据时使用 defaultdict 并将默认值作为空列表来执行此操作,并且当您读取 ID 和序列时,您可以使用 sequences_dict[record.seq].append(record.description) 将其添加到字典中。

让我知道这是否有帮助以及我是否可以提供其他帮助。

【讨论】:

感谢您的建议!它有所帮助,时间减少到 4.30 分钟。【参考方案2】:

根据 Sam Hollenbach 的建议,我可能会对您的代码进行以下 (4) 项更改。

import sys
from Bio import AlignIO
from Bio import SeqIO
from Bio.Seq import Seq
import time
start_time = time.time()
from collections import defaultdict


databasefile = sys.argv[1]
queryfile = sys.argv[2]

file_hits = "./" + sys.argv[2].split("_protein")[0] + "_ZeNovo_hits_v1.txt"
file_report = "./" + sys.argv[2].split("_protein")[0] + "_ZeNovo_report_v1.txt"
_format = "fasta" #(change 1)
output_file = open(file_hits, 'w')
output_file_2 = open(file_report,'w')
sequences_dict = defaultdict(list)

output_file.write("\t\n".format("protein_query", "hits"))
for record in SeqIO.parse(databasefile, _format):
    sequences_dict[record.seq].append(record.description) #(change 2)
    #sequences_dict[record.description] = str(record.seq)
print("processed database in --- :.3f seconds ---".format(time.time() - start_time))

processed_counter = 0
for record in SeqIO.parse(queryfile, _format):
    query_seq = record.seq #(change 3)
    count = 0
    output_file.write("\t".format(record.description))
    if query_seq in sequences_dict: #(change 4)
        count = len(sequences_dict[query_seq])
        output_file.write('\t'.join(sequences_dict[query_seq]) + "\n")
    processed_counter += 1
    print("processed protein", processed_counter)
    output_file_2.write(record.description+'\t'+str(count)+
                        '\t'+str(len(record.seq))+'\t'+str(record.seq)+'\n')
output_file.close()
output_file_2.close()
print("Done in --- :.3f seconds ---".format(time.time() - start_time))

更改 #1: - 将格式变量的名称更改为 _format(以避免与 Python 术语“格式”发生冲突 并在使用它的代码中进行更改。

更改 #2:使用 record.seq 作为字典的键并将 record.description 附加到列表(作为值)

更改 #3:无需将 record.seq 转换为 str - 它已经是一个字符串。

更改 #4:这 3 行将比在原始代码中遍历字典更快地找到任何匹配的记录。

我不确定应该如何处理output_file.write("\t".format(record.description))

另外,不能说我已经找到了完整工作程序所需的所有更改。如果您在尝试建议的更改后有任何问题,请告诉我。

【讨论】:

是的,我做了所有这些更改,但我会将更改#1 添加到我当前的脚本中。

以上是关于使用 dict.items() 为大型数据集优化字典查找的主要内容,如果未能解决你的问题,请参考以下文章

优化解决方案以在大型数据集上找到共同的第三个

使用大型列表优化 Django 查询集调用?

优化人员安置 - 大型数据集

适当的索引(或删除)以优化大型数据集表

如何优化大型数据集的查询?

为大型 Postgresql 表优化嵌套连接窗口函数