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é.
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.
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`
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()
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
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.
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.