Numpy大数组的直方图

19 投票
4 回答
20360 浏览
提问于 2025-04-15 20:32

我有一堆csv格式的数据集,每个大约有10GB。现在我想从这些数据的列中生成直方图。但是,似乎在numpy中,唯一的方法是先把整列数据加载到一个numpy数组中,然后再对这个数组调用numpy.histogram。这样做会占用很多不必要的内存。

请问numpy支持在线分箱吗?我希望能有一种方法,可以逐行读取我的csv文件,并在读取时对数值进行分箱。这样的话,任何时候内存中最多只会有一行数据。

自己写一个并不难,但我想知道有没有人已经发明过这个方法。

4 个回答

6

使用芬威克树进行分箱 (非常大的数据集;需要百分位边界)

我在这里提供第二个答案,因为这种方法与之前的很不同,并且解决了不同的问题。

如果你有一个非常大的数据集(数十亿个样本),而且你不知道应该在哪里设置分箱的边界怎么办?比如,你可能想把数据分成四分位数或十分位数。

对于小型数据集,解决办法很简单:把数据放进一个数组里,然后排序,再根据百分比直接跳到数组中的相应位置读取值。

但对于大型数据集,直接用数组存储数据不太现实(更不用说排序所需的时间了)……这时候可以考虑使用芬威克树,也叫“二进制索引树”。

我认为这种方法只适用于正整数数据,所以你至少需要对你的数据集有一定了解,以便在把数据放入芬威克树之前进行适当的调整(可能还需要缩放)。

我用这种方法在合理的时间和内存限制下找到了一个包含1000亿个样本的数据集的中位数。(可以考虑使用生成器来打开和读取文件,正如我之前的回答提到的;这仍然很有用。)

关于芬威克树的更多信息:

6

这里有一种直接将你的数值分组的方法:

import numpy as NP

column_of_values = NP.random.randint(10, 99, 10)

# set the bin values:
bins = NP.array([0.0, 20.0, 50.0, 75.0])

binned_values = NP.digitize(column_of_values, bins)

'binned_values' 是一个索引数组,里面包含了每个值在 'column_of_values' 列中属于哪个分组的索引。

'bincount' 会给你(显而易见)每个分组的数量:

NP.bincount(binned_values)

考虑到你的数据集的大小,使用 Numpy 的 'loadtxt' 来创建一个生成器可能会很有用:

data_array = NP.loadtxt(data_file.txt, delimiter=",")
def fnx() :
  for i in range(0, data_array.shape[1]) :
    yield dx[:,i]
13

正如你所说,自己动手做其实并不难。你需要自己设置数据区间,并在处理文件时重复使用这些区间。下面的代码可以作为一个不错的起点:

import numpy as np
datamin = -5
datamax = 5
numbins = 20
mybins = np.linspace(datamin, datamax, numbins)
myhist = np.zeros(numbins-1, dtype='int32')
for i in range(100):
    d = np.random.randn(1000,1)
    htemp, jnk = np.histogram(d, mybins)
    myhist += htemp

我猜处理这么大的文件时,性能可能会成为一个问题,因为每处理一行都调用一次直方图可能会太慢。@doug的建议使用生成器似乎是解决这个问题的好办法。

撰写回答