如何对numpy数组的2x2子数组进行平均向量化?

5
我是一个有用的助手,可以将文本翻译成中文。
我有一个非常大的2D numpy数组,其中包含我需要取平均值的2x2子集。我正在寻找一种向量化此操作的方法。例如,给定x:
#               |- col 0 -|   |- col 1 -|   |- col 2 -|       
x = np.array( [[ 0.0,   1.0,   2.0,   3.0,   4.0,   5.0],  # row 0
               [ 6.0,   7.0,   8.0,   9.0,  10.0,  11.0],  # row 0
               [12.0,  13.0,  14.0,  15.0,  16.0,  17.0],  # row 1
               [18.0,  19.0,  20.0,  21.0,  22.0,  23.0]]) # row 1

我需要得到一个2x3的数组,其中每个2x2子数组的平均值组成该数组,即:
result = np.array( [[ 3.5,  5.5,  7.5],
                    [15.5, 17.5, 19.5]])

因此,元素[0,0]被计算为x [0:2,0:2]的平均值,而元素[0,1]将是x [2:4,0:2]的平均值。NumPy是否有对这样的子集进行聚合的向量化/高效方法?

2
你可能想看一下这个链接:https://dev59.com/LmQn5IYBdhLWcg3wamjO 当然,在那之后,你可以使用np.mean(arr, axis=-1)。 - dashesy
Scikit Image 中有一个函数可以进行重塑操作,以防你发现自己不断地重复编写代码:http://scikit-image.org/docs/dev/api/skimage.util.html#view-as-blocks - YXD
1个回答

9
如果我们通过 x.reshape(2,2,3,2) 来形成重塑矩阵 y,那么 (i,j) 2x2 子矩阵将由 y[i,:,j,:] 给出。例如:
In [340]: x
Out[340]: 
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.]])

In [341]: y = x.reshape(2,2,3,2)

In [342]: y[0,:,0,:]
Out[342]: 
array([[ 0.,  1.],
       [ 6.,  7.]])

In [343]: y[1,:,2,:]
Out[343]: 
array([[ 16.,  17.],
       [ 22.,  23.]])

要获取2x2子矩阵的平均值,请使用mean方法,其中axis=(1,3)

In [344]: y.mean(axis=(1,3))
Out[344]: 
array([[  3.5,   5.5,   7.5],
       [ 15.5,  17.5,  19.5]])

如果你使用的是不支持在元组中使用轴的旧版本numpy,你可以这样做:
In [345]: y.mean(axis=1).mean(axis=-1)
Out[345]: 
array([[  3.5,   5.5,   7.5],
       [ 15.5,  17.5,  19.5]])

请查看@dashesy在评论中提供的链接,获取有关重塑“技巧”的更多背景信息。


要推广到形状为(m,n)的2-d数组,其中m和n都是偶数,请使用以下方法

y = x.reshape(x.shape[0]/2, 2, x.shape[1], 2)
y可以被解释为一个2x2数组的数组。4维数组的第一和第三索引槽作为选择其中一个2x2块的索引。要获取左上角的2x2块,请使用y[0, :, 0, :]; 获取第二行第三列的块,请使用y[1, :, 2, :]; 通常,要访问块(j,k),请使用y[j, :, k, :]
要计算这些块的平均缩小数组,请使用mean方法,使用axis=(1, 3)(即在轴1和轴3上进行平均)。
avg = y.mean(axis=(1, 3))

以下是一个示例,其中 x 的形状为 (8, 10),因此 2x2 块的平均数组的形状为 (4, 5):

In [10]: np.random.seed(123)

In [11]: x = np.random.randint(0, 4, size=(8, 10))

In [12]: x
Out[12]: 
array([[2, 1, 2, 2, 0, 2, 2, 1, 3, 2],
       [3, 1, 2, 1, 0, 1, 2, 3, 1, 0],
       [2, 0, 3, 1, 3, 2, 1, 0, 0, 0],
       [0, 1, 3, 3, 2, 0, 3, 2, 0, 3],
       [0, 1, 0, 3, 1, 3, 0, 0, 0, 2],
       [1, 1, 2, 2, 3, 2, 1, 0, 0, 3],
       [2, 1, 0, 3, 2, 2, 2, 2, 1, 2],
       [0, 3, 3, 3, 1, 0, 2, 0, 2, 1]])

In [13]: y = x.reshape(x.shape[0]/2, 2, x.shape[1]/2, 2)

看一下其中的几个2x2块:

In [14]: y[0, :, 0, :]
Out[14]: 
array([[2, 1],
       [3, 1]])

In [15]: y[1, :, 2, :]
Out[15]: 
array([[3, 2],
       [2, 0]])

计算块的平均值:

In [16]: avg = y.mean(axis=(1, 3))

In [17]: avg
Out[17]: 
array([[ 1.75,  1.75,  0.75,  2.  ,  1.5 ],
       [ 0.75,  2.5 ,  1.75,  1.5 ,  0.75],
       [ 0.75,  1.75,  2.25,  0.25,  1.25],
       [ 1.5 ,  2.25,  1.25,  1.5 ,  1.5 ]])

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