it-swarm.com.de

Liest eine riesige CSV-Datei

Ich versuche derzeit, Daten aus CSV-Dateien in Python 2.7 mit bis zu 1 Million Zeilen und 200 Spalten (Dateien von 100 MB bis 1,6 GB) zu lesen langsam) für die Dateien mit weniger als 300.000 Zeilen, aber sobald ich darüber hinausgehe, erhalte ich Speicherfehler. Mein Code sieht folgendermaßen aus:

def getdata(filename, criteria):
    data=[]
    for criterion in criteria:
        data.append(getstuff(filename, criteron))
    return data

def getstuff(filename, criterion):
    import csv
    data=[]
    with open(filename, "rb") as csvfile:
        datareader=csv.reader(csvfile)
        for row in datareader: 
            if row[3]=="column header":
                data.append(row)
            Elif len(data)<2 and row[3]!=criterion:
                pass
            Elif row[3]==criterion:
                data.append(row)
            else:
                return data

Der Grund für die else-Klausel in der getstuff-Funktion ist, dass alle Elemente, die das Kriterium erfüllen, in der csv-Datei zusammen aufgeführt werden. Ich verlasse die Schleife, wenn ich an ihnen vorbeikomme, um Zeit zu sparen.

Meine Fragen sind:

  1. Wie kann ich es schaffen, dass dies mit den größeren Dateien funktioniert?

  2. Kann ich es auf irgendeine Weise schneller machen?

Mein Computer verfügt über 8 GB RAM, auf dem 64-Bit-Windows 7 ausgeführt wird, und der Prozessor ist 3,40 GHz (nicht sicher, welche Informationen Sie benötigen).

89
Charles Dillon

Sie lesen alle Zeilen in eine Liste ein und verarbeiten diese Liste dann. Tu das nicht .

Verarbeiten Sie Ihre Zeilen, während Sie sie produzieren. Wenn Sie die Daten zuerst filtern müssen, verwenden Sie eine Generatorfunktion:

import csv

def getstuff(filename, criterion):
    with open(filename, "rb") as csvfile:
        datareader = csv.reader(csvfile)
        yield next(datareader)  # yield the header row
        count = 0
        for row in datareader:
            if row[3] == criterion:
                yield row
                count += 1
            Elif count:
                # done when having read a consecutive series of rows 
                return

Ich habe auch Ihren Filtertest vereinfacht. Die Logik ist die gleiche, aber prägnanter.

Da Sie nur eine einzige Folge von Zeilen abgleichen, die dem Kriterium entsprechen, können Sie auch Folgendes verwenden:

import csv
from itertools import dropwhile, takewhile

def getstuff(filename, criterion):
    with open(filename, "rb") as csvfile:
        datareader = csv.reader(csvfile)
        yield next(datareader)  # yield the header row
        # first row, plus any subsequent rows that match, then stop
        # reading altogether
        # Python 2: use `for row in takewhile(...): yield row` instead
        # instead of `yield from takewhile(...)`.
        yield from takewhile(
            lambda r: r[3] == criterion,
            dropwhile(lambda r: r[3] != criterion, datareader))
        return

Sie können jetzt getstuff() direkt durchlaufen. Mach dasselbe in getdata():

def getdata(filename, criteria):
    for criterion in criteria:
        for row in getstuff(filename, criterion):
            yield row

Jetzt schleife direkt über getdata() in deinem Code:

for row in getdata(somefilename, sequence_of_criteria):
    # process row

Sie speichern jetzt nur eine Zeile anstelle Ihrer Tausenden von Zeilen pro Kriterium.

yield macht eine Funktion zu einer Generatorfunktion , was bedeutet, dass sie erst dann funktioniert, wenn Sie eine Schleife darüber erstellen.

136
Martijn Pieters

Obwohl Martijins Antwort wahrscheinlich die beste ist. Hier finden Sie eine intuitivere Möglichkeit, große CSV-Dateien für Anfänger zu verarbeiten. Auf diese Weise können Sie Gruppen von Zeilen oder Blöcken gleichzeitig verarbeiten.

import pandas as pd
chunksize = 10 ** 8
for chunk in pd.read_csv(filename, chunksize=chunksize):
    process(chunk)
29
mmann1123

Ich führe eine ganze Reihe von Schwingungsanalysen durch und sehe mir große Datensätze an (Dutzende und Hunderte von Millionen von Punkten). Meine Tests haben gezeigt, dass die Funktion pandas.read_csv () 20 mal schneller ist als numpy.genfromtxt (). Und die Funktion genfromtxt () ist dreimal schneller als die Funktion numpy.loadtxt (). Es scheint, dass Sie brauchen pandas für große Datenmengen.

Ich habe den Code und die Datensätze, die ich in diesem Test verwendet habe, in einem Blog veröffentlicht, in dem es um MATLAB vs Python für die Schwingungsanalyse geht.

12
Steve

was bei mir funktioniert hat und superfast ist

import pandas as pd
import dask.dataframe as dd
import time
t=time.clock()
df_train = dd.read_csv('../data/train.csv', usecols=[col1, col2])
df_train=df_train.compute()
print("load train: " , time.clock()-t)

Eine andere funktionierende Lösung ist:

import pandas as pd 
from tqdm import tqdm

PATH = '../data/train.csv'
chunksize = 500000 
traintypes = {
'col1':'category',
'col2':'str'}

cols = list(traintypes.keys())

df_list = [] # list to hold the batch dataframe

for df_chunk in tqdm(pd.read_csv(PATH, usecols=cols, dtype=traintypes, chunksize=chunksize)):
    # Can process each chunk of dataframe here
    # clean_data(), feature_engineer(),fit()

    # Alternatively, append the chunk to list and merge all
    df_list.append(df_chunk) 

# Merge all dataframes into one dataframe
X = pd.concat(df_list)

# Delete the dataframe list to release memory
del df_list
del df_chunk
4
Yury Wallet

Für jemanden, der auf diese Frage landet. Verwendung von pandas mit ' chunksize ' und ' usecols 'hat mir geholfen, eine große Zip-Datei schneller als die anderen vorgeschlagenen Optionen zu lesen.

import pandas as pd

sample_cols_to_keep =['col_1', 'col_2', 'col_3', 'col_4','col_5']

# First setup dataframe iterator, ‘usecols’ parameter filters the columns, and 'chunksize' sets the number of rows per chunk in the csv. (you can change these parameters as you wish)
df_iter = pd.read_csv('../data/huge_csv_file.csv.gz', compression='gzip', chunksize=20000, usecols=sample_cols_to_keep) 

# this list will store the filtered dataframes for later concatenation 
df_lst = [] 

# Iterate over the file based on the criteria and append to the list
for df_ in df_iter: 
        tmp_df = (df_.rename(columns={col: col.lower() for col in df_.columns}) # filter eg. rows where 'col_1' value grater than one
                                  .pipe(lambda x:  x[x.col_1 > 0] ))
        df_lst += [tmp_df.copy()] 

# And finally combine filtered df_lst into the final lareger output say 'df_final' dataframe 
df_final = pd.concat(df_lst)
1
ewalel

hier ist eine andere Lösung für Python3:

import csv
with open(filename, "r") as csvfile:
    datareader = csv.reader(csvfile)
    count = 0
    for row in datareader:
        if row[3] in ("column header", criterion):
            doSomething(row)
            count += 1
        Elif count > 2:
            break

hier ist datareader eine Generatorfunktion.

1