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