Cálculo médio de elemento numpy para matriz 2D

Oct 01 2020

Sou novo em Python e enfrento um problema de cálculo do valor médio do elemento em um array numpy 2D. Eu pesquisei na web e não encontrei o algoritmo ideal para essas coisas.

Então, por exemplo, eu tenho esta matriz 2D:

array = np.arange(20).reshape(4,5)
array

Out[7]: 
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12, 13, 14],
           [15, 16, 17, 18, 19]])

Quero obter outro array numpy 2D com os elementos iguais aos valores médios dos elementos da matriz anterior. Além disso, meu objetivo é ter a matriz de saída com a mesma forma da matriz de entrada.

Por exemplo, selecionei um bloco 3 * 3 de elementos de vizinhança e comecei com o primeiro elemento da matriz (zero):

Como é um elemento de 'canto', não podemos calcular a média de 3 * 3, então presumo que podemos calcular a média de 2 * 2: (0 + 1 + 5 + 6): 4 = 3

Em seguida, movemos nosso bloco 3 * 3 para o próximo elemento:

E calcule a média da mesma maneira e assim por diante para a primeira linha da matriz. Movendo linha por linha, elemento por elemento:

E calcule a média da mesma maneira: (0 + 1 + 2 + 5 + 6 + 7 + 10 + 11 + 12): 9 = 6

E assim por diante.

Você poderia me dizer por favor como é possível criar a matriz dos elementos médios com a mesma forma de uma matriz de entrada? Devo operar com loop for com 2 variáveis? E como lidar com elementos de 'fronteira' onde não podemos aplicar bloco 3 * 3 completo de elemento vizinho?

Será muito grato por sua ajuda!

PS Em meus cálculos, presumo ter a matriz de resultado final, para este caso:

Respostas

2 obchardon Oct 01 2020 at 17:47

Se usar scipyfor uma opção, você pode usar uma convolução 2D :

import numpy as np
from scipy import signal

# Example input
x = np.array([[ 0,  1,  2,  3,  4],
              [ 5,  6,  7,  8,  9],
              [10, 11, 12, 13, 14],
              [15, 16, 17, 18, 19]])

# The moving window
y = np.ones((3,3))

# We convolve x with y and then we normalize those value with another convolution
#  |        first convolution        |/|              second convolution               |
r = signal.convolve2d(x,y,mode='same')/signal.convolve2d(np.ones(x.shape),y,mode='same')

E produz:

array([[ 3. ,  3.5,  4.5,  5.5,  6. ],
       [ 5.5,  6. ,  7. ,  8. ,  8.5],
       [10.5, 11. , 12. , 13. , 13.5],
       [13. , 13.5, 14.5, 15.5, 16. ]])

como funciona ?

Portanto, a primeira convolução produz a soma do elemento desejado:

array([[ 12,  21,  27,  33,  24],
       [ 33,  54,  63,  72,  51],
       [ 63,  99, 108, 117,  81],
       [ 52,  81,  87,  93,  64]])

E o segundo produz a ponderação (quantos elementos foram somados em cada posição):

 array([[4., 6., 6., 6., 4.],
        [6., 9., 9., 9., 6.],
        [6., 9., 9., 9., 6.],
        [4., 6., 6., 6., 4.]])
1 Valdi_Bo Oct 01 2020 at 18:37

Você pode fazer sua tarefa usando apenas o Numpy .

Para calcular a média de um elemento e seus vizinhos, defina a seguinte função:

def meanSurroud(arr, r, c):
    return np.mean(arr[max(r - 1, 0) : r + 2, max(c - 1, 0) : c + 2])

Em seguida, chame-o para cada índice em sua matriz de origem e salve o resultado em uma matriz de destino:

result = np.empty_like(array, dtype=float)
for ind in np.ndindex(array.shape):
    result[ind] = meanSurroud(array, ind[0], ind[1])

O resultado é:

array([[ 3. ,  3.5,  4.5,  5.5,  6. ],
       [ 5.5,  6. ,  7. ,  8. ,  8.5],
       [10.5, 11. , 12. , 13. , 13.5],
       [13. , 13.5, 14.5, 15.5, 16. ]])