2015-09-29 3 views
8

Ich habe ein 2D-Array von ganzen Zahlen Upsampling, die MxN ist, und ich möchte das Array (BM) x (BN) expandieren, in denen B ist die Länge einer quadratischen Kachelseite, so wird jedes Element des Eingangsarrays als ein BxB Block in dem endgültigen Array wiederholt. Unten ist ein Beispiel mit einer verschachtelten for-Schleife. Gibt es einen schnelleren/eingebauten Weg?Schnell Weg numpy Array von nächsten Nachbarn Fliesen

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 

Ergebnis ...

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

Antwort

11

Eine Option ist

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

Dies aufgrund des Zwischen Array etwas verschwenderisch, aber es ist zumindest prägnant.

3

Wahrscheinlich nicht die schnellste, aber ..

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

Es tut die Kronecker product, so geht es um eine Multiplikation für jedes Element in der Ausgabe.

11

Hier ist ein potenziell schneller Weg schreiten Tricks und Umformen:

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 

Die zugrunde liegenden Daten in a kopiert wird, wenn reshape genannt wird, so dass diese Funktion gibt keinen Blick. Im Vergleich zur Verwendung von repeat entlang mehrerer Achsen sind jedoch weniger Kopiervorgänge erforderlich.

Die Funktion kann dann wie folgt verwendet werden:

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

Jetzt für kleine Blöcke, diese Methode ein wenig langsamer als repeat verwenden, aber schneller als kron.

Für etwas größere Blöcke wird es jedoch schneller als andere Alternativen. Zum Beispiel unter Verwendung einer Blockform von (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 

Der Spalt zwischen den Verfahren zu, wenn die Blockgrße zunimmt.

Auch wenn a ein großes Array ist, kann es schneller als Alternativen:

>>> 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 
Verwandte Themen