Ich habe eine sehr schlechte Leistung bei der Verwendung von Iterrows von Pandas festgestellt.
Ist das etwas, was andere erleben? Ist es spezifisch für Iterrows und sollte diese Funktion für Daten einer bestimmten Größe vermieden werden (ich arbeite mit 2-3 Millionen Zeilen)?
Diese Diskussion auf GitHub hat mich zu der Annahme geführt, dass dies beim Mischen von dtypes im Datenrahmen verursacht wird. Das einfache Beispiel unten zeigt jedoch, dass es auch bei Verwendung eines dtype (float64) vorhanden ist. Dies dauert auf meinem Computer 36 Sekunden:
import pandas as pd
import numpy as np
import time
s1 = np.random.randn(2000000)
s2 = np.random.randn(2000000)
dfa = pd.DataFrame({'s1': s1, 's2': s2})
start = time.time()
i=0
for rowindex, row in dfa.iterrows():
i+=1
end = time.time()
print end - start
Warum lassen sich vektorisierte Operationen wie so viel schneller anwenden? Ich stelle mir vor, dass dort auch eine zeilenweise Iteration stattfinden muss.
Ich kann nicht herausfinden, wie ich in meinem Fall keine Iterrows verwenden soll (dies werde ich für eine zukünftige Frage speichern). Daher würde ich mich freuen, wenn Sie diese Iteration konsequent vermeiden konnten. Ich mache Berechnungen basierend auf Daten in separaten Datenrahmen. Danke dir!
--- Bearbeiten: Eine vereinfachte Version von dem, was ich ausführen möchte, wurde unten hinzugefügt ---
import pandas as pd
import numpy as np
#%% Create the original tables
t1 = {'letter':['a','b'],
'number1':[50,-10]}
t2 = {'letter':['a','a','b','b'],
'number2':[0.2,0.5,0.1,0.4]}
table1 = pd.DataFrame(t1)
table2 = pd.DataFrame(t2)
#%% Create the body of the new table
table3 = pd.DataFrame(np.nan, columns=['letter','number2'], index=[0])
#%% Iterate through filtering relevant data, optimizing, returning info
for row_index, row in table1.iterrows():
t2info = table2[table2.letter == row['letter']].reset_index()
table3.ix[row_index,] = optimize(t2info,row['number1'])
#%% Define optimization
def optimize(t2info, t1info):
calculation = []
for index, r in t2info.iterrows():
calculation.append(r['number2']*t1info)
maxrow = calculation.index(max(calculation))
return t2info.ix[maxrow]
quelle
apply
wird NICHT vektorisiert.iterrows
ist noch schlimmer, da es alles einpackt (mit dem sich die Leistung unterscheidetapply
). Sie sollten nuriterrows
in sehr wenigen Situationen verwenden. IMHO nie. Zeigen Sie, womit Sie tatsächlich arbeiteniterrows
.DatetimeIndex
In zu tunTimestamps
(wurde im Python-Bereich implementiert), und dies wurde im Master erheblich verbessert.Antworten:
Im Allgemeinen
iterrows
sollte nur in sehr, sehr spezifischen Fällen verwendet werden. Dies ist die allgemeine Rangfolge für die Ausführung verschiedener Operationen:Die Verwendung einer benutzerdefinierten Cython-Routine ist normalerweise zu kompliziert. Lassen Sie uns dies zunächst überspringen.
1) Vektorisierung ist IMMER die erste und beste Wahl. Es gibt jedoch eine kleine Anzahl von Fällen (die normalerweise eine Wiederholung beinhalten), die nicht auf offensichtliche Weise vektorisiert werden können. Darüber hinaus auf einem kleinen
DataFrame
schneller sein, andere Methoden zu verwenden.3) kann
apply
normalerweise von einem Iterator im Cython-Raum verarbeitet werden. Dies wird intern von Pandas erledigt, obwohl es davon abhängt, was imapply
Ausdruck vor sich geht. Zum Beispieldf.apply(lambda x: np.sum(x))
wird ziemlich schnell ausgeführt, obwohl es natürlichdf.sum(1)
noch besser ist. Jedoch so etwas wiedf.apply(lambda x: x['b'] + 1)
wird jedoch im Python-Raum ausgeführt und ist folglich viel langsamer.4)
itertuples
packt die Daten nicht in aSeries
. Es werden nur die Daten in Form von Tupeln zurückgegeben.5)
iterrows
Boxt die Daten in aSeries
. Verwenden Sie eine andere Methode, es sei denn, Sie benötigen dies wirklich.6) Aktualisieren eines leeren Frames zeilenweise. Ich habe gesehen, dass diese Methode viel zu oft angewendet wurde. Es ist bei weitem das langsamste. Es ist wahrscheinlich üblich (und für einige Python-Strukturen relativ schnell), aber a
DataFrame
führt eine angemessene Anzahl von Überprüfungen der Indizierung durch, sodass das Aktualisieren einer Zeile immer sehr langsam ist. Viel besser neue Strukturen zu schaffen undconcat
.quelle
itertuples
ist schneller alsapply
:(pd.DataFrame.apply
ist oft langsamer alsitertuples
. Darüber hinaus lohnt es sich, das Listenverständnismap
, die schlecht benanntennp.vectorize
undnumba
(in keiner bestimmten Reihenfolge) für nicht vektorisierbare Berechnungen zu berücksichtigen, z . B. diese Antwort .Vektoroperationen in Numpy und Pandas sind aus mehreren Gründen viel schneller als Skalaroperationen in Vanilla Python:
Amortisierte Typensuche : Python ist eine dynamisch typisierte Sprache, sodass für jedes Element in einem Array ein Laufzeit-Overhead anfällt. Numpy (und damit Pandas) führen jedoch Berechnungen in C durch (häufig über Cython). Der Typ des Arrays wird erst zu Beginn der Iteration bestimmt. Diese Einsparungen allein sind einer der größten Gewinne.
Besseres Caching : Das Iterieren über ein C-Array ist cachefreundlich und daher sehr schnell. Ein Pandas DataFrame ist eine "spaltenorientierte Tabelle", was bedeutet, dass jede Spalte wirklich nur ein Array ist. Die nativen Aktionen, die Sie für einen DataFrame ausführen können (z. B. das Summieren aller Elemente in einer Spalte), weisen daher nur wenige Cache-Fehler auf.
Mehr Möglichkeiten für Parallelität : Ein einfaches C-Array kann über SIMD-Anweisungen bearbeitet werden. Einige Teile von Numpy aktivieren SIMD, abhängig von Ihrer CPU und dem Installationsprozess. Die Vorteile der Parallelität sind nicht so dramatisch wie die statische Eingabe und das bessere Caching, aber sie sind immer noch ein solider Gewinn.
Moral der Geschichte: Verwenden Sie die Vektoroperationen in Numpy und Pandas. Sie sind schneller als skalare Operationen in Python, weil diese Operationen genau das sind, was ein C-Programmierer ohnehin von Hand geschrieben hätte. (Abgesehen davon, dass der Array-Begriff viel einfacher zu lesen ist als explizite Schleifen mit eingebetteten SIMD-Anweisungen.)
quelle
Hier ist der Weg, um Ihr Problem zu lösen. Dies ist alles vektorisiert.
quelle
Eine andere Option ist die Verwendung
to_records()
, die schneller ist als beideitertuples
unditerrows
.Für Ihren Fall gibt es jedoch viel Raum für andere Arten von Verbesserungen.
Hier ist meine endgültige optimierte Version
Benchmark-Test:
Vollständiger Code:
Die endgültige Version ist fast 10x schneller als der ursprüngliche Code. Die Strategie lautet:
groupby
diese , um einen wiederholten Vergleich von Werten zu vermeiden.to_records
diese Option, um auf rohe numpy.records-Objekte zuzugreifen.quelle
Ja, Pandas itertuples () ist schneller als iterrows (). Sie können auf die Dokumentation verweisen: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iterrows.html
"Um dtypes beim Durchlaufen der Zeilen beizubehalten, ist es besser, itertuples () zu verwenden, das namedtuples der Werte zurückgibt und im Allgemeinen schneller als iterrows ist."
quelle
Details in diesem Video
Benchmark
quelle