2013-02-20 161 views
2

我有包含像这样Python字典约为10大文件加入大型辞书:通过相同的密钥

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])} 
    } 

它们基本上是字典的所有词典。每个文件的大小都在1 GB左右(以上只是数据的一个例子)。不管怎么说,我想要做的是加入了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]) 

但是,如果我尝试在我的1 GB文件我通过将d1和d2以及最终字典保留在内存中来快速耗尽内存。

我有几个想法:

  1. 有没有一种方法,我可以只加载从分段词典的按键,比较这些,如果同样的人在多个字典中找到需要综合利用价值?
  2. 而不是将字典合并成一个巨大的文件(这可能会给我未来的内存头痛),我怎么可以在合并数据后为许多单独的文件包含一个键的所有值?例如,对于上述数据,我只想有:

    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])} 
    

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

+0

有没有你不是一个理由使用数据库系统?听起来你所拥有的是以这种方式操纵的大量数据。 – 2013-02-20 02:28:07

+0

大部分原因是我对任何一种数据库都缺乏经验。你建议我用什么来将Python字典转换为数据库? – deckardk 2013-02-20 02:37:41

+0

您使用'eval'的事实使得懒惰的解决方案变得相当困难。像@Voo所说的那样并使用数据库。 – nneonneo 2013-02-20 02:48:12

回答

1

shelve模块是一个非常易于使用的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() 
+0

太棒了,这看起来像是一个很好的短期解决方案。我一定要为未来学习一些关于数据库的东西。 – deckardk 2013-02-20 03:09:17

+0

那里有趣的模块,将记住以备将来参考,这当然可以派上用场。 – Voo 2013-02-20 06:47:22

+0

@nneonneo,我试着快速实现这个,但更新值似乎并不奏效。我得到一个“AttributeError:'NoneType'对象没有属性'更新'”错误,因为它似乎是更新不存在的键。我之前使用过defaultdict来解决这个问题,但我不知道如何在这里继续,有什么想法? – deckardk 2013-02-21 03:07:02

1

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

为什么要经历这一切努力,如果你可以让一个数百万工时的数据库处理它?这样做会更有效率,而且更容易查询信息。

我见过Oracle数据库存储大于10 GB的数据,没有任何问题,我相信postgre也会处理这一点。好的是,如果你使用ORM,你可以抽象出那些基本的如果有必要,细节就会消失,并担心它们。

此外,虽然生物信息学不是我的专长,但我确信有针对生物信息学的具体解决方案 - 也许其中一个将是完美契合?

+0

的确如此,听起来像我应该做的。我对数据库有一点经验,你建议我用什么?让我尝试给出一点背景:原始数据是一个大的6 GB字典,它是使用BioPython代码生成的,该代码被重新分类到上面的信息中。这就是我一直坚持这些数据结构的原因,但我很乐意学习新的东西。 – deckardk 2013-02-20 02:33:26

+0

@deckardk就我个人而言,我会首先查看[SQLAlchemy](http://www.sqlalchemy.org/)的一些教程,该教程提供了一个对象关系映射(ORM),它将大部分数据库mojo抽象出来。对于你的数据库,你可能想使用PostgreSQL,而不是用于本教程的sqlite(但是由于这些细节被抽象出来,你可以简单地从sqlite开始,如果你注意到性能不够好,改为Postgre后来)。 – Voo 2013-02-20 02:39:46

+0

谢谢@Voo。我会看看这些教程,并尝试学习关于数据库的新知识:) – deckardk 2013-02-20 02:47:54

0

这个概念应该工作。

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

例如,如果您在一次传递中创建了所有密钥的唯一第一个字符的列表,然后将每个传递过程都处理为新的输出文件。如果它是简单的字母数据,则逻辑选择将是字母表中每个字母的循环。

例如,在“p”阶段,您将处理'PRO-HIS-MET'

然后,您将结合所有文件的所有结果。

如果您是一名开发人员,如果您可以处理这种交互,那么以前答案中的数据库创意可能是最好的方法。这个想法需要创建一个2级结构,插入和更新记录,然后用SQL语句查询结果。

+0

使文件系统解决方案接近可伸缩和高效,可能涉及内存映射文件到地址空间并让操作系统担心交换。 *比一个简单的数据库设置复杂得多,其中有数百万个教程。 – Voo 2013-02-20 02:32:37

+0

海报不是开发人员(暗示他没有数据库技能)我提出了一种基于他具有脚本技能的事实。正如发布中指出的那样,我认为数据库解决方案是最好的方法。 – DarrenMB 2013-02-20 02:43:26

+0

我不是不同意我只是说这篇文章是在生物信息学工作,这意味着10GB可能是他将获得的数据量的一个小的下界,并且即使FS有效地实现给定的问题也是一个地狱比阅读ORM教程复杂得多。地狱它需要一个有经验的开发者一天左右才能想出一些合理的东西。 – Voo 2013-02-20 02:45:43