Как я могу векторизовать усреднение 2x2 подмассивов массива numpy?

У меня есть очень большой массив 2D numpy, который содержит подмножества 2x2, которые мне нужно взять в среднем. Я ищу способ векторизации этой операции. Например, учитывая х:

#               |- 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 векторизованные/эффективные способы выполнения агрегатов на таких подмножествах?


person MarkD    schedule 11.11.2014    source источник
comment
вы можете взглянуть на это: stackoverflow.com/questions/16856788/ конечно, после этого вы можете использовать np.mean(arr, axis=-1)   -  person dashesy    schedule 11.11.2014
comment
В Scikit Image есть функция, которая выполняет трюк с изменением формы, если вы обнаружите, что пишете ее неоднократно: scikit-image.org/docs/dev/api/skimage.util.html#view-as-blocks   -  person YXD    schedule 12.11.2014


Ответы (1)


Если мы формируем измененную матрицу y = x.reshape(2,2,3,2), то подматрица (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), где 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 ]])
person Warren Weckesser    schedule 11.11.2014