2016-09-08 1 views
2

Ich muss gleichzeitig zwei voneinander abhängige Felder füllen, auf der Grundlage ihrer vorherigen Element, etwa so:numpy Vektorisierung von interdependenten Arrays

import numpy as np 
a = np.zeros(100) 
b = np.zeros(100) 
c = np.random.random(100) 

for num in range(1, len(a)): 
    a[num] = b[num-1] + c[num] 
    b[num] = b[num-1] + a[num] 

Gibt es eine Möglichkeit, um wirklich vectorize diese (dh nicht mit numpy.vectorize) unter Verwendung von numpig? Beachten Sie, dass dies willkürliche Arrays sind, die keine Lösung für diese spezifischen Werte suchen.

+0

Sie nach einem Weg suchen, das für diese spezifischen Werte von 'a' zu tun, 'b' und 'c', oder ist es für beliebige Werte von 'c'? – Praveen

+0

@ Praveen, willkürliche Werte für alle genannten Arrays, ich bin nur auf der Suche nach einer generischen Lösung für dieses Problem. – gucciolo

Antwort

3

Wie in @ Praveens Beitrag erwähnt, können wir diese Ausdrücke für wenige Iterationen schreiben, die versuchen, die geschlossene Form zu finden, und das wäre natürlich eine Dreiecksmatrix für c. Dann müssen wir nur iterativ-skalierteb[0] hinzufügen, um volle b zu erhalten. Um a zu erhalten, fügen wir einfach verschobene Versionen von b und c hinzu.

Also, umsetzungs weise ist hier eine andere Perspektive auf es einige NumPy broadcasting und dot-product Gründen der Effizienz, mit -

p = 2**np.arange(a.size-1) 
scale1 = p[:,None]//p 
b_out = np.append(b[0],scale1.dot(c[1:]) + 2*p*b[0]) 
a_out = np.append(a[0],b_out[:-1] + c[1:]) 

Wenn a und b gemeint sind immer als 0 beginnen zu sein, den Code für die letzten beiden Schritte würden vereinfachen -

b_out = np.append(0,scale1.dot(c[1:])) 
a_out = np.append(0,b_out[:-1] + c[1:]) 
+0

Danke @Divakar! – gucciolo

2

Ja, es gibt:

c = np.arange(100) 
a = 2 ** c - 1 
b = numpy.cumsum(a) 
+0

Danke @Nils, ich suchte nach einer generischen Lösung für das Problem und nicht für bestimmte Werte von 'c', ich aktualisierte meine Frage. – gucciolo

+0

Eine Lösung für Ihr Problem sollte nach den hier von Nils geposteten Linien möglich sein; obwohl ich nicht überprüft habe, ob das genau ist. –

+1

Danke @Eelco, ich habe Probleme zu verstehen, wie dies an einen nicht-analytischen Fall angepasst werden könnte. Wenn 'c' mit Zufallszahlen gefüllt ist (siehe meine aktualisierte Frage), kann die zweite Zeile in @Nils-Lösung nicht durch eine analoge Vektorisierung ersetzt werden, ist das richtig? – gucciolo

1

Offensichtlich sind die Updates:

a_i = b_i-1 + c_i 
b_i = 2*b_i-1 + c_i 

die Rekursion Schreiben aus,

b_0 = c_0    # I'm not sure if c_0 is to be used 
b_1 = 2*b_0 + c_1 
    = 2*c_0 + c_1 
b_2 = 2*b_1 + c_2 
    = 2*(2*c_0 + c_1) + c_2 
    = 4*c_0 + 2*c_1 + c_2 
b_3 = 2*b_2 + c_3 
    = 2*(4*c_0 + 2*c_1 + c_2) + c_3 
    = 8*c_0 + 4*c_1 + 2*c_2 + c_3 

So scheint es, dass

b_i = np.sum((2**np.arange(i+1))[::-1] * c[:i]) 
a_i = b_i-1 + c_i 

Es ist hier nicht möglich, eine kumulative Summe zu erstellen, da sich der Koeffizient c_i ständig ändert.

Der einfachste Weg, um dies vollständig zu vektorisieren, ist wahrscheinlich nur eine riesige Matrix zu verwenden. Wenn c Größe hat N:

t = np.zeros((N, N)) 
x, y = np.tril_indices(N) 
t[x, y] = 2 ** (x - y) 

Das gibt uns:

>>> t 
array([[ 1., 0., 0., 0.], 
     [ 2., 1., 0., 0.], 
     [ 4., 2., 1., 0.], 
     [ 8., 4., 2., 1.]]) 

So, jetzt können Sie tun:

b = np.sum(t * c, axis=1) 
a = np.zeros(N) 
a[1:] = b[:-1] + c[1:] 

Ich würde wahrscheinlich diese Lösung nicht empfehlen. Von dem, was ich über Rechenmethoden weiß, scheint dies für große N nicht numerisch stabil zu sein. Aber ich habe das Gefühl, dass dies für jede vektorisierte Lösung gilt, die die Summierung am Ende durchführt. Vielleicht solltest du sowohl die for-Schleife als auch dieses Stück Code ausprobieren und sehen, ob deine Fehler mit der vektorisierten Lösung in die Luft gehen.

+0

Danke @Praveen! Versucht, die Ergebnisse zu replizieren, aber "a" und "b" unterscheiden sich von den Ergebnissen der Schleife. Trotzdem eine großartige Erklärung, wie man dahin kommt. – gucciolo