2013-02-20 243 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