Come posso filtrare le righe al caricamento nella funzione read_csv di Pandas?


94

Come posso filtrare le righe di un CSV da caricare in memoria utilizzando i panda? Questa sembra un'opzione che si dovrebbe trovare in read_csv. Mi sto perdendo qualcosa?

Esempio: abbiamo un CSV con una colonna timestamp e vorremmo caricare solo le righe che hanno un timestamp maggiore di una data costante.

Risposte:


163

Non esiste un'opzione per filtrare le righe prima che il file CSV venga caricato in un oggetto panda.

Puoi caricare il file e quindi filtrare usando df[df['field'] > constant], o se hai un file molto grande e sei preoccupato che la memoria si esaurisca, usa un iteratore e applica il filtro mentre concateni parti del tuo file, ad esempio:

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])

È possibile variare il chunksizeper soddisfare la memoria disponibile. Vedi qui per maggiori dettagli.


perché chunk['filed']>constantposso inserirli tra 2 valori costanti? Ad esempio: costante1> blocco ['campo']> costante2. O posso usare "in range"?
weefwefwqg3

Prova:chunk[(chunk['field'] > constant2)&(chunk['field']<constant1)]
Johannes Wachs

Manca un .loc? chunk.loc[chunk['field'] > constant]
Vincent

1
Puoi usare maschere booleane con o senza .loc. Non credo che .locesistesse nel 2012, ma immagino che in questi giorni l'uso .locsia un po 'più esplicito.
Matti John,

8

Non ho trovato un modo semplice per farlo nel contesto di read_csv. Tuttavia, read_csvrestituisce un DataFrame, che può essere filtrato selezionando le righe dal vettore booleano df[bool_vec]:

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

Questa è la selezione di tutte le righe in df (supponendo che df sia un qualsiasi DataFrame, come il risultato di una read_csvchiamata, che contiene almeno una colonna datetime timestamp) per cui i valori nella timestampcolonna sono maggiori del valore di targettime. Domanda simile .


1
Non ne sono sicuro, ma ho la sensazione che sarebbe estremamente pesante per l'utilizzo della memoria.
Nathan

2

Se l'intervallo filtrato è contiguo (come di solito accade con i filtri di data e ora (timbro)), la soluzione più veloce è codificare l'intervallo di righe. Combina semplicemente skiprows=range(1, start_row)con i nrows=end_rowparametri. Quindi l'importazione richiede pochi secondi mentre la soluzione accettata richiederebbe minuti. Alcuni esperimenti con l'iniziale start_rownon sono un costo enorme visto il risparmio sui tempi di importazione. Si noti che abbiamo mantenuto la riga di intestazione utilizzando range(1,..).


-3

Se sei su Linux puoi usare grep.

# 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

1
Usare grep è una scelta seriamente sbagliata per diversi motivi. 1) è lento 2) non è portatile 3) non è panda o python (puoi usare espressioni regolari proprio all'interno di python), motivo per cui ho downvotato la tua risposta
Ahmed Masud

La tua soluzione non funziona su tutte le piattaforme e include anche Grep. Questa è la ragione del voto negativo.
Roman Orac

-3

È possibile specificare il nrowsparametro.

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

Questo codice funziona bene nella versione 0.20.3.


1
OP chiede come filtrare non limitare il numero di righe lette. Questo è il motivo per cui ho svalutato la tua risposta.
Roman Orac
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.