Numpy重采样2D数组

12

我正在寻找一种快速的方法对2D numpy数组进行数字分组。所谓分组是指计算子矩阵的平均值或累积值。例如,x = numpy.arange(16).reshape(4, 4) 将被分割为4个2x2的子矩阵,并给出numpy.array([[2.5,4.5],[10.5,12.5]]),其中2.5=numpy.average([0,1,4,5])等...

如何以高效的方式执行此操作...我真的不知道如何执行这个操作......

非常感谢...


子矩阵是否保证完全适合?你有numpy 1.7可用吗(这只是很好,不是必需的)? - seberg
我有numpy 1.8dev,但我的工作需要旧版本... - user1187727
3个回答

20
您可以使用更高维度的数组视图,并沿着额外维度取平均值:
In [12]: a = np.arange(36).reshape(6, 6)

In [13]: a
Out[13]: 
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35]])

In [14]: a_view = a.reshape(3, 2, 3, 2)

In [15]: a_view.mean(axis=3).mean(axis=1)
Out[15]: 
array([[  3.5,   5.5,   7.5],
       [ 15.5,  17.5,  19.5],
       [ 27.5,  29.5,  31.5]])

一般来说,如果您想要将形状为(a, b)的数组分成(rows, cols)个容器,则应使用.reshape(rows // a, a, cols // b, b)进行重塑。还要注意.mean的顺序很重要,例如a_view.mean(axis=1).mean(axis=3)会引发错误,因为a_view.mean(axis=1)只有三个维度,尽管a_view.mean(axis=1).mean(axis=2)可以正常工作,但这使得理解所发生的情况变得更加困难。

正如现在的代码一样,仅当您可以将整数个容器放入数组中时才能正常运行,即a可以整除rows并且b可以整除cols。有方法可以处理其他情况,但您必须定义所需的行为。


5
在NumPy 1.7中,你可以使用.mean(axis=(1,3))将其压缩在一起! - seberg
1
我不知道这种重塑是可能的,太好了!不幸的是,平均值是有序依赖的,因此如何获得例如2x2子矩阵的平均值呢?在你的例子中(我的意思是角落0,1,6,7等...)? - user1187727
1
@user1187727,我不认为我理解你的问题,但[[0, 1], [6, 7]]的平均值是a_view.mean(axis=3).mean(axis=1)的第[0, 0]项。 - Jaime
我认为@user1187727混淆了事实,即重塑后的数组(使用reshape(3, 2, 3, 2)不是2x2子矩阵的数组,尽管结果仍然是正确的。 - shaman.sir

1
请查看SciPy Cookbook on rebinning,它提供了以下代码片段:
def rebin(a, *args):
    '''rebin ndarray data into a smaller ndarray of the same rank whose dimensions
    are factors of the original dimensions. eg. An array with 6 columns and 4 rows
    can be reduced to have 6,3,2 or 1 columns and 4,2 or 1 rows.
    example usages:
    >>> a=rand(6,4); b=rebin(a,3,2)
    >>> a=rand(6); b=rebin(a,2)
    '''
    shape = a.shape
    lenShape = len(shape)
    factor = asarray(shape)/asarray(args)
    evList = ['a.reshape('] + \
             ['args[%d],factor[%d],'%(i,i) for i in range(lenShape)] + \
             [')'] + ['.sum(%d)'%(i+1) for i in range(lenShape)] + \
             ['/factor[%d]'%i for i in range(lenShape)]
    print ''.join(evList)
    return eval(''.join(evList))

0

我猜你只是想知道如何一般性地构建一个能够高效处理数组的函数,就像你的例子中的numpy.reshape。所以如果性能真的很重要,而且你已经在使用numpy,你可以像numpy一样编写自己的C代码。例如,arange的实现完全是用C语言编写的。几乎所有与numpy有关的性能问题都是用C语言实现的。

但是,在这样做之前,你应该尝试在Python中实现代码,并查看性能是否足够好。尽可能使Python代码高效。如果仍然无法满足你的性能需求,那就采用C语言的方式。

你可以在文档中了解更多相关信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接