web-dev-qa-db-fra.com

Grand DataFrame persistant dans pandas

J'explore de passer à python et pandas comme utilisateur de longue date SAS utilisateur.

Cependant, lors de l'exécution de certains tests aujourd'hui, j'ai été surpris de constater que python était à court de mémoire lors de la tentative de pandas.read_csv(), un fichier csv de 128 Mo. Il contenait environ 200 000 lignes et 200 colonnes de fichiers). principalement des données numériques.

Avec SAS, je peux importer un fichier csv dans un ensemble de données SAS). Il peut être aussi gros que mon disque dur.

Y a-t-il quelque chose d'analogue dans pandas?

Je travaille régulièrement avec des fichiers volumineux et n'ai pas accès à un réseau informatique distribué.

88
Zelazny7

En principe, il ne devrait pas manquer de mémoire, mais il y a actuellement des problèmes de mémoire avec read_csv sur des fichiers volumineux causés par des = Python (c'est vague mais on le sait depuis longtemps: http://github.com/pydata/pandas/ issues/407 ).

Pour le moment, il n’existe pas de solution parfaite (en voici une fastidieuse: vous pouvez transcrire le fichier ligne par ligne dans un tableau NumPy pré-alloué ou un fichier mappé en mémoire --np.mmap), mais c’est un projet sur lequel je vais travailler dans un proche avenir. Une autre solution consiste à lire le fichier par petits morceaux (utilisez iterator=True, chunksize=1000) puis concaténer ensuite avec pd.concat. Le problème survient lorsque vous extrayez l'intégralité du fichier texte en mémoire dans un grand Slurp.

77
Wes McKinney

Wes a bien sûr raison! Je me contente de fournir un exemple de code un peu plus complet. J'ai eu le même problème avec un fichier de 129 Mo, qui a été résolu par:

from pandas import *

tp = read_csv('large_dataset.csv', iterator=True, chunksize=1000)  # gives TextFileReader, which is iterable with chunks of 1000 rows.
df = concat(tp, ignore_index=True)  # df is DataFrame. If errors, do `list(tp)` instead of `tp`
76
fickludd

Ceci est un fil plus ancien, mais je voulais simplement vider ma solution de contournement ici. J'ai d'abord essayé le paramètre chunksize (même avec des valeurs assez petites comme 10000), mais cela n'a pas beaucoup aidé; avait toujours des problèmes techniques avec la taille de la mémoire (mon CSV était ~ 7,5 Go).

Pour le moment, je viens de lire des fragments de fichiers CSV selon une approche en boucle et de les ajouter, par exemple, à une base de données SQLite, étape par étape:

import pandas as pd
import sqlite3
from pandas.io import sql
import subprocess

# In and output file paths
in_csv = '../data/my_large.csv'
out_sqlite = '../data/my.sqlite'

table_name = 'my_table' # name for the SQLite database table
chunksize = 100000 # number of lines to process at each iteration

# columns that should be read from the CSV file
columns = ['molecule_id','charge','db','drugsnow','hba','hbd','loc','nrb','smiles']

# Get number of lines in the CSV file
nlines = subprocess.check_output('wc -l %s' % in_csv, Shell=True)
nlines = int(nlines.split()[0]) 

# connect to database
cnx = sqlite3.connect(out_sqlite)

# Iteratively read CSV and dump lines into the SQLite table
for i in range(0, nlines, chunksize):

    df = pd.read_csv(in_csv,  
            header=None,  # no header, define column header manually later
            nrows=chunksize, # number of rows to read at each iteration
            skiprows=i)   # skip rows that were already read

    # columns to read        
    df.columns = columns

    sql.to_sql(df, 
                name=table_name, 
                con=cnx, 
                index=False, # don't use CSV file index
                index_label='molecule_id', # use a unique column from DataFrame as index
                if_exists='append') 
cnx.close()    
39
user2489252

Ci-dessous, mon flux de travail.

import sqlalchemy as sa
import pandas as pd
import psycopg2

count = 0
con = sa.create_engine('postgresql://postgres:pwd@localhost:00001/r')
#con = sa.create_engine('sqlite:///XXXXX.db') SQLite
chunks = pd.read_csv('..file', chunksize=10000, encoding="ISO-8859-1",
                     sep=',', error_bad_lines=False, index_col=False, dtype='unicode')

En vous basant sur la taille de votre fichier, vous feriez mieux d’optimiser la taille des morceaux.

 for chunk in chunks:
        chunk.to_sql(name='Table', if_exists='append', con=con)
        count += 1
        print(count)

Une fois toutes les données stockées dans la base de données, vous pouvez interroger celles dont vous avez besoin à partir de la base de données.

5
WeNYoBen

Si vous voulez charger d’énormes fichiers csv, dask peut être une bonne option. Il imite le pandas api, donc il semble assez similaire aux pandas

lien vers dask sur github

3
user8108173

Vous pouvez utiliser Pytable plutôt que pandas df. Il est conçu pour les grands ensembles de données et le format de fichier est en hdf5. Le temps de traitement est donc relativement rapide.

1
Elm662