Verschiedene Möglichkeiten, die letzte Zeile einer CSV-Datei in Python zu lesen

Unter Linux gibt es einen Befehl namens "tail", mit dem Sie die "n" -Zeile am Ende der Datei abrufen können. Es ist ziemlich praktisch, daher möchte ich dasselbe mit Python tun können. Ich möchte eine Funktion erstellen, die n Zeilen vom Ende der Datei mit tail (Dateiname, n) abruft, wobei verschiedene Ansätze verwendet werden.

Den letzten Ansatz finden Sie auf der Website it-swarm.dev Suchen Sie effizient die letzte Zeile der Textdatei. -Ich verweise auf die Seite swarm.dev/ja/python/ Finde effizient die letzte Zeile der Textdatei / 940298444 /).

Zu verwendende Datei

Die zu lesende Datei könnte eine Textdatei sein, aber dieses Mal werde ich die CSV-Datei verwenden. Der Dateiname lautet "test.csv". Der Inhalt ist eine Zusammenfassung des Bitcoin-Preises in 86400 Zeilen (im Wert von einem Tag) pro Sekunde.

test.csv


date,price,size
1588258800,933239.0,3.91528007
1588258801,933103.0,3.91169431
1588258802,932838.0,2.91
1588258803,933217.0,0.5089811

(Unterlassung)

1588345195,955028.0,0.0
1588345196,954959.0,0.05553
1588345197,954984.0,1.85356
1588345198,955389.0,10.91445135
1588345199,955224.0,3.61106

Obwohl es nichts mit dem Hauptthema zu tun hat, sind die Einheiten für Datum, Preis und Größe UnixTime, YEN, BTC, wenn Sie jeden Artikel vorerst erläutern. Die erste Zeile bedeutet, dass zum Zeitpunkt "1588258800", dh am 1. Mai um 0:00:00 Uhr, "3.915280007" Stückchen Münzen für "933239.0" Yen gekauft und verkauft wurden.

Lesen Sie von Anfang an gehorsam

Verwenden Sie zunächst die integrierte Funktion open (), um das Dateiobjekt abzurufen, alle Zeilen von Anfang an zu lesen und nur die letzten n Zeilen auszugeben. Wenn n 0 oder eine negative ganze Zahl ist, werden seltsame Ergebnisse erhalten, so dass es tatsächlich notwendig ist, eine auf natürliche Zahlen beschränkte Verarbeitung durchzuführen, dies ist jedoch für die Sichtbarkeit wichtig.

python


def tail(fn, n):
    #Öffnen Sie die Datei und erhalten Sie alle Zeilen in einer Liste
    with open(fn, 'r') as f:
        #Lesen Sie eine Zeile.Die erste Zeile ist die Kopfzeile. Verwerfen Sie daher das Ergebnis
        f.readline()

        #Lesen Sie alle Zeilen
        lines = f.readlines()
    
    #Gibt nur n Zeilen von hinten zurück
    return lines[-n:]

#Ergebnis
file_name = 'test.csv'
tail(file_name, 3)
# ['1588345197,954984.0,1.85356\n',
#  '1588345198,955389.0,10.91445135\n',
#  '1588345199,955224.0,3.61106\n']

Wenn es sich um eine Textdatei handelt, können Sie sie unverändert lassen, die Verwendung für CSV-Dateien jedoch etwas vereinfachen.

python


def tail(fn, n):
    #Öffnen Sie die Datei und erhalten Sie alle Zeilen in einer Liste
    with open(fn, 'r') as f:
        f.readline()
        lines = f.readlines()

    #Geben Sie einen String zurück, nachdem Sie ihn zu einem Array gemacht haben.Übrigens str->Geben Sie die Konvertierung in float ein
    return [list(map(float ,line.strip().split(','))) for line in lines[-n:]]

#Ergebnis
tail(file_name, 3)
# [[1588345197.0, 954984.0, 1.85356],
#  [1588345198.0, 955389.0, 10.91445135],
#  [1588345199.0, 955224.0, 3.61106]]

Das einzige, was sich geändert hat, ist die "Return" -Linie, aber da die Funktionen überfüllt und schwer zu verstehen sind, werde ich es gleich erklären. Die folgende Verarbeitung wird für jede Zeile durchgeführt.

  1. Entfernen Sie den Zeilenvorschubcode mit strip () '1588345197,954984.0,1.85356\n' -> '1588345197,954984.0,1.85356'

  2. Konvertieren Sie Zeichenfolgen mit "split ()" in durch Kommas getrennte Arrays '1588345197,954984.0,1.85356' -> ['1588345197', '954984.0', '1.85356']

  3. Konvertieren Sie jedes Element des Arrays mit map () von einem String in einen Float-Typ ['1588345197', '954984.0', '1.85356'] -> [1588345197.0, 954984.0, 1.85356]

Verwenden Sie das CSV-Modul

Da das CSV-Modul jede Zeile automatisch in ein Array konvertiert, ist es etwas langsamer, kann aber genauer beschrieben werden.

python


import csv

def tail_csv(fn, n):
    with open(fn) as f:
        #Konvertieren Sie das Dateiobjekt in einen CSV-Reader
        reader = csv.reader(f)
        #Verwerfen Sie den Header
        next(reader)
        #Lesen Sie alle Zeilen
        rows = [row for row in reader]

    #Schweben Sie nur die letzten n Zeilen und kehren Sie zurück
    return [list(map(float, row)) for row in rows[-n:]]

Verwenden Sie das Pandas-Modul

Da Pandas eine Schwanzfunktion haben, ist es überraschend einfach zu schreiben.

python


import pandas as pd

def tail_pd(fn, n):
    df = pd.read_csv(fn)
    return df.tail(n).values.tolist()

Da Pandas sich mit Numpy-Arrays befasst, wird es am Ende mit tolist () in eine Liste konvertiert. Es ist nicht erforderlich, ob das Numpy-Array verwendet werden kann.

Messen Sie die Ausführungszeit für jedes Muster

Da ipython einen praktischen Befehl namens timeit hat, vergleichen wir ihn mit der Anzahl der Schleifen, die auf 100 gesetzt sind.

timeit -n100 tail('test.csv', 3)
18.8 ms ± 175 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

timeit -n100 tail_csv('test.csv', 3)
67 ms ± 822 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

timeit -n100 tail_pd('test.csv', 3)
30.4 ms ± 2.45 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

Es stellte sich heraus, dass es schnell zu lesen war, ohne ein Modul zu verwenden. Cospa scheint das Beste zu sein, weil Pandas die Einfachheit des Codes ist und die Geschwindigkeit angemessen ist. Da das CSV-Modul absichtlich auch in nicht verwendete Zeilen von einer Zeichenfolge in ein Array konvertiert, sind die Ergebnisse äußerst schlecht.

Wenn Sie die Datei von hinten lesen, wird es einen Moment dauern

Alle bisherigen Ansätze lesen schließlich alle Zeilen. Da ich jedoch nur die letzten Zeilen möchte, sollte das Lesen sofort abgeschlossen sein, wenn es eine Möglichkeit gibt, die Datei von hinten zu lesen. Siehe Seite [Die letzte Zeile der Textdatei effizient finden](https://www.it-swarm.dev/ja/python/ Die letzte Zeile der Textdatei effizient finden / 940298444 /) tat. Lesen Sie ungefähr 100 Bytes von hinten in der Reihenfolge, und wenn ein Zeilenvorschubcode gefunden wird, ist die Zeichenfolge danach die letzte Zeile. Nur die letzte Zeile wird auf der Seite gefunden, aber um den Befehl "tail" zu realisieren Sie müssen die n-Linie von hinten finden, stellen Sie sie also nur dort ein.

Als vorläufiges Wissen werden wir zunächst erklären, wie der Dateizeiger bedient wird. Es gibt drei Funktionen: f.tell (), f.read (Größe) und f.seek (Offset, woher). f.tell () gibt die Position zurück, auf die der Zeiger aktuell zeigt. f.read (size) gibt den gelesenen Inhalt size Bytes von der aktuellen Position zurück. Der Zeiger bewegt sich zur Leseposition. Er kann nur in die positive Richtung vorgerückt werden. f.seek (offset, wherece) ist eine Funktion, die die Position des Zeigers verschiebt. Das Argument "woher" stellt die Position dar. Einer der Werte "0, 1, 2" wird eingegeben. "0" ist der Anfang der Datei, "1" ist die aktuelle Zeigerposition und "2" ist das Ende der Datei. Meint. Geben Sie eine Ganzzahl für "Offset" ein. Im Gegensatz zu "Lesen" können Sie einen negativen Wert übergeben. So gibt beispielsweise "f.seek (-15, 1)" die aktuelle Zeigerposition um 15 an den Anfang zurück.

Wir werden es basierend auf diesen implementieren.

python


#Verwenden Sie split, das reguläre Ausdrücke verwenden kann
import re

def tail_b(fn, n=None):
    #Wenn n nicht angegeben wird, wird nur die letzte Zeile alleine zurückgegeben
    if n is None:
        n = 1
        is_list = False
    #n ist eine natürliche Zahl
    elif type(n) != int or n < 1:
        raise ValueError('n has to be a positive integer')
    #Wenn n angegeben ist, werden n Zeilen zusammen in einer Liste zurückgegeben.
    else:
        is_list = True

    # 128 *Lesen Sie jeweils n Bytes
    chunk_size = 64 * n

    # seek()Benimmt sich unerwartet, außer im Binärmodus'rb'Konkretisieren
    with open(fn, 'rb') as f:
        #Erste Zeile, um die Position ganz links ohne die Überschrift zu finden(Kopfzeile)Ich lese
        f.readline()
        #Der allererste Zeilenvorschubcode befindet sich am linken Ende(Beenden Sie beim Lesen am Ende der Datei)Zu
        # -1 ist'\n'1 Byte
        left_end = f.tell() - 1
        
        #Ende der Datei(2)1 Byte zurück von. read(1)Einlesen
        f.seek(-1, 2)
        
        #Am Ende der Datei befinden sich häufig Leerzeilen und Leerzeichen
        #Position des letzten Zeichens in der Datei ohne diese(Rechtes Ende)Finden
        while True:
            if f.read(1).strip() != b'':
                #Rechtes Ende
                right_end = f.tell()
                break
            #Machen Sie einen Schritt, also machen Sie zwei Schritte nach unten
            f.seek(-2, 1)
        
        #Anzahl der ungelesenen Bytes links
        unread = right_end - left_end
        
        #Anzahl der gelesenen Zeilen.Wenn dies n oder mehr wird, bedeutet dies, dass n Zeilen gelesen wurden.
        num_lines = 0

        #Variablen zum Verbinden der gelesenen Byte-Strings
        line = b''
        while True:
            #Die Anzahl der ungelesenen Bytes ist Chunk_Wenn es kleiner als die Größe wird,Chunk-Fraktion_Größe
            if unread < chunk_size:
                chunk_size = f.tell() - left_end
            
            #Chunk von Ihrem aktuellen Standort_Bewegen Sie sich nach Größe an den Anfang der Datei
            f.seek(-chunk_size, 1)
            
            #Lesen Sie nur so viel, wie Sie sich bewegen
            chunk = f.read(chunk_size)

            #Verbinden
            line = chunk + line

            #Da ich wieder mit dem Lesen fortfuhr, Chunk am Anfang nochmal_Größenverschiebung
            f.seek(-chunk_size, 1)
            
            #Aktualisieren Sie die Anzahl der ungelesenen Bytes
            unread -= chunk_size

            #Wenn ein Zeilenvorschubcode enthalten ist
            if b'\n' in chunk:
                #Anzahl so viele wie die Anzahl der Zeilenvorschubcodes_Zeilen hochzählen
                num_lines += chunk.count(b'\n')

                #Lesen Sie mehr als n Zeilen,Oder wenn die Anzahl der ungelesenen Bytes 0 erreicht, endet ein Signal
                if num_lines >= n or not unread:
                    #Zuletzt gefundener Zeilenvorschubcode
                    leftmost_blank = re.search(rb'\r?\n', line)

                    #Das Teil muss vor dem zuletzt gefundenen Zeilenvorschubcode nicht benötigt werden
                    line = line[leftmost_blank.end():]

                    #Konvertieren Sie die Byte-Zeichenfolge in eine Zeichenfolge
                    line = line.decode()

                    #'\r\n'Oder\n'In ein Array konvertieren, das durch getrennt ist
                    lines = re.split(r'\r?\n', line)

                    #Zum Schluss n Stücke von hinten herausnehmen,In Float-Typ konvertieren und zurückgeben
                    result = [list(map(float, line.split(','))) for line in lines[-n:]]

                    #Wenn n nicht angegeben wird, wird die letzte Zeile alleine zurückgegeben.
                    if not is_list:
                        return result[-1]
                    else:
                        return result

Die Erklärung finden Sie im Anhang. Lassen Sie uns die Hauptzeitmessung durchführen.

timeit -n100 tail_b(fn, 3)
87.8 µs ± 3.74 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Die bisher beste Zeit war der erste Ansatz, der "18,8 ms ± 175 µs" betrug. Dies bedeutet, dass die Ausführungszeit etwa "0,5%" beträgt. Das heißt "200" Mal, aber 86400 Zeilen von Anfang an. Es ist natürlich, dass es einen großen Unterschied gibt, weil es der Unterschied zwischen dem Lesen aller oder dem Lesen einiger Zeilen von hinten ist.

abschließend

Ich habe vier Muster eingeführt, aber es scheint eine andere Möglichkeit zu geben, den Befehl "tail" des Systems mit dem Modul "subprocess" auszuführen. Dies ist eine umgebungsabhängige Methode, daher habe ich sie diesmal weggelassen. Die am meisten empfohlene Methode, die ich eingeführt habe, ist die, die mit "Pandas" in zwei Zeilen geschrieben werden kann. Python ist eine Sprache, die beherrscht, wie Sie sich mit dem Code eines anderen amüsieren können.

Die Methode zum Lesen von der Rückseite der Datei wird empfohlen, wenn Sie Geschwindigkeit benötigen oder wenn die Anzahl der Zeilen und Zeichen lächerlich groß ist und das Lesen der Datei von Anfang an zu lange dauert. Es macht auch keinen Sinn, "64" zu verwenden, um "chunk_size" zu bestimmen. Es ist wahrscheinlich am schnellsten, es auf ungefähr die Länge einer Zeile in einer Datei einzustellen, aber einige Dateien variieren je nach Zeile stark in der Länge. Daher kann ich nichts sagen. Wenn Sie mit einer Datei arbeiten, die einige Zeichen in einer kurzen Zeile, aber 10.000 Zeichen in einer langen Zeile enthält, müssen Sie chunk_size dynamisch ändern. Wenn beispielsweise die Anzahl der in einer Suche gefundenen Zeilen weit unter n liegt, wird die nächste chunk_size verdoppelt und verdoppelt. Es scheint auch effektiv zu sein, die nächste chunk_size aus der Anzahl der durchsuchten Zeilen und der durchschnittlichen Länge der Zeilen zu bestimmen.

Recommended Posts

Verschiedene Möglichkeiten, die letzte Zeile einer CSV-Datei in Python zu lesen
Google sucht mit Python nach der Zeichenfolge in der letzten Zeile der Datei
Lesen Sie die Datei Zeile für Zeile mit Python
Lesen Sie die Datei Zeile für Zeile mit Python
[Python] Lesen Sie die angegebene Zeile in der Datei
Lesen Sie die Standardausgabe eines Unterprozesses zeilenweise in Python
Lesen einer CSV-Datei mit Python 2/3
So setzen Sie eine Zeilennummer am Anfang einer CSV-Datei
[Python] Lesen der CSV-Datei (Methode read_csv des Pandas-Moduls)
Ich habe ein Programm erstellt, um die Größe einer Datei mit Python zu überprüfen
Vorlage des Python-Skripts zum Lesen des Inhalts der Datei
2 Möglichkeiten, alle CSV-Dateien in einem Ordner zu lesen
Ändern Sie das Standardausgabeziel in eine Datei in Python
Verschiedene Methoden zur Berechnung der Ähnlichkeit zwischen Daten mit Python
[Hinweis] Import von Dateien in das übergeordnete Verzeichnis in Python
So erhalten Sie den letzten (letzten) Wert in einer Liste in Python
So bestimmen Sie die Existenz eines Selenelements in Python
So überprüfen Sie die Speichergröße einer Variablen in Python
So überprüfen Sie die Speichergröße eines Wörterbuchs in Python
Lesen Sie die Datei in Python mit einem relativen Pfad aus dem Programm
Verschiedene Möglichkeiten, um in Python ein Array von Zahlen von 1 bis 10 zu erstellen.
[Python] Listenverständnis Verschiedene Möglichkeiten zum Erstellen einer Liste
Lesen Sie eine Datei mit verstümmelten Linien in Python
Holen Sie sich den Aufrufer einer Funktion in Python
So erstellen Sie eine JSON-Datei in Python
Kopieren Sie die Liste in Python
Ausgabe in Form eines Python-Arrays
Lesen Sie mit Python Zeile für Zeile aus der Datei
So lesen Sie Dateien in verschiedenen Verzeichnissen
Geschwindigkeitsbewertung der Ausgabe von CSV-Dateien in Python
Lesen Sie die Python-CSV-Datei
So übergeben Sie das Ergebnis der Ausführung eines Shell-Befehls in einer Liste in Python
Python - Lesen Sie Daten aus einer numerischen Datendatei und suchen Sie die multiple Regressionslinie.
[Python] Scannen Sie den Ordner einschließlich der Unterordner → Exportieren Sie die Dateiliste in CSV
Zeichnen Sie ein Faltlinien- / Streudiagramm mit Python Matplotlib für die CSV-Datei (2 Spalten).
Ich möchte den Dateinamen, die Zeilennummer und den Funktionsnamen in Python 3.4 erhalten
So erhalten Sie mit Python eine Liste der Dateien im selben Verzeichnis
Analysieren Sie eine JSON-Zeichenfolge, die in eine Datei in Python geschrieben wurde
Verschiedene Methoden zum Extrahieren von Spalten des NumPy-Arrays
So ermitteln Sie die Anzahl der Stellen in Python
Ich habe versucht, eine CSV-Datei mit Python zu berühren
Lesen Sie die CSV-Datei und zeigen Sie sie im Browser an
Ein Memorandum zum Ausführen eines Python-Skripts in einer Bat-Datei
Lesen Sie die XML-Datei anhand des Python-Tutorials
Ich möchte eine Datei mit Python zufällig testen
Python-Skript, das eine JSON-Datei aus einer CSV-Datei erstellt
Geben Sie das Ausgabeergebnis von sklearn.metrics.classification_report als CSV-Datei aus
Ein Memorandum über die Umsetzung von Empfehlungen in Python
Lesen von CSVs, die in Python nur Ganzzahlen enthalten
Um das Äquivalent von Rubys ObjectSpace._id2ref in Python zu tun
Python Hinweis: Das Rätsel, einer Variablen eine Variable zuzuweisen
Was bedeutet das letzte () in einer Funktion in Python?
Ich habe ein Skript erstellt, um zu überprüfen, ob an der angegebenen Position der JSON-Datei in Python Englisch eingegeben wird.
So zeigen Sie das Änderungsdatum einer Datei in C-Sprache bis zu Nanosekunden an
Wie identifiziere ich das Element mit der geringsten Anzahl von Zeichen in einer Python-Liste?
[Ansible] Beispiel für ein Playbook, das der ersten Zeile der Datei eine Zeichenkette hinzufügt
Ein Hinweis, der einen Job in Python implementiert, der eine GCS-Datei in BigQuery lädt
Beachten Sie, dass sich die Methode zum Veröffentlichen von Modulen in PyPI auf verschiedene Weise geändert hat.