读取大文件(>8GB)并将数据转储到字典中并再次加载的最快方法



我正在处理一个大的蛋白质序列(fasta)文件(>8GB),我的想法是创建一个字典,其中键和值分别是蛋白质id和序列。

就目前而言,我可以使用pickle制作数据并将其转储到字典中,然后尝试使用cpickle打开(我读取pickle转储数据更快,cpickle加载数据更快)。但这里的主要问题是时间:将它作为字典制作和转储需要太多的时间和内存(PC有8GB的内存)。

有没有更快的选项可以用来处理Python中的大文件?

以下是我创建字典和转储数据的Python代码:

from Bio import SeqIO
import pickle,sys
fastaSeq = {}
with open('uniref90.fasta') as fasta_file:
for seq_record in SeqIO.parse(fasta_file, 'fasta'):
header =seq_record.id
uniID = header.split('_')[1]
seqs = str(seq_record.seq)
fastaSeq[uniID] = seqs
f = open('uniref90.obj', 'wb')
pickle.dump(fastaSeq, f, pickle.HIGHEST_PROTOCOL)
f.close()

加载字典并在单独的Python程序中执行一些任务:

import cPickle as pickle
seq_dict = pickle.load(open("uniref90.obj", "rb"))
for skey in seq_dict.keys():
#doing something 

数据库是你的朋友,我的儿子。

import sqlite3
from Bio import SeqIO
db = sqlite3.connect("./db")
c = db.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS map (k text unique, v text)''')
db.commit()

def keys(db):
cursor = db.cursor()
return cursor.execute("""SELECT k FROM map""").fetchall()

def get(key, db, default=None):
cursor = db.cursor()
result = cursor.execute("""SELECT v FROM map WHERE k = ?""", (key,)).fetchone()
if result is None:
return default
return result[0]

def save(key, value, db):
cursor = db.cursor()
cursor.execute("""INSERT INTO map VALUES (?,?)""", (key, value))
db.commit()

with open('uniref90.fasta') as fasta_file:
for seq_record in SeqIO.parse(fasta_file, 'fasta'):
header = seq_record.id
uniID = header.split('_')[1]
seqs = str(seq_record.seq)
save(uniID, seqs, db)

cPickle是迄今为止通用数据结构最快的。

根据数据结构施加的约束,可以尝试ujson,它是速度更快的JSON实现之一,请注意,您可能需要传递一些标志来保持浮点值的准确性。

如果你的数据是平的,那么numpy.load变体会更快。有从文本到二进制数据的格式选项。

最后,numpy.mmap允许您在不"加载"二进制数据的情况下访问二进制数据,也就是说,只有当您访问数据时,数据才会到达RAM。这应该是迄今为止最快的。

如果您一直使用字典,那么等效的模块就是shelve模块。

好吧,你的问题实际上是如何处理一组大数据,而不一定是用python。问题是,无论你尝试什么,你都不想在内存中加载>8GB,因为这会使你的应用程序交换,每次你尝试访问一个元素时,你都会从RAM中获得页面输入/页面输出。

我的方法是将数据集实际排序为多个文件,这些文件可以很容易地进行pickle,每个文件都使用键上的一些哈希函数进行排序,这样可以快速加载拆分的数据集。然后只加载与哈希函数条件匹配的数据集,这将很快完成,并提取键的值。

最后,始终使用cPickle,它是Pickle的C实现,并且在加载和转储方面应该更快(尽管我个人从未制定过基准测试)。

注意:这个解决方案在某种程度上就是穷人的数据库。当然,@fretash的建议和@Jakob使用数据库的解决方案是一个非常好的主意。尽管我建议的解决方案是在网络节点之间分发数据集的常见方式,但在多个服务器之间分发存储。

最新更新