Ich möchte über jede Zeile einer gesamten Datei iterieren. Eine Möglichkeit, dies zu tun, besteht darin, die gesamte Datei zu lesen, sie in einer Liste zu speichern und dann die interessierende Zeile zu überschreiten. Diese Methode verbraucht viel Speicher, daher suche ich nach einer Alternative.
Mein Code bisher:
for each_line in fileinput.input(input_file):
do_something(each_line)
for each_line_again in fileinput.input(input_file):
do_something(each_line_again)
Die Ausführung dieses Codes gibt eine Fehlermeldung aus : device active
.
Irgendwelche Vorschläge?
Der Zweck besteht darin, die paarweise Zeichenfolgenähnlichkeit zu berechnen, dh für jede Zeile in der Datei möchte ich den Levenshtein-Abstand mit jeder anderen Zeile berechnen.
Antworten:
Die richtige, vollständig pythonische Methode zum Lesen einer Datei ist die folgende:
Die
with
Anweisung behandelt das Öffnen und Schließen der Datei, auch wenn im inneren Block eine Ausnahme ausgelöst wird. Dasfor line in f
behandelt dasf
Dateiobjekt als iterierbar, das automatisch gepufferte E / A- und Speicherverwaltung verwendet, sodass Sie sich nicht um große Dateien kümmern müssen.quelle
for line in f:
es funktioniert? Ich meine, wie ist das Iterieren über ein Dateiobjekt möglich?__iter__
, die angibt, was zu tun ist. Dateiobjekte definieren diese spezielle Methode, um einen Iterator über die Zeilen zurückzugeben. (Ungefähr.)Zwei speichereffiziente Methoden in Rangfolge (die erste ist die beste) -
with
- unterstützt von Python 2.5 und höheryield
wenn Sie wirklich die Kontrolle darüber haben möchten, wie viel gelesen werden soll1. Verwendung von
with
with
ist die schöne und effiziente pythonische Art, große Dateien zu lesen. Vorteile - 1) Das Dateiobjekt wird nach dem Verlassen deswith
Ausführungsblocks automatisch geschlossen . 2) Ausnahmebehandlung innerhalb deswith
Blocks. 3) Die Speicherschleifefor
durchläuft das Dateiobjektf
zeilenweise. Intern werden gepufferte E / A-Vorgänge (zur Optimierung kostspieliger E / A-Vorgänge) und Speicherverwaltung ausgeführt.2. Verwendung von
yield
Manchmal möchte man eine genauere Kontrolle darüber, wie viel in jeder Iteration gelesen werden soll. Verwenden Sie in diesem Fall iter & ield . Beachten Sie, dass bei dieser Methode die Datei am Ende explizit geschlossen werden muss.
Fallstricke und der Vollständigkeit halber - Die folgenden Methoden sind nicht so gut oder nicht so elegant zum Lesen großer Dateien, aber bitte lesen Sie sie, um ein umfassendes Verständnis zu erhalten.
In Python besteht die häufigste Methode zum Lesen von Zeilen aus einer Datei darin, Folgendes zu tun:
Wenn dies erledigt ist, lädt die
readlines()
Funktion (dasselbe gilt für dieread()
Funktion) die gesamte Datei in den Speicher und iteriert dann darüber. Ein etwas besserer Ansatz (die beiden erstgenannten Methoden sind die besten) für große Dateien ist die Verwendung desfileinput
Moduls wie folgt:Der
fileinput.input()
Aufruf liest Zeilen nacheinander, speichert sie jedoch nicht im Speicher, nachdem sie gelesen wurden, oder auch nur so, dafile
in Python iterierbar ist.Verweise
quelle
for line in open(...).readlines(): <do stuff>
. Warum würdest du?! Sie haben gerade alle Vorteile von Pythons cleverem gepufferten Iterator-E / A ohne Nutzen verloren.readlines
und erklären, warum dies nicht gut ist (weil die Datei in den Speicher eingelesen wird) und dann erklären, was dasfileinput
Modul tut und warum Sie Vielleicht möchten Sie es gegenüber den anderen Methoden verwenden, dann erklären, wie das Chunking der Datei die E / A verbessert, und ein Beispiel für die Chunking-Funktion geben (aber erwähnen, dass Python dies bereits für Sie erledigt, damit Sie es nicht müssen). Es ist jedoch nicht gut, nur fünf Möglichkeiten zur Lösung eines einfachen Problems anzugeben, von denen vier in diesem Fall falsch sind.So entfernen Sie Zeilenumbrüche:
Mit Universal-Newline - Unterstützung alle Textdatei Linien scheinen beendet zu werden
'\n'
, was auch immer die Terminatoren in der Datei'\r'
,'\n'
oder'\r\n'
.BEARBEITEN - So legen Sie die universelle Newline-Unterstützung fest:
open(file_path, mode='rU')
- erforderlich [danke @ Dave ]open(file_path, mode='rU')
- optionalopen(file_path, newline=None)
- optionalDer
newline
Parameter wird nur in Python 3 unterstützt und ist standardmäßig aufNone
. Dermode
Parameter ist'r'
in allen Fällen standardmäßig . DasU
ist in Python veraltet 3. In Python 2 unter Windows einen anderen Mechanismus zu übersetzen scheint\r\n
zu\n
.Docs:
So behalten Sie native Zeilenabschlüsse bei:
Der Binärmodus kann die Datei weiterhin in Zeilen mit analysieren
in
. Jede Zeile enthält alle Terminatoren in der Datei.Dank @katrielalex ‚s Antwort , Pythons open () doc, und ipython Experimente.
quelle
open(file_path, 'rU')
universelle Zeilenumbrüche aktivieren.Dies ist eine Möglichkeit, eine Datei in Python zu lesen:
Es wird keine vollständige Liste zugewiesen. Es iteriert über die Zeilen.
quelle
with open(input_file) as f:
. Dies erspart Ihnen dasf.close()
und stellt sicher, dass Sie nicht versehentlich vergessen, es zu schließen. Verhindert Speicherlecks und alles, was beim Lesen von Dateien sehr wichtig ist.Ein Zusammenhang im Vorfeld, woher ich komme. Code-Schnipsel sind am Ende.
Wenn ich kann, bevorzuge ich die Verwendung eines Open-Source-Tools wie H2O, um parallele CSV-Dateilesevorgänge mit hoher Leistung durchzuführen. Dieses Tool ist jedoch in seinen Funktionen eingeschränkt. Am Ende schreibe ich viel Code, um Data Science-Pipelines zu erstellen, bevor ich sie für das überwachte Lernen in den H2O-Cluster einspeise.
Ich habe Dateien wie 8 GB HIGGS-Dataset von UCI Repo und sogar 40 GB CSV-Dateien für datenwissenschaftliche Zwecke erheblich schneller gelesen, indem ich viel Parallelität mit dem Poolobjekt und der Kartenfunktion der Multiprozessor-Bibliothek hinzugefügt habe. Zum Beispiel erfordert das Clustering mit Suchvorgängen für den nächsten Nachbarn sowie DBSCAN- und Markov-Clustering-Algorithmen einige parallele Programmierfinesse, um einige ernsthaft herausfordernde Speicher- und Wanduhrzeitprobleme zu umgehen.
Normalerweise teile ich die Datei gerne zeilenweise mit Gnu-Tools in Teile auf und maskiere sie dann alle, um sie parallel im Python-Programm zu finden und zu lesen. Ich verwende üblicherweise mehr als 1000 Teildateien. Das Ausführen dieser Tricks hilft immens bei der Verarbeitungsgeschwindigkeit und den Speicherbeschränkungen.
Der pandas dataframe.read_csv ist ein Single-Thread, sodass Sie diese Tricks ausführen können, um Pandas schneller zu machen, indem Sie eine map () für die parallele Ausführung ausführen. Sie können htop verwenden, um zu sehen, dass bei einfachen alten sequentiellen Pandas dataframe.read_csv 100% CPU auf nur einem Kern der eigentliche Engpass in pd.read_csv ist, nicht auf der Festplatte.
Ich sollte hinzufügen, dass ich eine SSD auf einem schnellen Grafikkartenbus verwende, keine sich drehende HD auf einem SATA6-Bus sowie 16 CPU-Kerne.
Eine andere Technik, von der ich herausgefunden habe, dass sie in einigen Anwendungen hervorragend funktioniert, ist das parallele Lesen von CSV-Dateien innerhalb einer riesigen Datei, wobei jeder Worker mit einem unterschiedlichen Versatz in die Datei gestartet wird, anstatt eine große Datei in viele Teiledateien vorab aufzuteilen. Verwenden Sie Pythons Dateisuche () und tell () in jedem parallelen Worker, um die große Textdatei in Streifen an verschiedenen Start- und Endbytepositionen des Byteversatzes in der großen Datei gleichzeitig zu lesen. Sie können eine Regex-Suche für die Bytes durchführen und die Anzahl der Zeilenvorschübe zurückgeben. Dies ist eine Teilsumme. Summieren Sie schließlich die Teilsummen, um die globale Summe zu erhalten, wenn die Kartenfunktion nach Beendigung der Arbeit zurückkehrt.
Im Folgenden finden Sie einige Beispielbenchmarks, die den Parallel-Byte-Offset-Trick verwenden:
Ich benutze 2 Dateien: HIGGS.csv ist 8 GB. Es stammt aus dem UCI-Repository für maschinelles Lernen. all_bin .csv ist 40,4 GB groß und stammt aus meinem aktuellen Projekt. Ich benutze 2 Programme: das mit Linux gelieferte GNU wc-Programm und das von mir entwickelte reine Python fastread.py-Programm.
Das sind etwa 4,5 GB / s oder 45 Gbit / s, die Geschwindigkeit beim Schlürfen von Dateien. Das ist keine sich drehende Festplatte, mein Freund. Das ist eigentlich eine Samsung Pro 950 SSD.
Unten finden Sie den Geschwindigkeits-Benchmark für dieselbe Datei, die von gnu wc, einem reinen C-kompilierten Programm, zeilenweise gezählt wird.
Was cool ist, ist, dass mein reines Python-Programm in diesem Fall im Wesentlichen der Geschwindigkeit des von gnu wc kompilierten C-Programms entspricht. Python wird interpretiert, aber C wird kompiliert, daher ist dies eine ziemlich interessante Leistung, ich denke, Sie würden dem zustimmen. Natürlich muss wc wirklich in ein paralleles Programm geändert werden, und dann würde es wirklich die Socken von meinem Python-Programm schlagen. Aber so wie es heute ist, ist gnu wc nur ein sequentielles Programm. Sie tun, was Sie können, und Python kann heute parallel tun. Das Kompilieren von Cython kann mir möglicherweise helfen (für eine andere Zeit). Auch Speicherzuordnungsdateien wurden noch nicht untersucht.
Fazit: Die Geschwindigkeit ist für ein reines Python-Programm im Vergleich zu einem C-Programm gut. Es ist jedoch nicht gut genug, das reine Python-Programm über dem C-Programm zu verwenden, zumindest nicht für die Zählung. Im Allgemeinen kann die Technik für andere Dateiverarbeitungen verwendet werden, sodass dieser Python-Code immer noch gut ist.
Frage: Verbessert das einmalige Kompilieren des regulären Ausdrucks und das Weitergeben an alle Mitarbeiter die Geschwindigkeit? Antwort: Die Vorkompilierung von Regex hilft in dieser Anwendung NICHT. Ich nehme an, der Grund dafür ist, dass der Aufwand für die Serialisierung und Erstellung von Prozessen für alle Mitarbeiter dominiert.
Eine Sache noch. Hilft das parallele Lesen von CSV-Dateien überhaupt? Ist die Festplatte der Engpass oder die CPU? Viele sogenannte Top-Antworten auf Stackoverflow enthalten die allgemeine Entwickler-Weisheit, dass Sie nur einen Thread benötigen, um eine Datei zu lesen. Das Beste, was Sie tun können, heißt es. Sind sie sich aber sicher?
Lass es uns herausfinden:
Oh ja, ja, das tut es. Das parallele Lesen von Dateien funktioniert recht gut. Na siehst du!
Ps. Falls einige von Ihnen wissen wollten, was wäre, wenn der balanceFactor bei Verwendung eines einzelnen Worker-Prozesses 2 wäre? Nun, es ist schrecklich:
Wichtige Teile des Python-Programms fastread.py:
Die Definition für PartitionDataToWorkers ist nur gewöhnlicher sequentieller Code. Ich habe es weggelassen, falls jemand anderes etwas üben möchte, wie paralleles Programmieren ist. Ich habe die schwierigeren Teile kostenlos verschenkt: den getesteten und funktionierenden Parallelcode, zu Ihrem Lernvorteil.
Dank an: Das Open-Source-H2O-Projekt von Arno und Cliff und den H2O-Mitarbeitern für ihre großartige Software und Lehrvideos, die mich wie oben gezeigt zu diesem reinen Python-Hochleistungs-Parallelbyte-Offset-Lesegerät inspiriert haben. H2O liest parallel Dateien mit Java, kann von Python- und R-Programmen aufgerufen werden und ist verrückt schnell und schneller als alles andere auf der Welt beim Lesen großer CSV-Dateien.
quelle
Katrielalex bot die Möglichkeit, eine Datei zu öffnen und zu lesen.
Wie auch immer Ihr Algorithmus vorgeht, er liest die gesamte Datei für jede Zeile der Datei. Das bedeutet, dass die Gesamtmenge des Lesens einer Datei - und des Berechnens der Levenshtein-Entfernung - N * N erfolgt, wenn N die Anzahl der Zeilen in der Datei ist. Da Sie sich Sorgen um die Dateigröße machen und diese nicht im Speicher behalten möchten, mache ich mir Sorgen um die resultierende quadratische Laufzeit . Ihr Algorithmus gehört zur Klasse der O (n ^ 2) -Algorithmen, die häufig durch Spezialisierung verbessert werden können.
Ich vermute, dass Sie hier bereits den Kompromiss zwischen Speicher und Laufzeit kennen, aber vielleicht möchten Sie untersuchen, ob es eine effiziente Möglichkeit gibt, mehrere Levenshtein-Entfernungen parallel zu berechnen. Wenn ja, wäre es interessant, Ihre Lösung hier zu teilen.
Wie viele Zeilen haben Ihre Dateien und auf welcher Art von Maschine (Speicher- und CPU-Leistung) muss Ihr Algorithmus ausgeführt werden, und wie hoch ist die tolerierte Laufzeit?
Code würde aussehen wie:
Die Fragen sind jedoch, wie Sie die Abstände speichern (Matrix?) Und ob Sie einen Vorteil daraus ziehen können, z. B. die äußere Zeile für die Verarbeitung vorzubereiten oder einige Zwischenergebnisse für die Wiederverwendung zwischenzuspeichern.
quelle
Wenn Sie beispielsweise eine bestimmte Zeile auf eine Länge von mehr als 10 prüfen möchten, arbeiten Sie mit dem, was Sie bereits zur Verfügung haben.
quelle
Aus der Python-Dokumentation für fileinput .input ():
Ferner lautet die Definition der Funktion:
Wenn ich zwischen den Zeilen lese, weiß ich, dass es
files
sich um eine Liste handeln kann, damit Sie so etwas wie Folgendes haben können:Sehen Sie hier für weitere Informationen
quelle
Ich würde dringend empfehlen, das Standard-Laden von Dateien nicht zu verwenden, da es schrecklich langsam ist. Sie sollten sich die numpy-Funktionen und die IOpro-Funktionen ansehen (z. B. numpy.loadtxt ()).
http://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html
https://store.continuum.io/cshop/iopro/
Dann können Sie Ihre paarweise Operation in Stücke aufteilen:
Es ist fast immer viel schneller, Daten in Chunks zu laden und dann Matrixoperationen durchzuführen, als sie Element für Element auszuführen !!
quelle
Müssen Sie häufig eine große Datei von der letzten Positionslesung lesen?
Ich habe ein Skript erstellt, mit dem eine Apache access.log-Datei mehrmals täglich geschnitten wird. Also musste ich einen Positionscursor auf die letzte Zeile setzen, die während der letzten Ausführung analysiert wurde . Zu diesem Zweck habe ich
file.seek()
undfile.seek()
Methoden verwendet, die das Speichern des Cursors in einer Datei ermöglichen.Mein Code:
quelle
Der beste Weg , große Datei, Zeile für Zeile zu lesen ist Python verwenden enumerate Funktion
quelle