Python 通过相同的键连接大型词典

Python 通过相同的键连接大型词典,python,bioinformatics,dictionary,defaultdict,Python,Bioinformatics,Dictionary,Defaultdict,我有大约10个包含python字典的大型文件,如下所示: dict1: { 'PRO-HIS-MET': { 'A': ([1,2,3],[4,5,6],[7,8,9]), 'B': ([5,2],[6],[8,9]), 'C': ([3],[4],[7,8])}, 'TRP-MET-GLN': { 'F': ([-5,-4,1123],[-7,-

我有大约10个包含python字典的大型文件,如下所示:

    dict1:
    {   
        'PRO-HIS-MET': {
            'A': ([1,2,3],[4,5,6],[7,8,9]),
            'B': ([5,2],[6],[8,9]),
            'C': ([3],[4],[7,8])},
        'TRP-MET-GLN': {
            'F': ([-5,-4,1123],[-7,-11,2],[-636,-405])}
    }

    dict2:
    {   
        'PRO-HIS-MET': {
            'J': ([-657], [7,-20,3], [-8,-85,15])}

        'TRP-MET-GLN':{
            'K': ([1,2,3],[4,50,6],[7,80,9]), 
            'L': ([5,20],[60,80],[8,9])}
    }
基本上它们都是字典中的字典。每个文件的大小约为1GB(以上只是数据的一个示例)。无论如何,我想做的是把这10本字典合并在一起:

    final:
    {
        'PRO-HIS-MET': {
            'A': ([1,2,3],[4,5,6],[7,8,9]),
            'B': ([5,2],[6],[8,9]),
            'C': ([3],[4],[7,8])
            'J': ([-657], [7,-20,3], [-8,-85,15])},
        'TRP-MET-GLN': {
            'F': ([-5,-4,1123],[-7,-11,2],[-636,-405])
            'K': ([1,2,3],[4,50,6],[7,80,9]), 
            'L': ([5,20],[60,80],[8,9])}
    }
我在小文件上尝试了以下代码,效果很好:

    import csv
    import collections
    d1 = {}
    d2 = {}
    final = collections.defaultdict(dict)

    for key, val in csv.reader(open('filehere.txt')):
        d1[key] = eval(val)
    for key, val in csv.reader(open('filehere2.txt')):
        d2[key] = eval(val)

    for key in d1:
        final[key].update(d1[key])
    for key in d2:
        final[key].update(d2[key])

    out = csv.writer(open('out.txt', 'w'))
    for k, v in final.items():
        out.writerow([k, v])
然而,如果我尝试在我的1GB文件上使用它,我会将d1和d2以及最终的字典保留在内存中,从而很快耗尽内存

我有两个想法:

  • 有没有一种方法可以让我只从分段字典中加载键,比较它们,如果在多个字典中找到相同的键,只需合并这些值
  • 与其将字典合并到一个大文件中(这可能会让我在未来的内存中感到头疼),我如何在合并数据后创建多个包含一个键的所有值的单独文件?例如,对于上述数据,我只需要:

    pro-his-met.txt:
    'PRO-HIS-MET': {
        'A': ([1,2,3],[4,5,6],[7,8,9]),
        'B': ([5,2],[6],[8,9]),
        'C': ([3],[4],[7,8])
        'J': ([-657], [7,-20,3], [-8,-85,15])}
    trp-met-gln.txt:
    'TRP-MET-GLN': {
        'F': ([-5,-4,1123],[-7,-11,2],[-636,-405])
        'K': ([1,2,3],[4,50,6],[7,80,9]), 
        'L': ([5,20],[60,80],[8,9])}
    

  • 作为一名生物学家,我没有太多的编程经验(你可能已经猜到上面的数据代表了一个生物信息学问题),所以任何帮助都将不胜感激

    就个人而言,这听起来像是发明数据库来解决问题的原型。是的,你可以通过保存文件来解决这个问题,为了性能优化,你可以将文件映射到内存中,让操作系统来处理交换等。但是这确实很复杂,很难做到真正的好

    如果你能让一个已经投入了数百万工时的数据库来处理它,为什么还要经历所有这些努力呢?这将更有效率,并且作为一个额外的好处,更容易查询信息

    我看到Oracle DBs存储的数据远远超过10 GB,没有任何问题,我相信postgre也会处理这一问题。。好的方面是,如果你使用ORM,你可以把那些细节抽象出来,如果有必要的话,以后再担心它们


    另外,虽然生物信息学不是我的专长,但我很确定有专门针对生物信息学的解决方案——也许其中一个最适合

    这个概念应该行得通

    我会考虑在每次执行一部分键时对文件进行多次传递。并保存该结果

    如果你在一次传递中创建所有键的唯一第一个字符的列表,然后将每个传递处理为新的输出文件。如果是简单的字母数据,逻辑上的选择将是字母表中每个字母的循环

    在“p”通行证中,您将处理“PRO-HIS-MET”

    然后,您将在最后合并所有文件的所有结果


    如果您是一名开发人员,如果您能够处理这种交互,那么前面答案中的数据库思想可能是最好的方法。这个想法需要创建一个两级结构,在其中插入和更新记录,然后使用SQL语句查询结果。搁置模块是一个非常易于使用的Python数据库。它远没有真正的数据库强大(关于这一点,请参阅@Voo的答案),但它可以操作大型词典

    首先,从字典中创建工具架:

    import shelve
    s = shelve.open('filehere.db', flag='n', protocol=-1, writeback=False)
    for key, val in csv.reader(open('filehere.txt')):
        s[key] = eval(val)
    s.close()
    
    现在您已将所有内容整齐地搁置起来,可以高效地操作字典:

    import shelve
    import itertools
    s = shelve.open('final.db', flag='c', protocol=-1, writeback=False)
    s1 = shelve.open('file1.db', flag='r')
    s2 = shelve.open('file2.db', flag='r')
    for key, val in itertools.chain(s1.iteritems(), s2.iteritems()):
        d = s.get(key, {})
        d.update(val)
        s[key] = d # force write
    s.close()
    

    你不使用数据库系统有什么原因吗?听起来你有很多数据需要以这种方式处理。主要原因是我对任何类型的数据库都缺乏经验。您建议我使用什么来将python字典转换为db?您使用
    eval
    这一事实使得使用惰性解决方案非常困难。按照@Voo所说的去做,使用一个数据库。使文件系统解决方案更接近可伸缩性和效率,可能需要将文件映射到地址空间,让操作系统担心交换。要比一个有数百万教程的简单DB设置复杂得多。海报不是开发人员(意味着他没有DB技能),我建议了一种基于他有脚本技能这一事实的方法。我相信DB解决方案是最好的方法,正如帖子中提到的。我并不反对,我只是说这篇帖子是在生物信息学领域工作的,这意味着10GB可能是他将获得的数据量的一个小下限,使用FS实现给定的问题甚至有点效率比阅读ORM教程要复杂得多。见鬼,一个有经验的开发人员要花上一天左右的时间才能想出一些合理的方法。这听起来确实是我应该做的。我对数据库几乎没有经验,你建议我用什么?让我试着给出一点背景信息:原始数据是一个6GB的大字典,它是使用BioPython代码生成的,并根据上面的信息重新排序。这就是我一直坚持使用这些数据结构的原因,但我很高兴能学到一些新的东西。@deckardk个人认为,我首先要看一些关于对象关系映射(ORM)的教程,它将大部分数据库任务抽象出来。对于您的数据库,您可能希望使用PostgreSQL而不是本教程中使用的sqlite(但由于这些细节已被抽象掉,您可以很容易地从sqlite开始,以简化操作,如果您注意到性能不够好,请稍后更改为Postgre)。谢谢@Voo。我将看一看这些教程,并尝试学习一些关于数据库的新知识:)太棒了,目前看来这是一个很好的短期解决方案。对于未来的数据库,我肯定要学习一两件事。其中有趣的模块,将牢记在心,以备将来参考,这肯定会派上用场。@nneonneo,我尝试了快速实现,但更新值似乎不起作用。我得到一个“AttributeError:‘NoneType’对象没有