2016-06-15 16 views
3

So habe ich die folgenden numpy Arrays:Vektorisierung - Hinzufügen von Arrays ohne Schleifen?

c = array([[ 1, 2, 3], 
      [ 4, 5, 6], 
      [ 7, 8, 9], 
      [10, 11, 12]]) 
X = array([[10, 15, 20, 5], 
      [ 1, 2, 6, 23]]) 
y = array([1, 1]) 

ich jede 1x4 Zeile in dem X Array zu einem der Spalten in c hinzufügen versuchen. Das y Array gibt an, welche Spalte. Das obige Beispiel bedeutet, dass wir beide Zeilen im Array X der Spalte 1 von c hinzufügen. Das heißt, wir sollten folgendes Ergebnis erwarten:

 c = array([[ 1, 2+10+1, 3], = array([[ 1, 13, 3], 
       [ 4, 5+15+2, 6],   [ 4, 22, 6], 
       [ 7, 8+20+6, 9],   [ 7, 34, 9], 
       [10, 11+5+23, 12]])   [10, 39, 12]]) 

Weiß jemand, wie ich das ohne Schleifen machen kann? Ich versuchte c[:,y] += X, aber es scheint, als ob nur die zweite Zeile von X Spalte 1 von c einmal hinzugefügt wird. Dabei ist zu beachten, dass y nicht zwingend [1,1] sein muss, es kann auch [0,1] sein. In diesem Fall würden wir die erste Reihe von X zu Spalte 0 von c und die zweite Reihe von X zu Spalte 1 von c hinzufügen.

Antwort

3

Mein erster Gedanke, als ich die gewünschte Berechnung sah, war nur noch die zwei Reihen von X zu summieren, und fügen hinzu, dass in die 2. Spalte von c:

In [636]: c = array([[ 1, 2, 3], 
      [ 4, 5, 6], 
      [ 7, 8, 9], 
      [10, 11, 12]]) 

In [637]: c[:,1]+=X.sum(axis=0) 

In [638]: c 
Out[638]: 
array([[ 1, 13, 3], 
     [ 4, 22, 6], 
     [ 7, 34, 9], 
     [10, 39, 12]]) 

Aber wenn wir wollen, von einem allgemeinen arbeiten Index wie y, brauchen wir einen besonderen bufferless Betrieb - das heißt, wenn es Duplikate in y:

In [639]: c = array([[ 1, 2, 3], 
      [ 4, 5, 6], 
      [ 7, 8, 9], 
      [10, 11, 12]]) 

In [641]: np.add.at(c,(slice(None),y),X.T) 

In [642]: c 
Out[642]: 
array([[ 1, 13, 3], 
     [ 4, 22, 6], 
     [ 7, 34, 9], 
     [10, 39, 12]]) 

Sie müssen .at im nu sehen mpy Dokumente.

in IPython add.at? zeigt mir den doc, der folgendes beinhaltet:

Führt ungepufferte anstelle Operation auf Operanden 'a' für Elemente angegeben durch 'Indizes'. Für den Zusatz ufunc ist diese Methode äquivalent zu a[indices] += b, außer dass die Ergebnisse für Elemente gesammelt werden, die mehrfach indiziert sind.Zum Beispiel wird nur a[[0,0]] += 1 das erste Element inkrementiert einmal wegen der Pufferung, während add.at(a, [0,0], 1) zweimal das erste Element inkrementieren.

Mit einem anderen y es funktioniert immer noch

In [645]: np.add.at(c,(slice(None),[0,2]),X.T) 

In [646]: c 
Out[646]: 
array([[11, 2, 4], 
     [19, 5, 8], 
     [27, 8, 15], 
     [15, 11, 35]]) 
+1

Ich weiß nicht, ob es klarer ist, aber weil e '.T' gibt eine Ansicht zurück, Sie können das gleiche Ergebnis erhalten, indem Sie alles transponieren, was zu einer einfacheren Indizierung führt, d. h.' np.add.at (c.T, y, X) 'erzeugt den gleichen Effekt. – Jaime

+0

Vielen Dank für den Auszug über Universalfunktionen, sehr nützlich! – Tonechas

0

Erstens scheint Ihr Code im Allgemeinen zu funktionieren, wenn Sie X transponieren. Zum Beispiel:

c = array([[ 1, 2, 3], 
      [ 4, 5, 6], 
      [ 7, 8, 9], 
      [10, 11, 12]]) 
X = array([[10, 15, 20, 5], 
      [ 1, 2, 6, 23]]).transpose() 
y = array([1, 2]) 

c[:,y] += X 
print c 
#OUTPUT: 
#[[ 1 12 4] 
# [ 4 20 8] 
# [ 7 28 15] 
# [10 16 35]] 

Allerdings funktioniert es nicht, wenn es in y, wie in Ihrem speziellen Beispiel alle doppelten Spalten sind. Ich glaube, das liegt daran, c[:, [1,1]] wird ein Array mit zwei Spalten generieren, die jeweils die Scheibe c[:, 1] haben. Beide Schichten zeigen auf den gleichen Teil von c, und wenn die Addition bei jedem auftritt, werden beide gelesen, dann wird der entsprechende Teil von X zu jedem hinzugefügt, dann werden sie zurückgeschrieben, was bedeutet, dass der letzte geschrieben wird Zurück ist der Endwert. Ich glaube nicht, dass Sie mit numpy eine Operation wie diese vektorisieren können, weil das grundsätzlich nicht möglich ist. Dazu müssen Sie jeweils eine Spalte bearbeiten, den Wert speichern und später erneut bearbeiten.

Sie müssen sich vielleicht mit keinen Duplikaten zufrieden geben oder anderweitig etwas wie einen Akkumulator implementieren.

0

Dies ist die Lösung kam ich mit:

def my_func(c, X, y): 
    cc = np.zeros((len(y), c.shape[0], c.shape[1])) 
    cc[range(len(y)), :, y] = X 
    return c + np.sum(cc, 0) 

Die folgende interaktive Sitzung zeigt, wie es funktioniert:

>>> my_func(c, X, y) 
array([[ 1., 13., 3.], 
     [ 4., 22., 6.], 
     [ 7., 34., 9.], 
     [ 10., 39., 12.]]) 
>>> y2 = np.array([0, 2]) 
>>> my_func(c, X, y2) 
array([[ 11., 2., 4.], 
     [ 19., 5., 8.], 
     [ 27., 8., 15.], 
     [ 15., 11., 35.]]) 
Verwandte Themen