Bagaimana cara memfilter garis saat dimuat di fungsi Pandas read_csv?

95

Bagaimana cara memfilter baris CSV mana yang akan dimuat ke memori menggunakan panda? Ini sepertinya opsi yang harus ditemukan read_csv. Apakah saya melewatkan sesuatu?

Contoh: kami memiliki CSV dengan kolom stempel waktu dan kami ingin memuat hanya baris dengan stempel waktu lebih besar dari konstanta yang diberikan.

benjaminwilson
sumber

Jawaban:

165

Tidak ada opsi untuk memfilter baris sebelum file CSV dimuat ke objek pandas.

Anda dapat memuat file dan kemudian memfilter menggunakan df[df['field'] > constant], atau jika Anda memiliki file yang sangat besar dan Anda khawatir kehabisan memori, gunakan iterator dan terapkan filter saat Anda menggabungkan potongan file, misalnya:

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

Anda dapat memvariasikan chunksizeuntuk menyesuaikan memori yang tersedia. Lihat di sini untuk lebih jelasnya.

Matti John
sumber
karena chunk['filed']>constantdapatkah saya menjepitnya di antara 2 nilai konstan? Misalnya: konstanta1> potongan ['bidang']> konstanta2. Atau dapatkah saya menggunakan 'dalam jangkauan'?
weefwefwqg3
1
Coba:chunk[(chunk['field'] > constant2)&(chunk['field']<constant1)]
Johannes Wachs
Apakah ini hilang .loc? chunk.loc[chunk['field'] > constant]
Vincent
1
Anda dapat menggunakan masker boolean dengan atau tanpa .loc. Saya tidak berpikir .locada di tahun 2012, tapi saya rasa penggunaan hari .locini sedikit lebih eksplisit.
Matti John
8

Saya tidak menemukan cara langsung untuk melakukannya dalam konteks read_csv. Namun, read_csvmengembalikan DataFrame, yang dapat difilter dengan memilih baris menurut vektor boolean df[bool_vec]:

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

Ini memilih semua baris dalam df (dengan asumsi df adalah DataFrame, seperti hasil read_csvpanggilan, yang setidaknya berisi kolom datetime timestamp) yang nilai dalam timestampkolomnya lebih besar dari nilai waktu targettime. Pertanyaan serupa .

Grifon
sumber
1
Saya tidak yakin tentang ini, tetapi saya merasa ini akan sangat berat pada penggunaan memori.
Nathan
2

Jika rentang yang difilter berdekatan (seperti biasanya dengan filter waktu (stempel)), maka solusi tercepat adalah membuat kode keras untuk rentang baris. Cukup gabungkan skiprows=range(1, start_row)dengan nrows=end_rowparameter. Kemudian pengimporan membutuhkan waktu beberapa detik dan solusi yang diterima membutuhkan waktu beberapa menit. Beberapa percobaan dengan yang awal start_rowbukanlah biaya yang besar mengingat penghematan waktu impor. Perhatikan bahwa kita menyimpan baris header dengan menggunakan range(1,..).

mirekphd
sumber
-3

Jika Anda menggunakan linux, Anda dapat menggunakan 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
Christopher Bell
sumber
1
Menggunakan grep adalah pilihan yang sangat buruk karena beberapa alasan. 1) lambat 2) tidak portabel 3) bukan panda atau python (Anda dapat menggunakan ekspresi reguler tepat di dalam python) itulah sebabnya saya menurunkan suara jawaban Anda
Ahmed Masud
Solusi Anda tidak berfungsi di semua platform dan juga termasuk Grep. Inilah alasan dari downvote tersebut.
Roman Orac
-3

Anda dapat menentukan nrowsparameter.

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

Kode ini berfungsi dengan baik di versi 0.20.3.

pengguna1083290
sumber
1
OP menanyakan bagaimana menyaring tidak membatasi jumlah baris yang dibaca. Inilah mengapa saya tidak menyukai jawaban Anda.
Roman Orac