2016-07-13 7 views
3

Ich habe einen Datenrahmen wie folgt aus:Pandas bekommen Index der höchsten Punktprodukt

df1 = pd.DataFrame({'a':[1,2,3,4],'b':[5,6,7,8],'c':[9,10,11,12]}) 
    a b c 
0 1 5 9 
1 2 6 10 
2 3 7 11 
3 4 8 12 

Und ich möchte eine andere Spalte in diesem Datenrahmen schaffen, die für jede Zeile speichert, die andere Reihe die höchste Punktzahl erhält, wenn durchgeführt ein Punktprodukt gegen.

Zum Beispiel für die erste Zeile wir die Punktprodukte gegen die anderen Reihen berechnen werden:

df1.drop(0).dot(df1.loc[0]).idxmax() 
output: 3 

Deshalb ich eine Funktion erstellen:

def get_highest(dataframe): 
    lis = [] 
    for row in dataframe.index: 
     temp = dataframe.drop(row).dot(dataframe.loc[row]) 
     lis.append(temp.idxmax()) 
    return lis 

Und ich bekommen, was ich will mit :

Ok, das funktioniert, aber das Problem ist, dass es überhaupt nicht skaliert. Hier sind die Ausgänge von timeit für unterschiedliche Anzahl der Zeilen:

4 rows: 2.87 ms 
40 rows: 77.1 ms 
400 rows: 700 ms 
4000 rows: 10.4s 

Und ich muss führen dies auf einem Datenrahmen, die etwa 240k Zeilen und Spalten 3.3k hat. Deshalb hier meine Frage: Gibt es eine Möglichkeit, diese Berechnung zu optimieren? (wahrscheinlich, indem Sie es auf andere Weise ansprechen)

Vielen Dank im Voraus.

+0

ich die numpy Tag hinzugefügt, da wahrscheinlich eine numpy basierte Lösung wird schneller sein, so numpy Leute können auch einen Blick daran. – ayhan

+0

@ayhan Gute Idee, danke – ysearka

+0

Dies könnte hilfreich sein. http://StackOverflow.com/q/38177464/2336654 – piRSquared

Antwort

2

eine Matrixmultiplikation mit der Transponierten Do:

mat_mul = np.dot(df.values, df.values.T) 

Füllen Diagonalen mit einer kleinen Zahl, so dass sie nicht das Maximum sein kann (vorausgesetzt ich alle positiv, so mit -1 gefüllt, aber Sie können das ändern):

np.fill_diagonal(mat_mul, -1) 

nehmen nun das argmax des Arrays:

df['highest'] = mat_mul.argmax(axis=1) 

Timings auf einem 10K von 4 df:

%%timeit 
mat_mul = np.dot(df.values, df.values.T) 
np.fill_diagonal(mat_mul, -1) 
df['highest'] = mat_mul.argmax(axis=1) 

1 loop, best of 3: 782 ms per loop 

%timeit df['highest'] = get_highest(df) 
1 loop, best of 3: 9.8 s per loop 
+0

Vielen Dank für Ihre enswer, eigentlich habe ich schon versucht, aber das Problem ist, dass 'np.dot' auf großen Datenframes viel Speicher braucht, so dass ich sofort bekomme ein 'MemoryError'. Vielleicht gibt es eine Möglichkeit, den Datenrahmen zu zerstückeln? Ich weiß nicht viel über Chunking. – ysearka

+0

Ehrlich gesagt weiß ich auch nicht, wie man Matrix Multiplikation Stück für Stück effizient macht. Lass mich ein paar Dinge ausprobieren. – ayhan

2

Da die Punktprodukte für Paare würde wiederholt werden, wenn sie würde, der endgültige Skalarprodukt-Array für jede Zeile gegenüber jeder anderen Reihe sein, ein symmetrischer einer gekippt werden. Also können wir entweder für die unteren oder oberen dreieckigen Punktproduktelemente berechnen und dann die vollständige Form erhalten, indem wir scipy's squareform verwenden. Daher würden wir eine Implementierung wie so haben -

from scipy.spatial.distance import squareform 

arr = df1.values 
R,C = np.triu_indices(arr.shape[0],1) 
df1['highest'] = squareform(np.einsum('ij,ij->i',arr[R],arr[C])).argmax(1) 

Ausgang für Musterkoffer -

In [145]: df1 
Out[145]: 
    a b c highest 
0 1 5 9  3 
1 2 6 10  3 
2 3 7 11  3 
3 4 8 12  2 
+0

Das ist eine gute Idee, es schlägt meinen Code bis 4k Zeilen, aber wenn ich 40k Zeilen versuche, scheint es, dass sie übereinstimmen, so tendiere ich zu denken, dass es so gut auf meinem Hauptdatenrahmen wäre – ysearka

+0

@ysearka Lassen Sie mich fragen Sie - Haben Sie negative Zahlen im Datenrahmen? Ersetzen Sie auch 'np.einsum ('ij, ij-> i', arr [R], arr [C])' mit '(arr [R] * arr [C]). Sum (1)' und sehen Sie, ob gibt es immer noch Mismatch? – Divakar

+0

Ich bedauere die Verzögerung sehr, ich habe mich auf eine andere dringende Aufgabe konzentriert. Ich habe keine negative Zahl in meinem Datenrahmen, sie sind tatsächlich Mengen (Anzahl oder Volumen). Der Versuch, den Ersatz zu installieren, verbessert leider nicht die Rechenzeit. – ysearka

Verwandte Themen