Ouverture d’un fichier de 20 Go pour analyse avec des pandas


33

J'essaie actuellement d'ouvrir un fichier contenant des pandas et du python à des fins d'apprentissage automatique. Il serait idéal pour moi de les avoir tous dans un DataFrame. Maintenant, le fichier fait 18 Go et ma mémoire vive de 32 Go, mais je continue à avoir des erreurs de mémoire.

D'après votre expérience, est-ce possible? Si non, connaissez-vous une meilleure façon de contourner cela? (table de ruche? augmenter la taille de ma RAM à 64? créer une base de données et y accéder depuis python)


J'ai eu le même problème, je vous suggère d'augmenter l'échange, la pagination, la taille de votre disque dur.
Médias

En règle générale, lors du chargement de données pandas, vous devez disposer de 5 à 10 fois plus de RAM. Je recommande de faire des inplaceopérations, appeler explicitement garbage.collectorpour désallouer des objets.
Kiritee Gak

4
Améliorez cette question en précisant votre objectif final. Faites-vous une analyse exploratoire des données, le nettoyage des données, la formation d'un modèle ou quoi? Quel genre de données?
Pete

1
Avez-vous envisagé d'utiliser Dask ?
Rpanai

Réponses:


32

S'il s'agit d'un fichier csv et que vous n'avez pas besoin d'accéder à toutes les données en même temps lors de la formation de votre algorithme, vous pouvez le lire en morceaux. La pandas.read_csvméthode vous permet de lire un fichier par morceaux comme ceci:

import pandas as pd
for chunk in pd.read_csv(<filepath>, chunksize=<your_chunksize_here>)
    do_processing()
    train_algorithm()

Voici la documentation de la méthode


cela s'applique-t-il également au fichier zip?
James Wierzba le

Cela devrait fonctionner si le fichier compressé est également un fichier csv, vous devrez passer le type de compression comme argument de la méthode
Olel Daniel

22

Il existe deux possibilités: soit vous devez avoir toutes vos données en mémoire pour le traitement (votre algorithme d’apprentissage automatique souhaite par exemple les consommer toutes en même temps), soit vous pouvez vous en passer (votre algorithme n’a par exemple besoin que d’échantillons de lignes). colonnes à la fois).

Dans le premier cas, vous devrez résoudre un problème de mémoire . Augmentez la taille de votre mémoire, louez une machine dans le cloud, utilisez des opérations in-situ, fournissez des informations sur le type de données que vous lisez, assurez-vous de supprimer toutes les variables inutilisées et de ramasser les déchets, etc.

Il est très probable que 32 Go de RAM ne suffiraient pas à Pandas pour gérer vos données. Notez que le nombre entier "1" est juste un octet lorsqu'il est stocké en tant que texte mais 8 octets lorsqu'il est représenté par int64(ce qui est la valeur par défaut lorsque Pandas le lit dans du texte). Vous pouvez faire le même exemple avec un nombre à virgule flottante "1.0" qui passe d'une chaîne de 3 octets à une chaîne de 8 octets float64par défaut. Vous gagnerez peut-être un peu d’espace en laissant les pandas savoir avec précision les types à utiliser pour chaque colonne et en forçant les représentations les plus petites possibles, mais nous n’avons même pas commencé à parler de la surcharge de la structure de données de Python ici, ce qui peut ajouter un ou deux pointeurs facilement ici et là. , et les pointeurs sont de 8 octets chacun sur un ordinateur 64 bits.

Pour résumer: non, 32 Go de RAM ne sont probablement pas suffisants pour que les Pandas puissent gérer un fichier de 20 Go.

Dans le second cas (qui est plus réaliste et qui s’applique probablement à vous), vous devez résoudre un problème de gestion des données . En effet, le fait de charger toutes les données alors que vous n'en avez vraiment besoin que pour le traitement peut être le signe d'une mauvaise gestion des données. Il y a plusieurs options ici:

  1. Utilisez une base de données SQL. Si vous le pouvez, c'est presque toujours le premier choix et une solution décente et confortable. 20 Go semble correspondre à la taille de la plupart des bases de données SQL, même sans ordinateur portable (haut de gamme). Vous pourrez indexer des colonnes, effectuer des agrégations de base via SQL et obtenir les sous-échantillons nécessaires dans des pandas pour un traitement plus complexe à l'aide d'un simple pd.read_sql. Déplacer les données vers une base de données vous donnera également l'occasion de réfléchir aux types de données et aux tailles réelles de vos colonnes.

  2. Si vos données sont principalement numériques (c.-à-d. Matrices ou tenseurs), vous pouvez envisager de les conserver au format HDF5 (voir PyTables ), ce qui vous permet de ne lire que les tranches de grandes matrices nécessaires sur le disque. Les bases numpy.save et numpy.load obtiennent le même effet en mappant en mémoire les baies sur le disque. Pour les SIG et les données raster associées, il existe des bases de données dédiées , qui peuvent ne pas se connecter aux pandas aussi directement que SQL, mais doivent également vous permettre d'effectuer des tranches et des requêtes de manière raisonnablement simple.

  3. Les pandas ne prennent pas en charge un tel mappage mémoire "partiel" de HDF5 ou de matrices Numpy, à ma connaissance. Si vous voulez toujours une sorte de solution "pur-pandas", vous pouvez essayer de contourner le problème en "sharding": soit en stockant les colonnes de votre immense table séparément (par exemple dans des fichiers séparés ou dans des "tables" séparées d'un HDF5 unique). fichier) et en ne chargeant que ceux nécessaires à la demande, ou en stockant les morceaux de lignes séparément. Cependant, vous devrez alors implémenter la logique de chargement des morceaux nécessaires, réinventant ainsi les bicyclettes déjà implémentées dans la plupart des bases de données SQL. L'option 1 serait peut-être encore plus simple ici. Toutefois, si vos données sont au format CSV, vous pouvez les traiter en morceaux en spécifiant le chunksizeparamètre to pd.read_csv.


5
Quelque chose doit être mentionné dans "le premier cas" est que si le PO a beaucoup d'entrées avec la même valeur dans les données (comme des zéros), les données sont dites éparses et une matrice scipy sparse pourrait être utilisée à la place d'un pandas dataframe - les données rares nécessitent beaucoup moins de mémoire.
Ricardo Cruz

9

Je viens d'avoir ce problème il y a quelques jours! Je ne suis pas sûr que cela vous aide dans votre cas particulier, car vous ne fournissez pas autant de détails, mais ma situation était de travailler hors ligne sur un jeu de données «volumineux». Les données ont été obtenues sous forme de fichiers CSV compressés à 20 Go à partir de compteurs d’énergie, ainsi que des données chronologiques à plusieurs secondes.

Fichier IO:

data_root = r"/media/usr/USB STICK"
fname = r"meters001-050-timestamps.csv.gz"
this_file = os.path.join(data_root,fname)
assert os.path.exists(this_file), this_file
this_file

Créez un itérateur de bloc directement sur le fichier gzip (ne décompressez pas le fichier!)

cols_to_keep = [0,1,2,3,7]
column_names = ['METERID','TSTAMP','ENERGY','POWER_ALL','ENERGY_OUT',]
parse_dates = ['TSTAMP']
dtype={'METERID': np.int32, 
       'ENERGY': np.int32,
       'POWER_ALL': np.int32,
       'ENERGY_OUT': np.int32,
      }
df_iterator = pd.read_csv(this_file, 
                        skiprows=0, 
                        compression='gzip',
                        chunksize=1000000, 
                        usecols=cols_to_keep,
                        delimiter=";",
                        header=None,
                        names = column_names,
                      dtype=dtype,
                     parse_dates=parse_dates,
                     index_col=1,
                     )

Itérer sur les morceaux

new_df = pd.DataFrame()
count = 0
for df in df_iterator:
    chunk_df_15min = df.resample('15T').first()
    #chunk_df_30min = df.resample('30T').first()
    #chunk_df_hourly = df.resample('H').first()
    this_df = chunk_df_15min
    this_df = this_df.pipe(lambda x: x[x.METERID == 1])
    #print("chunk",i)
    new_df = pd.concat([new_df,chunk_df_15min])
    print("chunk",count, len(chunk_df_15min), 'rows added')
    #print("chunk",i, len(temp_df),'rows added')
    #break
    count += 1

À l'intérieur de la boucle de morceau, je filtre et ré-échantillonne à temps. Ce faisant, j'ai réduit la taille de 20 Go à quelques centaines de Mo HDF5 pour une exploration plus poussée des données hors connexion.


5

D'après mon expérience, l'initialisation read_csv()avec le paramètre a low_memory=Falsetendance à être utile lors de la lecture de fichiers volumineux. Je ne pense pas que vous ayez mentionné le type de fichier que vous lisez, alors je ne sais pas si cela est applicable à votre situation.


1

Si votre fichier est un fichier CSV, vous pouvez simplement le faire dans Chunk by Chunk. Vous pouvez simplement faire:

import pandas as pd
for chunk in pd.read_csv(FileName, chunksize=ChunkSizeHere)
(Do your processing and training here)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.