2011-01-07 22 views
15

Estoy intentando agrupar una matriz numpy en un tamaño más pequeño tomando el promedio de los elementos. Tales como tomar promedio de sub-arrays 5x5 foreach en una matriz de 100x100 para crear una matriz de tamaño de 20x20. Como tengo que manipular una gran cantidad de datos, ¿es una forma eficiente de hacerlo?Agrupación de matriz numpy 2D en promedio

+0

similares a [esta] (https://stackoverflow.com/questions/18645013/windowed-maximum-in-numpy/18645174#18645174) respuesta tan bien. – Daniel

Respuesta

23

He intentado esto de gama más pequeña, así que probarlo con la suya:

import numpy as np 

nbig = 100 
nsmall = 20 
big = np.arange(nbig * nbig).reshape([nbig, nbig]) # 100x100 

small = big.reshape([nsmall, nbig//nsmall, nsmall, nbig//nsmall]).mean(3).mean(1) 

Un ejemplo de 6x6 -> 3x3:

nbig = 6 
nsmall = 3 
big = np.arange(36).reshape([6,6]) 
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], 
     [24, 25, 26, 27, 28, 29], 
     [30, 31, 32, 33, 34, 35]]) 

small = big.reshape([nsmall, nbig//nsmall, nsmall, nbig//nsmall]).mean(3).mean(1) 

array([[ 3.5, 5.5, 7.5], 
     [ 15.5, 17.5, 19.5], 
     [ 27.5, 29.5, 31.5]]) 
4

Esto es muy sencillo, aunque me siento como que podría ser más rápido:

from __future__ import division 
import numpy as np 
Norig = 100 
Ndown = 20 
step = Norig//Ndown 
assert step == Norig/Ndown # ensure Ndown is an integer factor of Norig 
x = np.arange(Norig*Norig).reshape((Norig,Norig)) #for testing 
y = np.empty((Ndown,Ndown)) # for testing 
for yr,xr in enumerate(np.arange(0,Norig,step)): 
    for yc,xc in enumerate(np.arange(0,Norig,step)): 
     y[yr,yc] = np.mean(x[xr:xr+step,xc:xc+step]) 

También podría encontrar scipy.signal.decimate interesante. Aplica un filtro de paso bajo más sofisticado que el promedio simple antes de reducir el muestreo de los datos, aunque tendría que diezmar un eje y luego el otro.

2

media de una matriz 2D sobre subconjuntos de tamaño NxN:

height, width = data.shape 
data = average(split(average(split(data, width // N, axis=1), axis=-1), height // N, axis=1), axis=-1) 
+1

¡Bonito! Solo una aclaración de que el promedio y la división son funciones numpy. – MonkeyButter

0

Tenga en cuenta que eumiro's approach no funciona para matrices enmascarados como .mean(3).mean(1) como Sumes que cada media a lo largo del eje 3 se calculó a partir del mismo número de valores. Si hay elementos enmascarados en su matriz, esta suposición ya no se cumple. En ese caso, debe realizar un seguimiento del número de valores utilizados para calcular .mean(3) y reemplazar .mean(1) por una media ponderada. Los pesos son el número normalizado de valores utilizados para calcular .mean(3).

Aquí es un ejemplo:

import numpy as np 


def gridbox_mean_masked(data, Nbig, Nsmall): 
    # Reshape data 
    rshp = data.reshape([Nsmall, Nbig//Nsmall, Nsmall, Nbig//Nsmall]) 

    # Compute mean along axis 3 and remember the number of values each mean 
    # was computed from 
    mean3 = rshp.mean(3) 
    count3 = rshp.count(3) 

    # Compute weighted mean along axis 1 
    mean1 = (count3*mean3).sum(1)/count3.sum(1) 
    return mean1 


# Define test data 
big = np.ma.array([[1, 1, 2], 
        [1, 1, 1], 
        [1, 1, 1]]) 
big.mask = [[0, 0, 0], 
      [0, 0, 1], 
      [0, 0, 0]] 
Nbig = 3 
Nsmall = 1 

# Compute gridbox mean 
print gridbox_mean_masked(big, Nbig, Nsmall) 
Cuestiones relacionadas