Comment optimiser les pandas lorsque vous travaillez avec de grands ensembles de données (essai)

Lorsque la mémoire des wagons et / ou d'un petit ensemble de données peut être jetée en toute sécurité dans des pandas sans aucune optimisation. Cependant, si les données sont volumineuses, la question se pose de savoir comment les traiter ou au moins les compter.

Il est proposé de regarder l'optimisation en miniature afin de ne pas extraire des ensembles de données géants du réseau.

En tant qu'ensemble de données, nous utiliserons les habrastatistiques avec les commentaires des utilisateurs pour 2019, qui sont accessibles au public grâce à un utilisateur assidu:
jeu de données

À titre d'information, l' article précédemment traduit de Habr sera utilisé, dans lequel de nombreuses choses intéressantes sont mélangées.

Au lieu de rejoindre


L'ensemble de données habrastatistiques est considéré comme petit, bien qu'il occupe 288 Mo et se compose de 448533 lignes.
Bien sûr, vous pouvez trouver plus de données, mais pour ne pas accrocher la voiture, laissez-nous nous y attarder.

Pour la commodité des opérations, nous allons ajouter (il suffit d'écrire la première ligne du fichier) les noms des colonnes:

a,b,c,d 

Maintenant, si vous chargez directement l'ensemble de données dans des pandas et vérifiez la quantité de mémoire qu'il utilise

 import os import time import pandas as pd import numpy as np gl = pd.read_csv('habr_2019_comments.csv',encoding='UTF') def mem_usage(pandas_obj): if isinstance(pandas_obj,pd.DataFrame): usage_b = pandas_obj.memory_usage(deep=True).sum() else: #     ,     DataFrame,   Series usage_b = pandas_obj.memory_usage(deep=True) usage_mb = usage_b / 1024 ** 2 #     return "{:03.2f} MB".format(usage_mb) print (gl.info(memory_usage='deep')) 

voir qu'il "mange" 436,1 Mo:

 RangeIndex: 448533 entries, 0 to 448532 Data columns (total 4 columns): a 448533 non-null object b 448533 non-null object c 448533 non-null object d 448528 non-null object dtypes: object(4) memory usage: 436.1 MB 

Cela montre également que nous avons affaire à des colonnes qui contiennent des données de type objet.
Par conséquent, selon l' article , pour les colonnes, il est nécessaire de se concentrer sur l'optimisation calculée pour l'objet. Pour toutes les colonnes sauf une.

La colonne b contient les dates et, pour plus de clarté et de clarté, il est préférable de les envoyer à l'index de l'ensemble de données. Pour ce faire, modifiez le code utilisé lors de la lecture de l'ensemble de données:

 gl = pd.read_csv('habr_2019_comments.csv', parse_dates=['b'], encoding='UTF') 

Maintenant, les dates sont lues comme l'index de l'ensemble de données et la consommation de mémoire est légèrement réduite:

 memory usage: 407.0 MB 

Maintenant, nous optimisons les données dans l'ensemble de données lui-même en dehors des colonnes et de l'index


L'optimisation est appelée: «Optimisation du stockage des données de types d'objets à l'aide de variables catégorielles».

S'il est traduit en russe, nous devons combiner les données dans les colonnes par catégorie, là où elles sont efficaces.

Pour déterminer l'efficacité, vous devez connaître le nombre de valeurs uniques dans les colonnes et s'il est inférieur à 50% du nombre total de valeurs dans la colonne, la combinaison des valeurs dans la catégorie sera effective.

Regardons l'ensemble de données:

 gl_obj=gl.select_dtypes(include=['object']).copy() gl_obj.describe() 
:
  acd count 448533 448533 448528 unique 25100 185 447059 top VolCh 0 ! freq 3377 260438 184 

* colonne avec des dates dans l'index et non affichées

Comme vous pouvez le voir, à partir de la ligne unique, dans les colonnes a et c , l'union dans la catégorie est effective. Pour la colonne a, ce sont 25100 utilisateurs (évidemment moins de 448533), pour les valeurs c-185 de l'échelle avec "+" et "-" (également nettement moins que 448533).

Nous optimisons les colonnes:

 for col in gl_obj.columns: num_unique_values = len(gl_obj[col].unique()) num_total_values = len(gl_obj[col]) if num_unique_values / num_total_values < 0.5: converted_obj.loc[:,col] = gl_obj[col].astype('category') else: converted_obj.loc[:,col] = gl_obj[col] 

Pour comprendre la quantité de mémoire utilisée pour plus de commodité, nous introduisons une fonction:

 def mem_usage(pandas_obj): if isinstance(pandas_obj,pd.DataFrame): usage_b = pandas_obj.memory_usage(deep=True).sum() else: #     ,     DataFrame,   Series usage_b = pandas_obj.memory_usage(deep=True) usage_mb = usage_b / 1024 ** 2 #     return "{:03.2f} MB".format(usage_mb) 

Et vérifiez si l'optimisation a été efficace:

 >>> print('  : '+mem_usage(gl_obj))   : 407.14 MB >>> print('  : '+mem_usage(converted_obj))   : 356.40 MB >>> 

Comme vous pouvez le voir, un gain de 50 Mo supplémentaires a été reçu.

Maintenant, après avoir compris que l'optimisation a été bénéfique (cela se produit et vice versa), nous allons définir les paramètres de l'ensemble de données lors de la lecture afin de prendre immédiatement en compte les données que nous traitons:

 gl = pd.read_csv('habr_2019_comments.csv', parse_dates=['b'],index_col='b',dtype ={'c':'category','a':'category','d':'object'}, encoding='UTF') 

Nous vous souhaitons un travail rapide avec les jeux de données!

Le code de téléchargement est ici .

Source: https://habr.com/ru/post/fr467785/


All Articles