2015-09-29 11 views
8

Ho una matrice 2D di interi che è MxN, e mi vorrebbe espandere l'array di (BM) x (BN) dove B è il lunghezza di un lato di piastrella quadrata, quindi ogni elemento dell'array di input viene ripetuto come blocco BxB nell'array finale. Di seguito è riportato un esempio con un ciclo annidato per. C'è un modo più veloce/integrato?modo rapido per upsample gamma NumPy da vicino più prossimo piastrelle

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 

Risultato ...

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

risposta

11

Una possibilità è

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

Questo è leggermente spreco dovuto alla matrice intermedia, ma è conciso, almeno.

3
non

Probabilmente il più veloce, ma ..

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

Si fa il Kronecker product, quindi si tratta di una moltiplicazione per ogni elemento nell'output.

11

Ecco un modo potenzialmente veloce utilizzando trucchi falcata e rimodellando:

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 

I dati sottostanti in a viene copiato quando reshape è chiamato, quindi questa funzione non restituisce la vista. Tuttavia, rispetto all'utilizzo di repeat lungo più assi, sono necessarie meno operazioni di copia.

la funzione può essere quindi utilizzato come segue:

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

Ora, per piccoli blocchi, questo metodo è un po 'più lento rispetto all'utilizzo repeat ma più veloce kron.

Per blocchi leggermente più grandi, tuttavia, diventa più veloce rispetto ad altre alternative. Ad esempio, utilizzando una forma di blocco (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 

Il divario tra i metodi aumenta all'aumentare della dimensione del blocco.

Anche se a è una vasta gamma, può essere più veloce rispetto alle alternative:

>>> 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 
Problemi correlati