通过平均多个单元简化矩阵

时间:2015-04-03 16:17:21

标签: python arrays list numpy matrix

我有一个较大的2D numpy矩阵,需要做得更小(例如:从100x100转换为10x10)。

我的目标基本上是:将 nxn 矩阵分解为较小的 mxm 矩阵,平均这些 mxm 切片中的单元格,然后构建一个这些 mxm 切片中的新(较小)矩阵。

我正在考虑使用matrix[a::b, c::d]之类的东西来提取较小的矩阵,然后对这些值进行平均,但这似乎过于复杂。有没有更好的方法来实现这一目标?

3 个答案:

答案 0 :(得分:5)

您可以使用view_as_blocks功能(在scikit-image中)将数组拆分为块。

对于2D数组,这将返回一个4D数组,其中的行按行排序:

>>> import skimage.util as ski
>>> import numpy as np
>>> a = np.arange(16).reshape(4,4) # 4x4 array
>>> ski.view_as_blocks(a, (2,2))
array([[[[ 0,  1],
         [ 4,  5]],

        [[ 2,  3],
         [ 6,  7]]],


       [[[ 8,  9],
         [12, 13]],

        [[10, 11],
         [14, 15]]]])

沿最后两个轴取平均值将返回一个2D数组,其中每个块的均值为

>>> ski.view_as_blocks(a, (2,2)).mean(axis=(2,3))
array([[  2.5,   4.5],
       [ 10.5,  12.5]])

注意view_as_blocks通过修改步幅返回数组视图(它也适用于具有两个以上维度的数组)。它使用as_strided纯粹在NumPy中实现,因此如果您无法访问scikit-image库,可以copy the code from here

答案 1 :(得分:1)

如果没有ski-learn,您可以简单地重塑,并采取适当的方法。

M=np.arange(10000).reshape(100,100)
M1=M.reshape(10,10,10,10)
M2=M1.mean(axis=(1,3))

快速检查我是否有正确的轴

In [127]: M2[0,0]
Out[127]: 454.5

In [128]: M[:10,:10].mean()
Out[128]: 454.5

In [131]: M[-10:,-10:].mean()
Out[131]: 9544.5

In [132]: M2[-1,-1]
Out[132]: 9544.5

添加.transpose([0,2,1,3])会将2个平均维度放在最后,如view_as_blocks所示。

对于这个(100,100)案例,重塑方法比as_strided方法快2倍,但两者都非常快。

然而,直接跨越解决方案并不比重塑慢得多。

as_strided(M,shape=(10,10,10,10),strides=(8000,80,800,8)).mean((2,3))
as_strided(M,shape=(10,10,10,10),strides=(8000,800,80,8)).mean((1,3))

答案 2 :(得分:0)

我迟到了,但我建议scipy.ndimage.zoom()作为现成的解决方案。它使用从0到5的任意顺序的样条插值进行缩小(或升大)。根据您的问题,听起来像0阶段就足够了。

from scipy import ndimage as ndi
import numpy as np

M=np.arange(1000000).reshape(1000,1000)

shrinkby=10

Mfilt = ndi.filters.uniform_filter(input=M, size=shrinkby)
Msmall = ndi.interpolation.zoom(input=Mfilt, zoom=1./shrinkby, order=0)

这就是你所需要的一切。指定缩放而不是所需的输出大小可能稍微不方便,但至少order=0此方法非常快。

输出大小是每个维度输入的10%,即

print M.shape, Msmall.shape

给出(1000, 1000) (100, 100)以及从

获得的速度
%timeit Mfilt = ndi.filters.uniform_filter(input=M, size=shrinkby)
%timeit Msmall = ndi.interpolation.zoom(input=Mfilt, zoom=1./shrinkby, order=0)

在我的计算机上,10 loops, best of 3: 20.5 ms per loop来电uniform_filter1000 loops, best of 3: 1.67 ms per loop来电zoom。{/ p>