Anwenden mehrerer Funktionen auf jede Zeile eines Arrays

Ich habe ein numpy Array, das nur wenige Nicht-Null-Einträge hat, die entweder positiv oder negativ sein können. So etwas wie das:

myArray = np.array([[ 0. , 0. , 0. ], [ 0.32, -6.79, 0. ], [ 0. , 0. , 0. ], [ 0. , 1.5 , 0. ], [ 0. , 0. , -1.71]]) 

Am Ende möchte ich eine Liste erhalten, bei der jeder Eintrag dieser Liste einer Zeile von myArray entspricht und ein kumulatives Produkt von Funktionsausgaben ist, die von den Einträgen der jeweiligen Zeile von myArray und einer anderen Liste abhängen (im folgenden Beispiel) Es heißt l). Die einzelnen Begriffe hängen vom Zeichen des myArray-Eintrags ab: Wenn es positiv ist, wende ich "funPos" an, wenn es negativ ist, wende ich "funNeg" an und wenn der Eintrag 0 ist, wird der Begriff 1. Also im Beispiel Array von oben wäre es:

 output = [1*1*1 , funPos(0.32, l[0])*funNeg(-6.79,l[1])*1, 1*1*1, 1*funPos(1.5, l[1])*1, 1*1*funNeg(-1.71, l[2])] 

Ich habe dies wie unten gezeigt implementiert und es gibt mir die gewünschte Ausgabe (Hinweis: Das ist nur ein sehr vereinfachtes Spielzeugbeispiel, die eigentlichen Matrizen sind weit größer und die Funktionen komplizierter). Ich gehe durch jede Zeile des Arrays, wenn die Summe der Zeile 0 ist, muss ich keine Berechnungen durchführen und die Ausgabe ist nur 1. Wenn es nicht gleich 0 ist, gehe ich durch diese Zeile, überprüfe das Zeichen Von jedem Wert und wenden Sie die entsprechende Funktion an.

 import numpy as np def doCalcOnArray(Array1, myList): output = np.ones(Array1.shape[0]) #initialize output for indRow,row in enumerate(Array1): if sum(row) != 0: #only then calculations are needed tempProd = 1. #initialize the product that corresponds to the row for indCol, valCol in enumerate(row): if valCol > 0: tempVal = funPos(valCol, myList[indCol]) elif valCol < 0: tempVal = funNeg(valCol, myList[indCol]) elif valCol == 0: tempVal = 1 tempProd = tempProd*tempVal output[indRow] = tempProd return output def funPos(val1,val2): return val1*val2 def funNeg(val1,val2): return val1*(val2+1) myArray = np.array([[ 0. , 0. , 0. ], [ 0.32, -6.79, 0. ], [ 0. , 0. , 0. ], [ 0. , 1.5 , 0. ], [ 0. , 0. , -1.71]]) l = [1.1, 2., 3.4] op = doCalcOnArray(myArray,l) print op 

Der Ausgang ist

 [ 1. -7.17024 1. 3. -7.524 ] 

Das ist das gewünschte.
Meine Frage ist, ob es eine effizientere Möglichkeit, dies zu tun, da das ist ziemlich "teuer" für große Arrays.

EDIT: Ich akzeptierte die Antwort von gabhijit, weil die reine, numpy Lösung, die er kam, der schnellste für die Arrays ist, mit denen ich mich beschäftige. Bitte beachten Sie, dass es auch eine nette Arbeitslösung von RaJa gibt, die Panda benötigt und auch die Lösung von dave funktioniert gut, die als ein gutes Beispiel für die Verwendung von Generatoren und numpys "apply_along_axis" dienen kann.

4 Solutions collect form web for “Anwenden mehrerer Funktionen auf jede Zeile eines Arrays”

Hier ist, was ich versucht habe – mit reduzieren, Karte. Ich bin nicht sicher, wie schnell das ist – aber ist das, was du versuchst zu tun?

Bearbeiten 4: Einfachste und am meisten lesbare – Machen Sie l ein numpy Array und dann stark vereinfacht where .

 import numpy as np import time l = np.array([1.0, 2.0, 3.0]) def posFunc(x,y): return x*y def negFunc(x,y): return x*(y+1) def myFunc(x, y): if x > 0: return posFunc(x, y) if x < 0: return negFunc(x, y) else: return 1.0 myArray = np.array([ [ 0.,0.,0.], [ 0.32, -6.79, 0.], [ 0.,0.,0.], [ 0.,1.5,0.], [ 0.,0., -1.71]]) t1 = time.time() a = np.array([reduce(lambda x, (y,z): x*myFunc(z,l[y]), enumerate(x), 1) for x in myArray]) t2 = time.time() print (t2-t1)*1000000 print a 

Grundsätzlich lasst uns nur die letzte Zeile betrachten, sagt es kumulativ multiplizieren die Dinge in der enumerate(xx) , beginnend mit 1 (letzter Parameter zu reduce ). MyFunc nimmt einfach das Element in myArray (Zeile) und Element @ Index Zeile in l und multipliziert sie nach Bedarf.

Meine Ausgabe ist nicht gleich wie deine – also bin ich mir nicht sicher, ob das genau das ist, was du willst, aber vielleicht kannst du der Logik folgen.

Auch bin ich nicht so sicher, wie schnell das für riesige Arrays sein wird.

Bearbeiten: Nachfolgend ist ein "reiner numpy Weg", dies zu tun.

 my = myArray # just for brevity t1 = time.time() # First set the positive and negative values # complicated - [my.itemset((x,y), posFunc(my.item(x,y), l[y])) for (x,y) in zip(*np.where(my > 0))] # changed to my = np.where(my > 0, my*l, my) # complicated - [my.itemset((x,y), negFunc(my.item(x,y), l[y])) for (x,y) in zip(*np.where(my < 0))] # changed to my = np.where(my < 0, my*(l+1), my) # print my - commented out to time it. # Now set the zeroes to 1.0s my = np.where(my == 0.0, 1.0, my) # print my - commented out to time it a = np.prod(my, axis=1) t2 = time.time() print (t2-t1)*1000000 print a 

Lassen Sie mich versuchen, den zip(*np.where(my != 0)) zu erklären zip(*np.where(my != 0)) Teil so gut ich kann. np.where einfach zwei numpy Arrays erste Array ist ein Index der Zeile, zweite Array ist ein Index der Spalte, die die Bedingung (my != 0) in diesem Fall entspricht. Wir nehmen ein Tupel dieser Indizes und verwenden dann array.itemset und array.item , dankbar, Spaltenindex steht uns kostenlos zur Verfügung, so können wir nur das Element @ diesen Index in der Liste l . Dies sollte schneller sein als vorher (und um Größenordnungen lesbar !!). Brauchen timeit , um herauszufinden, ob es tatsächlich ist.

Bearbeiten 2: Muss nicht separat für Positiv und Negativ anrufen können mit einem Anruf np.where(my != 0) getan werden.

Also, mal sehen, ob ich deine Frage verstehe.

  1. Sie wollen Elemente Ihrer Matrix einer neuen Matrix zuordnen, so dass:
    • 0 Karten zu 1
    • x>0 Karten zu funPos(x)
    • x<0 Karten zu funNeg(x)
  2. Sie wollen das Produkt aller Elemente in den Zeilen diese neue Matrix berechnen.

Also, hier ist, wie ich es tun würde:

1:

 def myFun(a): if a==0: return 1 if a>0: return funPos(a) if a<0: return funNeg(a) newFun = np.vectorize(myFun) newArray = newFun(myArray) 

Und für 2:

 np.prod(newArray, axis = 1) 

Bearbeiten: Um den Index an funPos, funNeg weiterzugeben, kannst du wohl so etwas machen:

 # Python 2.7 r,c = myArray.shape ctr = -1 # I don't understand why this should be -1 instead of 0 def myFun(a): global ctr global c ind = ctr % c ctr += 1 if a==0: return 1 if a>0: return funPos(a,l[ind]) if a<0: return funNeg(a,l[ind]) 

Ich denke, diese numpy Funktion wäre Ihnen behilflich

Numpy.apply_along_axis

Hier ist eine Implementierung. Auch würde ich vor der Prüfung warnen, wenn die Summe des Arrays 0 ist. Das Vergleichen von Floats mit 0 kann ein unerwartetes Verhalten aufgrund von Maschinengenauigkeitsbeschränkungen ergeben. Auch wenn du -5 und 5 hast, ist die Summe null und ich bin mir nicht sicher, was du willst. Ich habe numpy's irgendeine () Funktion benutzt, um zu sehen, ob irgendetwas ungleich war. Zur Vereinfachung habe ich auch deine Liste (my_list) in den Geltungsbereich gezogen.

 import numpy as np my_list = 1.1, 2., 3.4 def func_pos(val1, val2): return val1 * val2 def func_neg(val1, val2): return val1 *(val2 + 1) def my_generator(row): for i, a in enumerate(row): if a > 0: yield func_pos(a, my_list[i]) elif a < 0: yield func_neg(a, my_list[i]) else: yield 1 def reduce_row(row): if not row.any(): return 1.0 else: return np.prod(np.fromiter(my_generator(row), dtype=float)) def main(): myArray = np.array([ [ 0. , 0. , 0. ], [ 0.32, -6.79, 0. ], [ 0. , 0. , 0. ], [ 0. , 1.5 , 0. ], [ 0. , 0. , -1.71]]) return np.apply_along_axis(reduce_row, axis=1, arr=myArray) 

Es gibt wohl schnellere Implikationen, ich denke, apply_along_axis ist wirklich nur eine Schleife unter den Deckeln.

Ich habe nicht getestet, aber ich wette, das ist schneller als das, was du angefangen hast, und sollte mehr Speicher effizient sein.

Ich habe dein Beispiel mit der Maskierungsfunktion von numpy Arrays ausprobiert. Allerdings konnte ich keine Lösung finden, um die Werte in deinem Array durch FunPos oder FunNeg zu ersetzen.

Also mein Vorschlag wäre, dies mit Pandas zu versuchen, da es Indizes beim Maskieren konserviert.

Siehe mein Beispiel:

 import numpy as np import pandas as pd def funPos(a, b): return a * b def funNeg(a, b): return a * (b + 1) myPosFunc = np.vectorize(funPos) #vectorized form of funPos myNegFunc = np.vectorize(funNeg) #vectorized form of funNeg #Input I = [1.0, 2.0, 3.0] x = pd.DataFrame([ [ 0.,0.,0.], [ 0.32, -6.79, 0.], [ 0.,0.,0.], [ 0.,1.5,0.], [ 0.,0., -1.71]]) b = pd.DataFrame(myPosFunc(x[x>0], I)) #calculate all positive values c = pd.DataFrame(myNegFunc(x[x<0], I)) #calculate all negative values b = b.combineMult(c) #put values of c in b b = b.fillna(1) #replace all missing values that were '0' in the raw array y = b.product() #multiply all elements in one row #Output print ('final result') print (y) print (y.tolist()) 
  • Ziehen von Elementen aus 2D-Array basierend auf Index-Array
  • Nennen dot Produkte und lineare Algebra Operationen in Cython?
  • Ignorieren String beim Lesen in ein Array
  • Numpy durchschnittliche Funktion Rundung Fehler
  • Python-Listen / Arrays: Deaktivieren Sie die negativen Indexing-Wrap-around in Slices
  • Unterschiedliche Ausgabe aus dem gleichen Code mit Exponenten in Python
  • Warum python einen Laufzeitfehler auslösen, während ich numpy.percentile für die Entzerrung durch scikit-image laufe?
  • Numpy Interpolation, um eine Vektorgröße zu erhöhen
  • NumPy-Array, ändern Sie die Werte, die NICHT in einer Liste von Indizes sind
  • Runde eine Python-Liste der Zahlen und pflegen die Summe
  • Itertools Produkt beschleunigt
  • Python ist die beste Programmiersprache der Welt.