scikit - Extrae bloques o parches de NumPy Array
scikits python (3)
Tengo una matriz numpy de 2 días de la siguiente manera:
a = np.array([[1,5,9,13],
[2,6,10,14],
[3,7,11,15],
[4,8,12,16]]
Quiero extraerlo en parches de 2 por 2 tamaños sin repetir los elementos.
La respuesta debería ser exactamente la misma. Puede ser una matriz tridimensional o una lista con el mismo orden de elementos que a continuación:
[[[1,5],
[2,6]],
[[3,7],
[4,8]],
[[9,13],
[10,14]],
[[11,15],
[12,16]]]
¿Cómo puede hacerlo fácilmente?
En mi problema real, el tamaño de a es (36, 72). No puedo hacerlo uno por uno. Quiero una forma programática de hacerlo.
Aquí hay un numby uníptico bastante críptico para generar su matriz de 3-d, llamado result1
aquí:
In [60]: x
Out[60]:
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 [61]: result1 = x.reshape(x.shape[0]/2, 2, x.shape[1]/2, 2).swapaxes(1, 2).reshape(-1, 2, 2)
result1
es como una matriz de 1-d de matrices de 2-d:
In [68]: result1.shape
Out[68]: (20, 2, 2)
In [69]: result1[0]
Out[69]:
array([[2, 1],
[3, 1]])
In [70]: result1[1]
Out[70]:
array([[2, 2],
[2, 1]])
In [71]: result1[5]
Out[71]:
array([[2, 0],
[0, 1]])
In [72]: result1[-1]
Out[72]:
array([[1, 2],
[2, 1]])
(Lo siento, no tengo tiempo en este momento para dar un desglose detallado de cómo funciona. Tal vez más tarde ...)
Aquí hay una versión menos críptica que usa una lista anidada de comprensión. En este caso, result2
es una lista de python de matrices numpy de 2 días:
In [73]: result2 = [x[2*j:2*j+2, 2*k:2*k+2] for j in range(x.shape[0]/2) for k in range(x.shape[1]/2)]
In [74]: result2[5]
Out[74]:
array([[2, 0],
[0, 1]])
In [75]: result2[-1]
Out[75]:
array([[1, 2],
[2, 1]])
Puede lograrlo con una combinación de np.reshape
y np.swapaxes
como tal -
def extract_blocks(a, blocksize):
M,N = a.shape
b0, b1 = blocksize
return a.reshape(M//b0,b0,N//b1,b1).swapaxes(1,2).reshape(-1,b0,b1)
Casos de muestra
Usemos una matriz de entrada de muestra, como ese:
In [94]: a
Out[94]:
array([[2, 2, 6, 1, 3, 6],
[1, 0, 1, 0, 0, 3],
[4, 0, 0, 4, 1, 7],
[3, 2, 4, 7, 2, 4],
[8, 0, 7, 3, 4, 6],
[1, 5, 6, 2, 1, 8]])
Ahora, usemos algunos tamaños de bloque para probar. Usemos dos casos con tamaños de bloques de (2,3)
y (3,3)
.
Caso 1 :
In [95]: extract_blocks(a, (2,3)) # Blocksize : (2,3)
Out[95]:
array([[[2, 2, 6],
[1, 0, 1]],
[[1, 3, 6],
[0, 0, 3]],
[[4, 0, 0],
[3, 2, 4]],
[[4, 1, 7],
[7, 2, 4]],
[[8, 0, 7],
[1, 5, 6]],
[[3, 4, 6],
[2, 1, 8]]])
Caso # 2:
In [96]: extract_blocks(a, (3,3)) # Blocksize : (3,3)
Out[96]:
array([[[2, 2, 6],
[1, 0, 1],
[4, 0, 0]],
[[1, 3, 6],
[0, 0, 3],
[4, 1, 7]],
[[3, 2, 4],
[8, 0, 7],
[1, 5, 6]],
[[7, 2, 4],
[3, 4, 6],
[2, 1, 8]]])
Usando scikit-image:
import numpy as np
from skimage.util import view_as_blocks
a = np.array([[1,5,9,13],
[2,6,10,14],
[3,7,11,15],
[4,8,12,16]])
print(view_as_blocks(a, (2, 2)))