2012-09-22 47 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