2012-07-16 73 views
0

我是python的新手,所以我很抱歉,如果這個例子很簡單。存儲已保存的列表時出現Python MemoryError

我想寫一個簡單的腳本,將兩個大型數據文件(每個〜40GB)的部分分別提取到一個生成的文件中,格式略有變化。我最初嘗試使用readlines(),但是將所有文件讀入內存,而我們的實例只有28GB內存。使用sizehint參數僅解析文件的一部分。

我現在迭代該文件。問題是我將文本解析的輸出存儲在三個列表中,這些列表變得相當大,超出了可用內存。我認爲這只是切換到使用交換,這將是很好,但它只是退出與「MemoryError」。

這適用於小樣本文件,但扼流圈對我們的實際數據。

腳本:

import sys 

a = [] 
b = [] 
c = [] 

file1 = open(sys.argv[1],"r") 
for line in file1: 
    if '@' in line: 
     a.append(line.lstrip('@').rstrip('\n')) 
     b.append(file1.next().rstrip('\n')) 
file1.close() 

file2 = open(sys.argv[2],"r") 
for line in file2: 
    if '@' in line: 
     c.append(file2.next().rstrip('\n')) 
file2.close() 

file3 = open(sys.argv[3],"w") 
for i in xrange(len(a)): 
    file3.write("".join([">",a[i],'\n',b[i],":",c[i],"\n"])) 

我在網上發現表明創造某種數據庫來存儲變量的,但不應該是必要的。你有什麼想法,我應該如何處理這個?

爲了完整,這就是我想要做的(從我們的例子中的測試數據:

file1: 

@Read.Salmonella_paratyphi_A_chromosome.29004.4835/1 
TCGTGTACAGCATTCTTTATAGTGGAACGGTGACCGTACCGCAAAGCTGCGAAATCAACGCCGGACKIPPTCGTAG 
+ 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 

file2: 

@Read.Salmonella_paratyphi_A_chromosome.29004.4835/1 
TCGTGTACAGCATTCTTTATAGTGGAACGGTGACCGTACCGCAAAGCTGCGAAATCAACGCCGGACAAACGATTCT 
+ 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 

file3 (output): 

>Read.Salmonella_paratyphi_A_chromosome.29004.4835/1 
TCGTGTACAGCATTCTTTATAGTGGAACGGTGACCGTACCGCAAAGCTGCGAAATCAACGCCGGACKIPPTCGTAG:TCGTGTACAGCATTCTTTATAGTGGAACGGTGACCGTACCGCAAAGCTGCGAAATCAACGCCGGACAAACGATTCT 
+0

數據庫解決方案將最有意義的,因爲你只是用了太多的內存。它可能被推動交換,但你不能依賴這種行爲。將中間結果存儲在磁盤上的文件中會讓您更有效地利用空間,而不是試圖將所有內容都放在內存中。 – sean 2012-07-16 16:34:47

+0

謝謝。我想過試圖做到這一點,但是當我得到三個結果列表然後不得不連接它們時,我會不會遇到同樣的內存錯誤? – Kipp 2012-07-16 16:35:56

+0

列表b從第一個文件輸出,列表c從第二個文件輸出。他們從兩個文件中的同一地點獲取數據,但數據不同。編輯:哦,我犯了一個錯字。它們來自不同的sys.argv [x]輸入。現在修復它。 – Kipp 2012-07-16 16:45:18

回答

0

我還沒有嘗試過這個自己,但似乎像下面應該工作:

file1 = open(sys.argv[1],"r") 
file2 = open(sys.argv[2],"r") 
file3 = open(sys.argv[3],"w") 

for line1 in file1: 
    if '@' in line1: # line1.startswith('@') is probably better here 
     a=line1.lstrip('@').rstrip('\n') 
     b=file1.next().rstrip('\n') 
     for line2 in file2: 
      if '@' in line2: 
       c=file2.next().rstrip('\n') 
       break 
     file3.write(">%s\n%s:%s\n"%(a,b,c)) 

file1.close() 
file2.close() 
file3.close() 

在這種情況下,每次只能在內存中保留一行......除非文件有真的長行; ^)。

此外,由於您的lstrip爲'@'字符,因此您可能需要考慮使用if line.startswith('@')而不是if '@' in line

+0

我認爲'for'循環不應該嵌套,應該是這樣嗎? – heltonbiker 2012-07-16 16:53:24

+0

@heltonbiker - 它們需要嵌套,因爲對於文件1中對應的一對行(a,b),file2中需要有1行(c)。我們搜索,直到找到該行,然後從(內部)'for'循環中斷開。文件對象應該記住它的位置,並重新啓動從下一次通過循環離開的地方的迭代(儘管如我所說,我沒有嘗試過自己;)) – mgilson 2012-07-16 16:56:11

+0

這是可能的,但我也很困惑; o)無論如何,如果第二個for循環有些「錯誤」,在第一個for循環中調用file2上的next()應該保持行順序。 – heltonbiker 2012-07-16 17:03:50

1

而不是解析文件到陣列(abc),你可以寫到文件,解析文件

事情是這樣的pseudo'ish代碼:

def get_line_with_at(a): 
    while a: 
     line = a.readline() 
     if "@" in line: 
      return line.strip() 


# Open all file handles 
a, b, c = [open(sys.argv[x + 1]) for x in range(3)] 
out = open(sys.argv[4]) 

while a and b and c: 
    # Repeat until a, b, and file handles are exhausted 
    chunk1 = get_line_with_at(a) 
    chunk2 = b.next().strip() 
    chunk3 = get_line_with_at(c) 

    out.write(
     ">%s\n%s:%s\n" % (chunk1, chunk2, chunk3)) 

這樣,你應該只需要很少的加載到內存(理論上4文件句柄和當前行的內容)

+0

這是一個奇妙的想法。我會試試這個,謝謝! – Kipp 2012-07-16 16:56:56

0

這裏是我的[第二,更緊湊]努力:

import sys 
import itertools 

def reader(fileobj, yield_at_line=False): 
    for line in fileobj: 
     if line.startswith('@'): 
      at_line = line.lstrip('@').rstrip('\n') 
      next_line = fileobj.next().rstrip('\n') 
      yield (at_line, next_line) if yield_at_line else next_line 

with open(sys.argv[1]) as file1, open(sys.argv[2]) as file2, open(sys.argv[3], "w") as file3: 
    first = reader(file1, yield_at_line=True) 
    second = reader(file2) 
    for (a,b), c in itertools.izip(first, second): 
     file3.write('>{}\n{}:{}\n'.format(a, b, c)) 

這給

~/coding$ cat file1 
@Read.Salmonella_paratyphi_A_chromosome.29004.4835/1 
TCGTGTACAGCATTCTTTATAGTGGAACGGTGACCGTACCGCAAAGCTGCGAAATCAACGCCGGACKIPPTCGTAG 
+ 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 

~/coding$ cat file2 
@Read.Salmonella_paratyphi_A_chromosome.29004.4835/1 
TCGTGTACAGCATTCTTTATAGTGGAACGGTGACCGTACCGCAAAGCTGCGAAATCAACGCCGGACAAACGATTCT 
+ 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 

~/coding$ python simulwork.py file1 file2 file3 
~/coding$ cat file3 
>Read.Salmonella_paratyphi_A_chromosome.29004.4835/1 
TCGTGTACAGCATTCTTTATAGTGGAACGGTGACCGTACCGCAAAGCTGCGAAATCAACGCCGGACKIPPTCGTAG:TCGTGTACAGCATTCTTTATAGTGGAACGGTGACCGTACCGCAAAGCTGCGAAATCAACGCCGGACAAACGATTCT 
+0

感謝您解決問題的代碼,這非常棒 – Kipp 2012-07-16 17:07:25