web-dev-qa-db-fra.com

Comment lire un fichier csv de 6 Go avec des pandas

J'essaie de lire un gros fichier csv (environ 6 Go) sur des pandas et j'obtiens l'erreur de mémoire suivante:

MemoryError                               Traceback (most recent call last)
<ipython-input-58-67a72687871b> in <module>()
----> 1 data=pd.read_csv('aphro.csv',sep=';')

C:\Python27\lib\site-packages\pandas\io\parsers.pyc in parser_f(filepath_or_buffer, sep, dialect, compression, doublequote, escapechar, quotechar, quoting, skipinitialspace, lineterminator, header, index_col, names, prefix, skiprows, skipfooter, skip_footer, na_values, na_fvalues, true_values, false_values, delimiter, converters, dtype, usecols, engine, delim_whitespace, as_recarray, na_filter, compact_ints, use_unsigned, low_memory, buffer_lines, warn_bad_lines, error_bad_lines, keep_default_na, thousands, comment, decimal, parse_dates, keep_date_col, dayfirst, date_parser, memory_map, nrows, iterator, chunksize, verbose, encoding, squeeze, mangle_dupe_cols, tupleize_cols, infer_datetime_format)
    450                     infer_datetime_format=infer_datetime_format)
    451 
--> 452         return _read(filepath_or_buffer, kwds)
    453 
    454     parser_f.__= name

C:\Python27\lib\site-packages\pandas\io\parsers.pyc in _read(filepath_or_buffer, kwds)
    242         return parser
    243 
--> 244     return parser.read()
    245 
    246 _parser_defaults = {

C:\Python27\lib\site-packages\pandas\io\parsers.pyc in read(self, nrows)
    693                 raise ValueError('skip_footer not supported for iteration')
    694 
--> 695         ret = self._engine.read(nrows)
    696 
    697         if self.options.get('as_recarray'):

C:\Python27\lib\site-packages\pandas\io\parsers.pyc in read(self, nrows)
   1137 
   1138         try:
-> 1139             data = self._reader.read(nrows)
   1140         except StopIteration:
   1141             if nrows is None:

C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader.read (pandas\parser.c:7145)()

C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._read_low_memory (pandas\parser.c:7369)()

C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._read_rows (pandas\parser.c:8194)()

C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._convert_column_data (pandas\parser.c:9402)()

C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._convert_tokens (pandas\parser.c:10057)()

C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser.TextReader._convert_with_dtype (pandas\parser.c:10361)()

C:\Python27\lib\site-packages\pandas\parser.pyd in pandas.parser._try_int64 (pandas\parser.c:17806)()

MemoryError: 

Toute aide sur ce ?? 

115
Rajkumar Kumawat

L'erreur indique que la machine ne dispose pas de suffisamment de mémoire pour lire l'intégralité du fichier CSV dans un DataFrame à la fois. En supposant que vous n'ayez pas besoin de l'intégralité du jeu de données dans la mémoire , Un moyen d'éviter le problème serait de traiter le fichier CSV dans Chunks (en spécifiant le paramètre chunksize):

chunksize = 10 ** 6
for chunk in pd.read_csv(filename, chunksize=chunksize):
    process(chunk)

Le paramètre chucksize spécifie le nombre de lignes par morceau . (Le dernier morceau peut contenir moins de chunksize lignes, bien sûr).

153
unutbu

La segmentation ne devrait pas toujours être le premier point de contact pour résoudre ce problème.

1. Le fichier est-il volumineux en raison de données répétées non numériques ou de colonnes non désirées? 

Si tel est le cas, vous pouvez parfois constater des économies de mémoire considérables en lisant les colonnes sous forme de catégories et en sélectionnant les colonnes requises via le paramètre pd.read_csvusecols.

2. Votre flux de travail nécessite-t-il un découpage, une manipulation, une exportation?

Si tel est le cas, vous pouvez utiliser dask.dataframe pour découper, effectuer vos calculs et exporter de manière itérative. Le découpage est effectué silencieusement par dask, qui prend également en charge un sous-ensemble d'IPA de pandas.

3. Si tout échoue, lisez ligne par ligne via des morceaux.

Chunk via pandas ou via bibliothèque csv en dernier recours.

38
jpp

J'ai procédé comme ça:

chunks=pd.read_table('aphro.csv',chunksize=1000000,sep=';',\
       names=['lat','long','rf','date','slno'],index_col='slno',\
       header=None,parse_dates=['date'])

df=pd.DataFrame()
%time df=pd.concat(chunk.groupby(['lat','long',chunk['date'].map(lambda x: x.year)])['rf'].agg(['sum']) for chunk in chunks)
29
Rajkumar Kumawat

Pour les grandes données, je vous recommande d'utiliser la bibliothèque "dask" 
par exemple: 

# Dataframes implement the Pandas API
import dask.dataframe as dd
df = dd.read_csv('s3://.../2018-*-*.csv')
16

La réponse ci-dessus satisfait déjà le sujet. Quoi qu'il en soit, si vous avez besoin de toutes les données en mémoire, jetez un œil à bcolz . Sa compression des données en mémoire. J'ai eu une très bonne expérience avec cela. Mais il manque beaucoup de caractéristiques de pandas

Edit: j’ai obtenu des taux de compression d’environ 1/10 ou une taille d’origine, bien sûr, en fonction du type de données. Les principales caractéristiques manquantes étaient les agrégats. 

8
PlagTag

Vous pouvez lire les données sous forme de morceaux et enregistrer chaque morceau en tant que pickle. 

import pandas as pd 
import pickle

in_path = "" #Path where the large file is
out_path = "" #Path to save the pickle files to
chunk_size = 400000 #size of chunks relies on your available memory
separator = "~"

reader = pd.read_csv(in_path,sep=separator,chunksize=chunk_size, 
                    low_memory=False)    

i=1
for chunk in reader:
    out_file = out_path + "/data_{}.pkl".format(i)
    with open(out_file, "wb") as f:
        pickle.dump(chunk,f,pickle.HIGHEST_PROTOCOL)
    i+=1

Dans l'étape suivante, lisez les cornichons et ajoutez chaque cornichon à la trame de données souhaitée.

import glob
pickle_path = "" #Same Path as out_path i.e. where the pickle files are

data_p_files=[]
for name in glob.glob(pickle_path + "/data_*.pkl"):
   data_p_files.append(name)


df = pd.DataFrame([])
for i in range(len(data_p_files)):
    df = df.append(pd.read_pickle(data_p_files[i]),ignore_index=True)
4
Humpe

Solution 1: 

Utilisation de pandas avec de grandes données

Solution 2:

TextFileReader = pd.read_csv(path, chunksize=1000)  # the number of rows per chunk

dfList = []
for df in TextFileReader:
    dfList.append(df)

df = pd.concat(dfList,sort=False)
3
blacksheep

Les fonctions read_csv et read_table sont presque identiques. Mais vous devez assigner le délimiteur «» lorsque vous utilisez la fonction read_table dans votre programme.

def get_from_action_data(fname, chunk_size=100000):
    reader = pd.read_csv(fname, header=0, iterator=True)
    chunks = []
    loop = True
    while loop:
        try:
            chunk = reader.get_chunk(chunk_size)[["user_id", "type"]]
            chunks.append(chunk)
        except StopIteration:
            loop = False
            print("Iteration is stopped")

    df_ac = pd.concat(chunks, ignore_index=True)
2
Tyrion W

Vous pouvez essayer sframe, qui a la même syntaxe que les pandas mais vous permet de manipuler des fichiers plus volumineux que votre RAM.

2
NunodeSousa

Voici un exemple:

chunkTemp = []
queryTemp = []
query = pd.DataFrame()

for chunk in pd.read_csv(file, header=0, chunksize=<your_chunksize>, iterator=True, low_memory=False):

    #REPLACING BLANK SPACES AT COLUMNS' NAMES FOR SQL OPTIMIZATION
    chunk = chunk.rename(columns = {c: c.replace(' ', '') for c in chunk.columns})

    #YOU CAN EITHER: 
    #1)BUFFER THE CHUNKS IN ORDER TO LOAD YOUR WHOLE DATASET 
    chunkTemp.append(chunk)

    #2)DO YOUR PROCESSING OVER A CHUNK AND STORE THE RESULT OF IT
    query = chunk[chunk[<column_name>].str.startswith(<some_pattern>)]   
    #BUFFERING PROCESSED DATA
    queryTemp.append(query)

#!  NEVER DO pd.concat OR pd.DataFrame() INSIDE A LOOP
print("Database: CONCATENATING CHUNKS INTO A SINGLE DATAFRAME")
chunk = pd.concat(chunkTemp)
print("Database: LOADED")

#CONCATENATING PROCESSED DATA
query = pd.concat(queryTemp)
print(query)
1
jonathask

Si vous utilisez des pandas pour lire des fichiers volumineux en gros morceaux, puis cédez rangée par rangée, voici ce que j'ai fait

import pandas as pd

def chunck_generator(filename, header=False,chunk_size = 10 ** 5):
   for chunk in pd.read_csv(filename,delimiter=',', iterator=True, chunksize=chunk_size, parse_dates=[1] ): 
        yield (chunk)

def _generator( filename, header=False,chunk_size = 10 ** 5):
    chunk = chunck_generator(filename, header=False,chunk_size = 10 ** 5)
    for row in chunk:
        yield row

if __== "__main__":
filename = r'file.csv'
        generator = generator(filename=filename)
        while True:
           print(next(generator))
1
paulg

En plus des réponses ci-dessus, pour ceux qui veulent traiter CSV puis exporter au format csv, parquet ou SQL, d6tstack est une autre bonne option. Vous pouvez charger plusieurs fichiers et il traite des modifications de schéma de données (colonnes ajoutées/supprimées). Une partie du support principal est déjà intégrée.

def apply(dfg):
    # do stuff
    return dfg

c = d6tstack.combine_csv.CombinerCSV([bigfile.csv], apply_after_read=apply, sep=',', chunksize=1e6)

# or
c = d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), apply_after_read=apply, chunksize=1e6)

# output to various formats, automatically chunked to reduce memory consumption
c.to_csv_combine(filename='out.csv')
c.to_parquet_combine(filename='out.pq')
c.to_psql_combine('postgresql+psycopg2://usr:pwd@localhost/db', 'tablename') # fast for postgres
c.to_mysql_combine('mysql+mysqlconnector://usr:pwd@localhost/db', 'tablename') # fast for mysql
c.to_sql_combine('postgresql+psycopg2://usr:pwd@localhost/db', 'tablename') # slow but flexible
0
citynorman

Si quelqu'un cherche toujours quelque chose comme ça, j'ai trouvé que cette nouvelle bibliothèque appelée modin peut aider. Il utilise l'informatique distribuée qui peut aider à la lecture. Voici un joli article comparant sa fonctionnalité avec celle des pandas. Il utilise essentiellement les mêmes fonctions que les pandas.

import modin.pandas as pd
pd.read_csv(CSV_FILE_NAME)
0
Jaskaran