Calcolo della media numpy per elemento per array 2D

Oct 01 2020

Sono nuovo in Python e devo affrontare un problema di calcolo del valore medio in termini di elemento nell'array numpy 2D. Ho cercato nel web e non ho trovato l'algoritmo ottimale per questa roba.

Quindi, ad esempio, ho questo array 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]])

Voglio ottenere un altro array numpy 2D con gli elementi uguali ai valori medi per elemento della matrice precedente. Inoltre, il mio obiettivo è avere la matrice di output con la stessa forma della matrice di input.

Ad esempio, ho selezionato un blocco 3 * 3 di elementi di vicinato e inizio con il primo elemento di matrice (zero):

Dato che è un elemento 'angolo' non possiamo calcolare la media di 3 * 3, quindi presumo che possiamo calcolare la media di 2 * 2: (0 + 1 + 5 + 6): 4 = 3

Quindi spostiamo il nostro blocco 3 * 3 sull'elemento successivo:

E calcola la media allo stesso modo e così via per la prima riga della matrice. Spostamento riga per riga, elemento per elemento:

E calcola la loro media allo stesso modo: (0 + 1 + 2 + 5 + 6 + 7 + 10 + 11 + 12): 9 = 6

E così via.

Puoi dirmi per favore come è possibile creare la matrice degli elementi medi con la stessa forma di una matrice di input? Devo farlo funzionare con il ciclo for con 2 variabili? E come trattare gli elementi "confine" in cui non possiamo applicare il blocco completo 3 * 3 dell'elemento vicino?

Sarà davvero apprezzato per il tuo aiuto!

PS Sui miei calcoli presumo di avere la matrice del risultato finale, per questo caso:

Risposte

2 obchardon Oct 01 2020 at 17:47

Se l'utilizzo scipyè un'opzione, puoi utilizzare una convoluzione 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 produce:

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. ]])

come funziona ?

Quindi la prima convoluzione produce la somma dell'elemento desiderato:

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

E il secondo produce la ponderazione (quanti elementi sono stati sommati in ogni posizione):

 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

Puoi svolgere il tuo compito usando esclusivamente Numpy .

Per calcolare la media di un elemento e dei suoi vicini, definire la seguente funzione:

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

Quindi chiamalo per ogni indice nell'array di origine e salva il risultato in un array di destinazione:

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

Il risultato è:

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. ]])