使用numpy数组高效地索引numpy数组



我有一个非常(非常、非常(大的二维数组,大约有一千列,但有几百万行(足够让它无法放入32GB机器上的内存(。我想计算一千列中每一列的方差。一个有帮助的关键事实是:我的数据是8位无符号整数。

以下是我的计划。我将首先构造一个新的二维数组,称为counts,其形状为(1000256(,其思想是counts[i,:] == np.bincount(bigarray[:,i])。一旦我有了这个数组,计算方差就变得微不足道了。

问题是,我不确定如何有效地计算它(这种计算必须实时运行,我希望带宽受到SSD返回数据速度的限制(。这是一种有效的方法,但速度慢得可怕:

counts = np.array((1000,256))
for row in iterator_over_bigaray_rows():
    for i,val in enumerate(row):
        counts[i,val] += 1

有没有办法写这个来跑得更快?类似这样的东西:

counts = np.array((1000,256))
for row in iterator_over_bigaray_rows():
    counts[i,:] = // magic np one-liner to do what I want

我想这就是你想要的:

counts[np.arange(1000), row] += 1

但是,如果您的数组有数百万行,您仍然需要对其中的数百万行进行迭代。以下技巧使我的系统加速接近5倍:

chunk = np.random.randint(256, size=(1000, 1000))
def count_chunk(chunk):
    rows, cols = chunk.shape
    col_idx = np.arange(cols) * 256
    counts = np.bincount((col_idx[None, :] + chunk).ravel(),
                         minlength=256*cols)
    return counts.reshape(-1, 256)
def count_chunk_by_rows(chunk):
    counts = np.zeros(chunk.shape[1:]+(256,), dtype=np.int)
    indices = np.arange(chunk.shape[-1])
    for row in chunk:
        counts[indices, row] += 1
    return counts

现在:

In [2]: c = count_chunk_by_rows(chunk)
In [3]: d = count_chunk(chunk)
In [4]: np.all(c == d)
Out[4]: True
In [5]: %timeit count_chunk_by_rows(chunk)
10 loops, best of 3: 80.5 ms per loop
In [6]: %timeit count_chunk(chunk)
100 loops, best of 3: 13.8 ms per loop

最新更新