Aus dieser Frage und anderen scheint es nicht empfehlenswert zu sein, concat
oder append
zum Erstellen eines Pandas-Datenrahmens zu verwenden, da dieser jedes Mal den gesamten Datenrahmen neu kopiert.
Mein Projekt beinhaltet das Abrufen einer kleinen Datenmenge alle 30 Sekunden. Dies könnte für ein 3-tägiges Wochenende dauern, sodass jemand leicht erwarten kann, dass mehr als 8000 Zeilen Zeile für Zeile erstellt werden. Was wäre der effizienteste Weg, um diesem Datenrahmen Zeilen hinzuzufügen?
Sie können Zeilen direkt zu einem DataFrame hinzufügen, indem Sie loc
für einen nicht vorhandenen Index verwenden. Aus der Pandas Dokumentation :
In [119]: dfi
Out[119]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
In [120]: dfi.loc[3] = 5
In [121]: dfi
Out[121]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
3 5 5 5
Wie erwartet ist die Verwendung von loc
wesentlich schneller als append
(ca. 14x):
import pandas as pd
df = pd.DataFrame({"A": [1,2,3], "B": [1,2,3], "C": [1,2,3]})
%%timeit
df2 = pd.DataFrame({"A": [4], "B": [4], "C": [4]})
df.append(df2)
# 1000 loops, best of 3: 1.61 ms per loop
%%timeit
df.loc[3] = 4
# 10000 loops, best of 3: 113 µs per loop
Ich habe den df.loc[i] = [new_data]
-Vorschlag dieser Antwort verwendet, aber ich habe> 500.000 Zeilen und das war sehr langsam.
Die Antworten sind zwar gut für die Frage des OPs, aber ich fand es effizienter, wenn es sich um eine große Anzahl von Zeilen (anstatt des vom OP beschriebenen Tricks) handelt, csvwriter zum Hinzufügen von Daten zu einem CSV-Objekt im Speicher zu verwenden. Verwenden Sie schließlich pandas.read_csv(csv)
, um die gewünschte DataFrame-Ausgabe zu generieren.
from io import BytesIO
from csv import writer
import pandas as pd
output = BytesIO()
csv_writer = writer(output)
for row in iterable_object:
csv_writer.writerow(row)
output.seek(0) # we need to get back to the start of the BytesIO
df = pd.read_csv(output)
return df
Dies war für ~ 500.000 Zeilen um das 1000-fache schneller und mit zunehmender Zeilenzahl wird die Geschwindigkeitsverbesserung nur noch größer (the df.loc[1] = [data]
wird vergleichsweise viel langsamer).
Ich hoffe, das hilft jemandem, der Effizienz benötigt, wenn er mit mehr Zeilen als mit dem OP arbeitet.
Sie müssen das Problem in zwei Teile aufteilen:
Wenn Ihre Daten kritisch sind (Sie können es sich nicht leisten, sie zu verlieren), senden Sie sie an eine Warteschlange und lesen Sie sie stapelweise aus der Warteschlange.
Die Warteschlange sorgt für eine zuverlässige (garantierte) Akzeptanz und dass Ihre Daten nicht verloren gehen.
Sie können die Daten aus der Warteschlange lesen und in einer Datenbank sichern.
Jetzt liest Ihre Python-App einfach aus der Datenbank und führt die Analyse in einem für die Anwendung sinnvollen Intervall durch - vielleicht möchten Sie stündliche Mittelwerte erstellen. In diesem Fall würden Sie das Skript jede Stunde ausführen, um die Daten aus der Datenbank abzurufen und die Ergebnisse möglicherweise in eine andere Datenbank/Tabelle/Datei zu schreiben.
Fazit: Teilen Sie das Sammeln und Analysieren von Teilen Ihrer Anwendung.
Wenn Sie davon ausgehen, dass Ihr Datenrahmen in der richtigen Reihenfolge indexiert ist, können Sie:
Zuerst prüfen Sie, was der nächste Indexwert ist, um eine neue Zeile zu erstellen:
myindex = df.shape[0]+1
Dann mit 'at' in jede gewünschte Spalte schreiben
df.at[myindex,'A']=val1
df.at[myindex,'B']=val2
df.at[myindex,'C']=val3
Sundances Antwort mag in Bezug auf die Verwendung richtig sein, aber der Benchmark ist einfach falsch. Wie moobie richtig angedeutet, existiert in diesem Beispiel bereits ein Index 3, was den Zugriff wesentlich schneller macht als bei einem nicht existierenden Index. Schau dir das an:
%%timeit
test = pd.DataFrame({"A": [1,2,3], "B": [1,2,3], "C": [1,2,3]})
for i in range(0,1000):
testrow = pd.DataFrame([0,0,0])
pd.concat([test[:1], testrow, test[1:]])
2,15 s ± 88 ms pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, je 1 Schleife)
%%timeit
test = pd.DataFrame({"A": [1,2,3], "B": [1,2,3], "C": [1,2,3]})
for i in range(0,1000):
test2 = pd.DataFrame({'A': 0, 'B': 0, 'C': 0}, index=[i+0.5])
test.append(test2, ignore_index=False)
test.sort_index().reset_index(drop=True)
972 ms ± 14,4 ms pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, je 1 Schleife)
%%timeit
test = pd.DataFrame({"A": [1,2,3], "B": [1,2,3], "C": [1,2,3]})
for i in range(0,1000):
test3 = [0,0,0]
test.loc[i+0.5] = test3
test.reset_index(drop=True)
1,13 s ± 46 ms pro Schleife (Mittelwert ± Standardabweichung von 7 Durchläufen, je 1 Schleife)
Dies ist natürlich rein synthetisch, und ich habe diese Ergebnisse zugegebenermaßen nicht erwartet, aber es scheint, dass mit nicht existierenden Indizes .loc
und .append
verhalten sich ziemlich ähnlich. Lass das hier.