Python - 从文件中获取列迭代器(不读取整个文件)

时间:2012-09-22 21:58:13

标签: python numpy median

我的主要目标是从浮动的巨大矩阵计算中位数(按列)。例如:

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 TB),因此我将其保存在csv文件中。 所以我想遍历每一列并计算中位数。

有没有办法让我在不读取整个文件的情况下获取列迭代器?

关于计算矩阵中位数的任何其他想法也会很好。谢谢!

4 个答案:

答案 0 :(得分: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]

这可以找出我们有多少列,然后循环遍历文件,从每行中取出当前列的项目。这意味着,我们最多只使用列的大小加上一行内存的大小。这是一个非常简单的发电机。注意我们必须继续重新打开文件,因为当我们遍历它时我们耗尽了迭代器。

答案 1 :(得分:1)

我会通过初始化N个空文件来做到这一点,每个文件一个。然后一次读取一行矩阵并将每个列条目发送到正确的文件。处理完整个矩阵后,返回并按顺序计算每个文件的中位数。

这基本上使用文件系统进行矩阵转置。转换后,计算每行的中位数很容易。

答案 2 :(得分: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数组的最佳选择。

答案 3 :(得分:0)

您可以使用bucketsort对磁盘上的每个列进行排序,而无需将它们全部读入内存。然后你可以简单地选择中间值。

或者您可以使用UNIX awksort命令在选择中位数之前拆分列然后对列进行排序。