Manera rápida de muestrear la matriz numpy mediante el mosaico del vecino más cercano

Tengo una matriz 2D de enteros que es MxN , y me gustaría expandir la matriz a (BM) x (BN) donde B es la longitud de un lado de mosaico cuadrado, por lo tanto, cada elemento de la matriz de entrada se repite como un bloque BxB en la matriz final. A continuación se muestra un ejemplo con un bucle nested. ¿Hay una manera más rápida / incorporada?

import numpy as np a = np.arange(9).reshape([3,3]) # input array - 3x3 B=2. # block size - 2 A = np.zeros([a.shape[0]*B,a.shape[1]*B]) # output array - 6x6 # Loop, filling A with tiled values of a at each index for i,l in enumerate(a): # lines in a for j,aij in enumerate(l): # a[i,j] A[B*i:B*(i+1),B*j:B*(j+1)] = aij 

Resultado …

 a= [[0 1 2] [3 4 5] [6 7 8]] A = [[ 0. 0. 1. 1. 2. 2.] [ 0. 0. 1. 1. 2. 2.] [ 3. 3. 4. 4. 5. 5.] [ 3. 3. 4. 4. 5. 5.] [ 6. 6. 7. 7. 8. 8.] [ 6. 6. 7. 7. 8. 8.]] 

Related of "Manera rápida de muestrear la matriz numpy mediante el mosaico del vecino más cercano"

Una opcion es

 >>> a.repeat(2, axis=0).repeat(2, axis=1) array([[0, 0, 1, 1, 2, 2], [0, 0, 1, 1, 2, 2], [3, 3, 4, 4, 5, 5], [3, 3, 4, 4, 5, 5], [6, 6, 7, 7, 8, 8], [6, 6, 7, 7, 8, 8]]) 

Esto es un desperdicio debido al conjunto intermedio, pero al menos es conciso.

Esta es una forma potencialmente rápida de usar trucos y remodelación de zancadas:

 from numpy.lib.stride_tricks import as_strided def tile_array(a, b0, b1): r, c = a.shape # number of rows/columns rs, cs = a.strides # row/column strides x = as_strided(a, (r, b0, c, b1), (rs, 0, cs, 0)) # view a as larger 4D array return x.reshape(r*b0, c*b1) # create new 2D array 

Los datos subyacentes en a se copian cuando se llama reshape , por lo que esta función no devuelve una vista. Sin embargo, en comparación con el uso de repeat en varios ejes, se requieren menos operaciones de copia.

La función se puede utilizar de la siguiente manera:

 >>> a = np.arange(9).reshape(3, 3) >>> a array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) >>> tile_array(a, 2, 2) array([[0, 0, 1, 1, 2, 2], [0, 0, 1, 1, 2, 2], [3, 3, 4, 4, 5, 5], [3, 3, 4, 4, 5, 5], [6, 6, 7, 7, 8, 8], [6, 6, 7, 7, 8, 8]]) >>> tile_array(a, 3, 4) array([[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2], [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2], [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2], [3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5], [3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5], [3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5], [6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8], [6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8], [6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8]]) 

Ahora, para bloques pequeños , este método es un poco más lento que usar repeat pero más rápido que kron .

Para bloques ligeramente más grandes, sin embargo, se vuelve más rápido que otras alternativas. Por ejemplo, usando una forma de bloque de (20, 20) :

 >>> %timeit tile_array(a, 20, 20) 100000 loops, best of 3: 18.7 µs per loop >>> %timeit a.repeat(20, axis=0).repeat(20, axis=1) 10000 loops, best of 3: 26 µs per loop >>> %timeit np.kron(a, np.ones((20,20), a.dtype)) 10000 loops, best of 3: 106 µs per loop 

La brecha entre los métodos aumenta a medida que aumenta el tamaño del bloque.

Además, si a es una matriz grande, puede ser más rápido que las alternativas:

 >>> a2 = np.arange(1000000).reshape(1000, 1000) >>> %timeit tile_array(a2, 2, 2) 100 loops, best of 3: 11.4 ms per loop >>> %timeit a2.repeat(2, axis=0).repeat(2, axis=1) 1 loops, best of 3: 30.9 ms per loop 

Probablemente no sea el más rápido, pero ..

 np.kron(a, np.ones((B,B), a.dtype)) 

Hace el producto Kronecker , por lo que implica una multiplicación para cada elemento en la salida.