Wie kann ich Zeilen beim Laden in der Pandas-Funktion read_csv filtern?

94

Wie kann ich filtern, welche Zeilen einer CSV mit Pandas in den Speicher geladen werden sollen? Dies scheint eine Option zu sein, die man finden sollte read_csv. Vermisse ich etwas

Beispiel: Wir haben eine CSV mit einer Zeitstempelspalte und möchten nur die Zeilen laden, deren Zeitstempel größer als eine bestimmte Konstante ist.

Benjaminwilson
quelle

Antworten:

163

Es gibt keine Option zum Filtern der Zeilen, bevor die CSV-Datei in ein Pandas-Objekt geladen wird.

Sie können entweder die Datei laden und dann mit filtern. df[df['field'] > constant]Wenn Sie eine sehr große Datei haben und sich Sorgen machen, dass der Speicher knapp wird, verwenden Sie einen Iterator und wenden Sie den Filter an, während Sie Teile Ihrer Datei verketten, z.

import pandas as pd
iter_csv = pd.read_csv('file.csv', iterator=True, chunksize=1000)
df = pd.concat([chunk[chunk['field'] > constant] for chunk in iter_csv])

Sie können den chunksizeSpeicher entsprechend Ihrem verfügbaren Speicher variieren . Sehen Sie hier für weitere Details.

Matti John
quelle
denn chunk['filed']>constantkann ich es zwischen 2 konstanten Werten einklemmen? Beispiel: Konstante1> Chunk ['Feld']> Konstante2. Oder kann ich "in Reichweite" verwenden?
weefwefwqg3
Versuchen Sie:chunk[(chunk['field'] > constant2)&(chunk['field']<constant1)]
Johannes Wachs
Fehlt das ein .loc? chunk.loc[chunk['field'] > constant]
Vincent
1
Sie können boolesche Masken mit oder ohne verwenden .loc. Ich glaube nicht, dass .loces 2012 existiert hat, aber ich denke, dass die Verwendung heutzutage .locetwas expliziter ist.
Matti John
8

Ich habe keinen direkten Weg gefunden, dies im Kontext von zu tun read_csv. read_csvGibt jedoch einen DataFrame zurück, der durch Auswahl von Zeilen nach booleschem Vektor gefiltert werden kann df[bool_vec]:

filtered = df[(df['timestamp'] > targettime)]

Hierbei werden alle Zeilen in df ausgewählt (vorausgesetzt, df ist ein beliebiger DataFrame, z. B. das Ergebnis eines read_csvAufrufs, der mindestens eine datetime-Spalte enthält timestamp), für die die Werte in der timestampSpalte größer als der Wert von targettime sind. Ähnliche Frage .

Greif
quelle
1
Ich bin mir nicht sicher, aber ich habe das Gefühl, dass dies die Speichernutzung extrem stark belasten würde.
Nathan
2

Wenn der gefilterte Bereich zusammenhängend ist (wie es normalerweise bei Zeitfiltern (Stempelfiltern) der Fall ist), besteht die schnellste Lösung darin, den Zeilenbereich fest zu codieren. Einfach skiprows=range(1, start_row)mit nrows=end_rowParametern kombinieren . Dann dauert der Import Sekunden, während die akzeptierte Lösung Minuten dauern würde. Ein paar Experimente mit der Initiale start_rowsind angesichts der Einsparungen bei den Importzeiten keine großen Kosten. Beachten Sie, dass wir die Kopfzeile mit verwendet haben range(1,..).

mirekphd
quelle
-3

Wenn Sie unter Linux arbeiten, können Sie grep verwenden.

# to import either on Python2 or Python3
import pandas as pd
from time import time # not needed just for timing
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO


def zgrep_data(f, string):
    '''grep multiple items f is filepath, string is what you are filtering for'''

    grep = 'grep' # change to zgrep for gzipped files
    print('{} for {} from {}'.format(grep,string,f))
    start_time = time()
    if string == '':
        out = subprocess.check_output([grep, string, f])
        grep_data = StringIO(out)
        data = pd.read_csv(grep_data, sep=',', header=0)

    else:
        # read only the first row to get the columns. May need to change depending on 
        # how the data is stored
        columns = pd.read_csv(f, sep=',', nrows=1, header=None).values.tolist()[0]    

        out = subprocess.check_output([grep, string, f])
        grep_data = StringIO(out)

        data = pd.read_csv(grep_data, sep=',', names=columns, header=None)

    print('{} finished for {} - {} seconds'.format(grep,f,time()-start_time))
    return data
Christopher Bell
quelle
1
Die Verwendung von grep ist aus mehreren Gründen eine ernsthaft schlechte Wahl. 1) es ist langsam 2) es ist nicht portabel 3) es ist nicht Pandas oder Python (Sie können reguläre Ausdrücke direkt in Python verwenden), weshalb ich Ihre Antwort abgelehnt habe
Ahmed Masud
Ihre Lösung funktioniert nicht auf allen Plattformen und enthält auch Grep. Dies ist der Grund für die Ablehnung.
Roman Orac
-3

Sie können nrowsParameter angeben .

import pandas as pd df = pd.read_csv('file.csv', nrows=100)

Dieser Code funktioniert gut in Version 0.20.3.

user1083290
quelle
1
OP fragt, wie gefiltert werden soll, ohne die Anzahl der gelesenen Zeilen zu begrenzen. Deshalb habe ich Ihre Antwort abgelehnt.
Roman Orac