2017-01-24 3 views
5

I vier quadratischen Matrizen mit 3Nx3N Dimension hat, genannt A, B, C und D.Optimieren der Zuordnung zu einem Array aus verschiedenen Arrays - NumPy

Ich mag, dass sie in einer einzigen Matrix kombinieren. Der Code mit für Schleifen ist die folgende:

import numpy 
N = 3 
A = numpy.random.random((3*N, 3*N)) 
B = numpy.random.random((3*N, 3*N)) 
C = numpy.random.random((3*N, 3*N)) 
D = numpy.random.random((3*N, 3*N)) 

final = numpy.zeros((6*N, 6*N)) 

for i in range(N): 
    for j in range(N): 
     for k in range(3): 
      for l in range(3): 
       final[6*i + k][6*j + l] = A[3*i+k][3*j+l] 
       final[6*i + k + 3][6*j + l + 3] = B[3*i+k][3*j+l] 
       final[6*i + k + 3][6*j + l] = C[3*i+k][3*j+l] 
       final[6*i + k][6*j + l + 3] = D[3*i+k][3*j+l] 

Ist es möglich, die vorherige für Schleifen in einer numpythonic Art und Weise zu schreiben?

+0

(nicht zum Thema) | Ich dachte mir, das einzige Mal, dass ich jemanden "numpythonisch" sagen hörte, war eine andere Person in SO. Aber dann habe ich überprüft und das warst du auch :) – miradulo

+1

@Mitch Fast ein * Tonic *. – Divakar

+0

Ja, ich kämpfe mit verschiedenen Möglichkeiten, Schleifen auf numpythonische Weise zu machen. Das Auge ist ein Fehler, es sollte Null sein. – NunodeSousa

Antwort

4

großes Problem für array-slicing in mehrdimensionale Tensoren/Arrays zu üben!

Wir werden das Ausgangs-Array als mehrdimensionale 6D-Array initialisieren und es einfach in Scheiben schneiden und die vier Arrays, die als 4D-Arrays umgeformt werden, zuweisen. Die Absicht ist, jegliches Stapeln/Verketten zu vermeiden, da dies speziell beim Arbeiten mit großen Arrays teuer wäre, indem stattdessen mit der Neugestaltung von Eingabe-Arrays gearbeitet wird, die lediglich Ansichten sind.

Hier ist die Umsetzung -

out = np.zeros((N,2,3,N,2,3),dtype=A.dtype) 
out[:,0,:,:,0,:] = A.reshape(N,3,N,3) 
out[:,0,:,:,1,:] = D.reshape(N,3,N,3) 
out[:,1,:,:,0,:] = C.reshape(N,3,N,3) 
out[:,1,:,:,1,:] = B.reshape(N,3,N,3) 
out.shape = (6*N,6*N) 

Nur ein bisschen mehr zu erklären, wir hatten:

  |------------------------ Axes for selecting A, B, C, D 
np.zeros((N,2,3,N,2,3),dtype=A.dtype) 
        |------------------------- Axes for selecting A, B, C, D 

So zwischen auszuwählen diese beiden Achsen (zweite und fünfte) von Längen (2x2) = 4 verwendet wurden die vier Eingänge.

Runtime Test

Approaches -

def original_app(A, B, C, D): 
    final = np.zeros((6*N,6*N),dtype=A.dtype) 
    for i in range(N): 
     for j in range(N): 
      for k in range(3): 
       for l in range(3): 
        final[6*i + k][6*j + l] = A[3*i+k][3*j+l] 
        final[6*i + k + 3][6*j + l + 3] = B[3*i+k][3*j+l] 
        final[6*i + k + 3][6*j + l] = C[3*i+k][3*j+l] 
        final[6*i + k][6*j + l + 3] = D[3*i+k][3*j+l] 
    return final 

def slicing_app(A, B, C, D): 
    out = np.zeros((N,2,3,N,2,3),dtype=A.dtype) 
    out[:,0,:,:,0,:] = A.reshape(N,3,N,3) 
    out[:,0,:,:,1,:] = D.reshape(N,3,N,3) 
    out[:,1,:,:,0,:] = C.reshape(N,3,N,3) 
    out[:,1,:,:,1,:] = B.reshape(N,3,N,3) 
    return out.reshape(6*N,6*N) 

Timings und Verifizierung -

In [147]: # Setup input arrays 
    ...: N = 200 
    ...: A = np.random.randint(11,99,(3*N,3*N)) 
    ...: B = np.random.randint(11,99,(3*N,3*N)) 
    ...: C = np.random.randint(11,99,(3*N,3*N)) 
    ...: D = np.random.randint(11,99,(3*N,3*N)) 
    ...: 

In [148]: np.allclose(slicing_app(A, B, C, D), original_app(A, B, C, D)) 
Out[148]: True 

In [149]: %timeit original_app(A, B, C, D) 
1 loops, best of 3: 1.63 s per loop 

In [150]: %timeit slicing_app(A, B, C, D) 
100 loops, best of 3: 9.26 ms per loop 
+0

Der Befehl 'numpy.allclose (out, final)' gibt True zurück: Dies stellt sicher, dass es das ist, was wir ausführen möchten –

+0

@GuillaumeJacquenot Danke für die Bestätigung! Laufzeittest mit dem Verifikationsteil hinzugefügt. – Divakar

1

Sie können concat em nur

concat A und B horizontal concat C und D horizontal

concat der Verbindung von AB mit dem conjucntion von CD vertikal

Beispiel:

AB = numpy.concatenate([A,B],1) 
CD = numpy.concatenate([C,D],1) 
ABCD = numpy.concatenate([AB,CD],0) 

ich hoffe das hilft :)

+0

Das Ergebnis ist nicht das erwartete: 'numpy.allclose (ABCD, final)' gibt false zurück –

+0

haben Sie versucht, nur ABCD zu drucken? es soll die gewünschte Matrix sein. Sie können (sollten) die Werte manuell überprüfen, indem Sie die Matrix drucken, um zu sehen, ob sie dem entspricht, was erwartet wird. versuche es mit kleinen 2x2 Matrizen als Beispiel/test – epattaro

+0

Du bist auf dem richtigen Weg. Meine Antwort mit 'bmat' macht diese Art von' Verkettung'. Das Layout des OPs ist jedoch komplizierter und erfordert einige Umformungen und Achsenwechsel. – hpaulj

2

Ich werde mit ein paar allgemeine Beobachtungen beginnen

Für numpy Arrays wir normalerweise die [,] Syntax verwenden, anstatt [] [] final [6 * i + k] [6 * j + l] final [6 * i + k, 6 * j + l]

Für neue Arrays von anderen bauten wir Dinge wie reshape und schneiden oft verwenden, so dass wir sie dann zusammen als Blöcke hinzufügen können, anstatt mit Iterationsschleifen

Für ein einfaches Beispiel, um aufeinanderfolgende Unterschiede zu nehmen:

y = x[1:] - x[:-1] 

In Bezug auf den Titel ist "Matrix-Erstellung" klarer. 'load' hat mehr den Sinn, Daten aus einer Datei zu lesen, wie in np.loadtxt.

=================

So mit N=1,

In [171]: A=np.arange(0,9).reshape(3,3) 
In [172]: B=np.arange(10,19).reshape(3,3) 
In [173]: C=np.arange(20,29).reshape(3,3) 
In [174]: D=np.arange(30,39).reshape(3,3) 

In [178]: final 
Out[178]: 
array([[ 0, 1, 2, 30, 31, 32], 
     [ 3, 4, 5, 33, 34, 35], 
     [ 6, 7, 8, 36, 37, 38], 
     [20, 21, 22, 10, 11, 12], 
     [23, 24, 25, 13, 14, 15], 
     [26, 27, 28, 16, 17, 18]]) 

, die mit einem Anruf erstellt werden kann, um bmat:

In [183]: np.bmat([[A,D],[C,B]]).A 
Out[183]: 
array([[ 0, 1, 2, 30, 31, 32], 
     [ 3, 4, 5, 33, 34, 35], 
     [ 6, 7, 8, 36, 37, 38], 
     [20, 21, 22, 10, 11, 12], 
     [23, 24, 25, 13, 14, 15], 
     [26, 27, 28, 16, 17, 18]]) 

bmat verwendet eine Mischung aus hstack und vstack. Es erzeugt auch eine np.matrix, daher die Notwendigkeit .A. @Divakar's Lösung ist verpflichtet, schneller zu sein.

Dies stimmt nicht mit N = 3 überein. 3x3 Blöcke sind außer Betrieb. Aber das Array auf 6d zu erweitern (wie Divakar es tut) und einige Achsen zu tauschen, bringt die Unterblöcke in die richtige Reihenfolge.

Für N=3:

In [57]: block=np.bmat([[A,D],[C,B]]) 
In [58]: b1=block.A.reshape(2,3,3,2,3,3) 
In [59]: b2=b1.transpose(1,0,2,4,3,5) 
In [60]: b3=b2.reshape(18,18) 
In [61]: np.allclose(b3,final) 
Out[61]: True 

In kürzester Zeit Tests (N = 3), mein Ansatz ist etwa die Hälfte der Geschwindigkeit von slicing_app.

Als eine Frage der Kuriosität funktioniert bmat mit einem String-Eingang: np.bmat('A,D;C,B'). Das ist, weil np.matrix vor Jahren versucht hat, ein MATLAB-Gefühl zu geben.

1

Noch ein anderer Weg, das zu tun, mit view_as_blocks:

from skimage.util import view_as_blocks 

def by_blocks(): 
    final = numpy.empty((6*N,6*N)) 
    a,b,c,d,f= [view_as_blocks(X,(3,3)) for X in [A,B,C,D,final]] 
    f[0::2,0::2]=a 
    f[1::2,1::2]=b 
    f[1::2,0::2]=c 
    f[0::2,1::2]=d 
    return final 

Denken Sie nur Block für Block und lassen Sie view_as_blocks Schritte und Formen für Sie verwalten. Es ist so schnell wie andere numpige Lösungen.

Verwandte Themen