Grande base de données persistante dans les pandas

j'explore la possibilité de passer à python et pandas en tant qu'utilisateur SAS de longue date.

cependant, lors de l'exécution de certains tests aujourd'hui, j'ai été surpris que python a manqué de mémoire en essayant de pandas.read_csv() un fichier csv de 128MO. Il avait environ 200.000 lignes et 200 colonnes de données principalement numériques.

avec SAS, je peux importer un fichier csv dans un ensemble de données SAS et il peut être aussi grand que mon disque dur.

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

je travaille régulièrement avec de gros fichiers et je n'ai pas accès à un réseau de calcul distribué.

82
demandé sur piRSquared 2012-07-24 04:50:49

6 réponses

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 les gros fichiers causés par certains problèmes internes complexes de Python (c'est vague mais c'est connu depuis longtemps: http://github.com/pydata/pandas/issues/407 ).

pour le moment il n'y a pas de solution parfaite (en voici une fastidieuse: vous pourriez transcrire le fichier ligne par ligne dans un tableau pré-alloué de NumPy ou un fichier mappé en mémoire-- np.mmap ), mais je vais y travailler dans un avenir proche. Une autre solution consiste à lire le fichier en petits morceaux (utiliser iterator=True, chunksize=1000 ), puis à concaténer avec pd.concat . Le problème vient quand vous tirez le fichier texte entier dans la mémoire dans un grand slurp.

73
répondu Wes McKinney 2012-09-09 02:46:50

de Wes est bien sûr droite! Je cherche juste un exemple de code 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`
73
répondu fickludd 2016-05-02 17:25:58

c'est un fil plus ancien, mais je voulais juste jeter ma solution de contournement ici. J'ai d'abord essayé le paramètre chunksize (même avec de très petites valeurs comme 10000), mais cela n'a pas aidé beaucoup; j'avais encore des problèmes techniques avec la taille de la mémoire (mon CSV était d'environ 7,5 Go).

en ce moment, je viens de lire des parties des fichiers CSV dans une approche for-loop et 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()    
36
répondu Sebastian 2015-02-06 20:46:56

Si vous voulez charger d'énormes fichiers csv, dask peut être une bonne option. Il imite l'api pandas, donc il se sent tout à fait similaire à pandas

lien de dask sur github

3
répondu user8108173 2017-06-08 21:54:47

ci-dessous est 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')

basé sur la taille de votre fichier, vous feriez mieux d'optimiser le chunksize.

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

après avoir toutes les données dans la base de données, vous pouvez interroger ceux que vous avez besoin de la base de données.

2
répondu Wen 2017-05-19 21:45:28

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
répondu Elm662 2017-02-10 17:38:48