Máximo de vientos en cantidad

Tengo una matriz y me gustaría producir una matriz más pequeña escaneando una ventana no superpuesta de 2×2 y obteniendo el máximo. Aquí hay un ejemplo:

import numpy as np np.random.seed(123) np.set_printoptions(linewidth=1000,precision=3) arr = np.random.uniform(-1,1,(4,4)) res = np.zeros((2,2)) for i in xrange(res.shape[0]): for j in xrange(res.shape[1]): ii = i*2 jj = j*2 res[i][j] = max(arr[ii][jj],arr[ii+1][jj],arr[ii][jj+1],arr[ii+1][jj+1]) print arr print res 

Así que una matriz como esta:

 [[ 0.393 -0.428 -0.546 0.103] [ 0.439 -0.154 0.962 0.37 ] [-0.038 -0.216 -0.314 0.458] [-0.123 -0.881 -0.204 0.476]] 

Debería convertirse en esto:

 [[ 0.439 0.962] [-0.038 0.476]] 

¿Cómo puedo hacer esto más eficientemente?

Puedes hacerlo:

 print arr.reshape(2,2,2,2).swapaxes(1,2).reshape(2,2,4).max(axis=-1) [[ 0.439 0.962] [-0.038 0.476]] 

Para explicar comenzando con:

 arr=np.array([[0.393,-0.428,-0.546,0.103], [0.439,-0.154,0.962,0.37,], [-0.038,-0.216,-0.314,0.458], [-0.123,-0.881,-0.204,0.476]]) 

Primero queremos agrupar los ejes en secciones relevantes.

 tmp = arr.reshape(2,2,2,2).swapaxes(1,2) print tmp [[[[ 0.393 -0.428] [ 0.439 -0.154]] [[-0.546 0.103] [ 0.962 0.37 ]]] [[[-0.038 -0.216] [-0.123 -0.881]] [[-0.314 0.458] [-0.204 0.476]]]] 

Remodela una vez más para obtener los grupos de datos que queremos:

 tmp = tmp.reshape(2,2,4) print tmp [[[ 0.393 -0.428 0.439 -0.154] [-0.546 0.103 0.962 0.37 ]] [[-0.038 -0.216 -0.123 -0.881] [-0.314 0.458 -0.204 0.476]]] 

Finalmente tomar el máximo a lo largo del último eje.

Esto se puede generalizar, para matrices cuadradas, a:

 k = arr.shape[0]/2 arr.reshape(k,2,k,2).swapaxes(1,2).reshape(k,k,4).max(axis=-1) 

Siguiendo los comentarios de Jamie y Dougal, podemos generalizar esto aún más:

 n = 2 #Height of window m = 2 #Width of window k = arr.shape[0] / n #Must divide evenly l = arr.shape[1] / m #Must divide evenly arr.reshape(k,n,l,m).max(axis=(-1,-3)) #Numpy >= 1.7.1 arr.reshape(k,n,l,m).max(axis=-3).max(axis=-1) #Numpy < 1.7.1 

Como mencioné en el área de comentarios, considere usar NumBa. Podría dejar su doble bucle tal como está, agregar unos 10 caracteres en un decorador y obtener un rendimiento tipo C para esto. Fácil de usar listo para usar si trabaja con la distribución “Anaconda” de Continuum Analytics de Python.

Este es casi un caso de uso perfecto para NumBa porque este algoritmo se expresa de forma mucho más natural con el doble bucle. El enfoque de remodelación explota operaciones de matriz rápidas, pero es extremadamente ilegible a menos que ya conozca el objective del progtwig. Es altamente deseable dejar funciones como esta en forma expandida y lograr velocidad al permitir que otra cosa se convierta a un lenguaje de bajo nivel después del hecho.