2012-09-22 44 views
5

我的主要目標是從一個巨大的浮點矩陣計算中值(按列)。例如:Python - 從文件中獲取列迭代器(不需要讀取整個文件)

a = numpy.array(([1,1,3,2,7],[4,5,8,2,3],[1,6,9,3,2])) 

numpy.median(a, axis=0) 

Out[38]: array([ 1., 5., 8., 2., 3.]) 

矩陣是太大,不適合在Python內存(約5兆兆字節),所以我把它在一個CSV文件。 所以我想跑過每一列並計算中位數。

我有沒有辦法讓列迭代器不讀取整個文件?

關於計算矩陣中位數的任何其他想法也是好的。謝謝!

+2

另請參閱:http://stackoverflow.com/questions/1053928/python-numpy-very-large-matrices –

回答

1

我會通過初始化N個空文件來做到這一點,每個列一個。然後一次讀取矩陣的一行,並將每個列條目發送到正確的文件。一旦處理完整個矩陣,返回並依次計算每個文件的中位數。

這基本上使用文件系統做矩陣轉置。一旦轉換,計算每一行的中位數很容易。

+1

感謝您的迴應!我的矩陣大小約爲5 TB,恐怕我沒有足夠的存儲空間來執行此操作:( – dbaron

3

如果你能適應每列到內存(你似乎在暗示你可以),那麼這應該工作:

import itertools 
import csv 

def columns(file_name): 
    with open(file_name) as file: 
     data = csv.reader(file) 
     columns = len(next(data)) 
    for column in range(columns): 
     with open(file_name) as file: 
      data = csv.reader(file) 
      yield [row[column] for row in data] 

該作品以找出我們有多少列有,然後遍歷文件,從每一行中取出當前列的項目。這意味着,我們至多一次使用列的大小加上一行內存的大小。這是一個非常簡單的發生器。請注意,我們必須不斷重新打開文件,因爲當我們循環遍歷迭代器時會耗盡它。

+0

如果重新打開文件存在問題,只需將for循環移出for循環並執行file.seek( 0)'inside。 –

+0

@MuMind這是一個很好的選擇重新打開一次又一次(也意味着你可以傳遞一個文件對象,如果你沒有文件名,無論出於何種原因) –

0

您可以使用bucketsort對磁盤上的每個列進行排序,而不必將它們全部讀入內存。然後你可以簡單地選擇中間值。

或者,您可以使用UNIX awksort命令在選擇中位數之前拆分並對列進行排序。

1

可能沒有直接的方法來做你對csv文件的要求(除非我誤解了你)。問題是沒有任何有意義的意義,其中任何文件都有「列」,除非該文件專門設計爲具有固定寬度的行。 CSV文件通常不是這樣設計的。在磁盤上,他們比一個巨大的字符串而已:

>>> import csv 
>>> with open('foo.csv', 'wb') as f: 
...  writer = csv.writer(f) 
...  for i in range(0, 100, 10): 
...   writer.writerow(range(i, i + 10)) 
... 
>>> with open('foo.csv', 'r') as f: 
...  f.read() 
... 
'0,1,2,3,4,5,6,7,8,9\r\n10,11,12,13,14,15,16,17,18,19\r\n20..(output truncated).. 

正如你所看到的,列字段不排隊預見的;第二列從索引2開始,但在下一行中,列的寬度增加1,從而排除對齊。當輸入長度變化時,情況會更糟糕。結果是csv閱讀器將不得不讀取整個文件,丟棄你不使用的數據。 (如果你不介意的話,那麼這就是答案 - 一行一行讀取整個文件,扔掉你不會用到的數據。)

如果你不介意浪費一些空間,並知道您的數據都不會超過某個固定寬度,您可以創建一個帶有固定寬度字段的文件,然後您可以使用偏移量來查找它。但是,一旦你這樣做了,你就可以開始使用真正的數據庫了。 PyTables似乎是許多用於存儲numpy陣列的最佳選擇。

+1

+1如果你打算要做到這一點不止一次,CSV是一個很好的選擇,以保持它。 –

+0

@senderle DB是我的目標。你知道如果numpy.loadtxt(file_path,usecols = [1,2,3])會做現在呢? – dbaron

+0

@dbaron,它只是取決於你的意思是「訣竅」。我敢肯定,'usecols = [1,2,3]'會避免將整個矩陣一次加載到內存中,所以從這個意義上說,是的,我也很肯定它會一行一行地讀取整個文件,拋出未使用的數據,所以在這個s中恩斯,沒有。 – senderle