Skip to main content

Lorsque vous utilisez des pandas pour faire fonctionner des données à petite échelle (moins de 100 Mo), la performance n'est souvent pas un problème. Face à des données à plus grande échelle (100 Mo à un nombre de Go), les problèmes de performance entraîneront du temps de fonctionner plus longtemps et conduiront à l'opération en raison de la mémoire insuffisante.


Bien que des étincelles puissent gérer de grands ensembles de données (100 Go à plusieurs SCT), mais doivent souvent utiliser leurs capacités. Matériel coûteux. Et les pandas sont différents, ils manquent d'une fonction riche définie pour nettoyer des données, une exploration et une analyse de haute qualité. Pour les données de taille moyenne, il est préférable d'utiliser beaucoup de pandas, au lieu de remplacer un autre outil.
Dans cet article, nous comprendrons l'utilisation de la mémoire Panda et comment choisir le type de données approprié pour les colonnes. L'utilisation de la mémoire du Dataframe est réduite de près de 90%.




Prénoncez d'abord un journal de match de baseball


.

Nous traiterons des experts des données concurrentielles de baseball de la grande ligue des États-Unis (MLB) de 130 ans, ces données proviennent de la Retrosheet: http: //www.retrosheet.rg/gamelogs/ index.html.


Ces données ont été divisées à l'origine en 127 fichiers CSV différents, mais nous avons utilisé CSVKIT pour fusionner ces données et ajouter des noms de colonne dans la première ligne. Si vous souhaitez télécharger cette version des données utilisées dans cet article, veuillez visiter: https://data.world/dataQuest/mlb-game-logs.

D'abord, entrez les données et regardez cinq lignes de premier plan:



import pandas as pdgl = pd.read_csv('game_logs.csv')gl.head()

















Nous résumons des colonnes importantes, mais si vous souhaitez connaître toutes les colonnes, nous créons également un dictionnaire de données pour l'ensemble du jeu de données: HTTPS: // Data.world/DataQuest/mlb-game- Journaux / Espace de travail / Data-Dictionnaire.


Day - Temps de jeu

V_NAME - Nom de groupe visuel gl.info(memory_usage='deep') v_league - Team Alliance

H_Name -Nom du groupe principal
H_League - Main Group Union

v_Score - Score <class 'pandas.core.frame.DataFrame'>RangeIndex: 171907 entries, 0 to 171906Columns: 161 entries, date to acquisition_infodtypes: float64(77), int64(6), object(78)memory usage: 861.6 MB H_SCORE - Le score principal du groupe

v_line_score - équipe à chaque fois, par exemple: 010000 (10) 00.
H_LINE_SCORE - Le groupe principal enregistre à chaque fois, par exemple: 010000 (10) 0x.

Park_id - Le jeu est détenu dans le jeu

Participation - Audience du jeu


Nous pouvons utiliser la méthode dataframe.info () pour fournir des données de haut niveau américain dans La trame de données, y compris sa taille, des informations de type de données et une utilisation de la mémoire.

Par défaut, Pandas s'approchera le nombre de cadres photo pour gagner du temps. Parce que nous sommes également intéressés par la précision, nous définissons le paramètre Memory_USAGE sur "Deep" pour obtenir le numéro exact.



Nous pouvons constater que nous avons 171 907 lignes et 161 annonces. Pandas détecte automatiquement le mal nous allons nous, trouvez que 83 colonnes sont des valeurs et 78 colonnes sont des objets.Les objets se réfèrent à une chaîne ou à un endroit où le type de données mixte comprend.


Pour mieux comprendre comment réduire la mémoire, voir comment Pandas stocke des données en mémoire.


Deuxièmement, des performances internes du cadre de données

à l'intérieur du panda, le même type de données organisera le même bloc de valeur (bloc de valeur). Vous trouverez ci-dessous un exemple illustrant la méthode de stockage des 12 premières colonnes de données Pandas.



Vous pouvez voir que ces blocs ne contiennent pas le nom vertical d'origine. En effet, ces blocs sont optimisés pour la valeur réelle dans les données de trame de données. La classe BlockManager de Pandas est responsable de la conservation de la relation de cartographie entre l'indice de la ferme et un bloc réel. Il peut être utilisé comme API, fournissant un accès aux données de base. Quoi qu'il en soit, pourquoi choisissons-nous, éditez-nous ou supprimons ces valeurs, l'interface de la couche de Dataframe et la classe BlockManager traduiront l'amourNotre pont pour fonctionner des appels et des méthodes.

for dtype in ['float','int','object']: selected_dtype = gl.select_dtypes(include=[dtype]) mean_usage_b = selected_dtype.memory_usage(deep=True).mean() mean_usage_mb = mean_usage_b / 1024 ** 2 print("Average memory usage for {} columns: {:03.2f} MB".format(dtype,mean_usage_mb))

Dans le module Pandas.core.internals, chaque type a une classe spéciale. Pandas utilise la classe ObjectBlock pour afficher des blocs contenant des colonnes à chaîne, avec une couche flottante pour indiquer des blocs contenant des dimensions dynamiques. Pour les blocs représentant les valeurs des entiers et des stores dynamiques, les pandas incorporent ces colonnes pour stocker Ndarray Numpy. Numpy Ndarray est construit autour de la matrice de langage C, dans lequel la valeur est stockée dans le bloc de mémoire continue. Ce schéma d'hébergement fait la valeur de la valeur très rapide.

Average memory usage for float columns: 1.29 MBAverage memory usage for int columns: 1.12 MBAverage memory usage for object columns: 9.53 MB Parce que chaque type de données est stocké séparément, nous vérifierons l'utilisation de la mémoire de différents types de données. Tout d'abord, voir la quantité moyenne de mémoire de chaque type de données.




On peut voir que 78 colonnes d'objet sont utilisées. Le montant est le plus grand. Parlons cela plus tard. Tout d'abord, voir si vous pouvez améliorer la quantité d'utilisationMademoiselle.

MARDI, Comprendre le style enfant


Comme nous l'avons mentionné ci-dessus, les pandas sont indiqués par une valeur comme Ndarrays Nudarrays et les stocker dans la mémoire continue du bloc. Ce mode de stockage contient moins d'espace et nous permet d'accéder rapidement à ces valeurs rapidement. Parce que Pandas utilise le même nombre d'octets lorsque chaque valeur du même type, Nud Ndarray peut stocker la quantité de valeur, de sorte que le panda peut renvoyer rapidement et avec précision certains octets à consommer par une colonne numérique.

De nombreux types de pandas ont de nombreux types d'enfants, peuvent utiliser moins d'octets pour montrer chaque valeur. Par exemple, le type à flotteur contient des sous-groupes Float16, Float32 et Float64 .. Numéros dans le nom de type représentant le nombre de bits (bit) indique la valeur de ce type. Par exemple: sous-élément que nous venons de répertorier une utilisation à tour de rôle utilise 2, 4, 8, 16 octets. Le tableau suivant fournit un type de dépendance le plus courant dans Panda:


Une valeur INT8 utilisée 1 sLes octets peuvent représenter 256 (2 ^ 8) nombres binaires. Cela signifie que nous pouvons utiliser cette sous-section pour afficher toutes les valeurs brutes de -128 à 127 (y compris 0).

Nous pouvons utiliser une classe numpy.IInfo pour vérifier le maximum et le minimum de chaque entiers. Par exemple:



Ici, nous pouvons voir ici que UINT (la différence entre entier non marqué) et Int (Integer représente). Les deux types ont la même capacité de stockage, mais l'un d'entre eux ne sauve que 0 et positif. Il n'y a pas d'icône entière qui nous permet de gérer des colonnes avec seulement des valeurs positives plus efficacement. import numpy as npint_types = ["uint8", "int8", "int16"]for it in int_types: print(np.iinfo(it))


Machine parameters for uint8---------------------------------------------------------------min = 0max = 255---------------------------------------------------------------Machine parameters for int8---------------------------------------------------------------min = -128max = 127---------------------------------------------------------------Machine parameters for int16---------------------------------------------------------------min = -32768max = 32767---------------------------------------------------------------


Type de colonne de valeur optimisée


nous pouvons utiliser la fonction pd.to_numérique () à faire sous-vue pour la conversion de notre numéro de chiffre taper). Nous allons utiliser dataframe.select_dtypes pour sélectionner une colonne entière, puis nous optimiserons les types.Ses données et compare la quantité de mémoire.



# We're going to be calculating memory usage a lot,# so we'll create a function to save us some time!def mem_usage(pandas_obj): if isinstance(pandas_obj,pd.DataFrame): usage_b = pandas_obj.memory_usage(deep=True).sum() else: # we assume if not a df it's a series usage_b = pandas_obj.memory_usage(deep=True) usage_mb = usage_b / 1024 ** 2 # convert bytes to megabytes return "{:03.2f} MB".format(usage_mb)gl_int = gl.select_dtypes(include=['int'])converted_int = gl_int.apply(pd.to_numeric,downcast='unsigned')print(mem_usage(gl_int))print(mem_usage(converted_int))compare_ints = pd.concat([gl_int.dtypes,converted_int.dtypes],axis=1)compare_ints.columns = ['before','after']compare_ints.apply(pd.Series.value_counts)


, nous pouvons voir que la mémoire est réduite de 7,9 Mo à 1,5 Mo, réduit de plus de 80%. Mais cela n'est pas très affecté par nos données d'origine, la colonne d'origine est donc très petite.

7.87 MB1.48 MB

Travailler sur une colonne dynamique.




nous pouvons voir ce type de données de colonne. La dynamique de colonne devient float32 de Float64, permettant une utilisation de 50% de la mémoire.
gl_float = gl.select_dtypes(include=['float'])converted_float = gl_float.apply(pd.to_numeric,downcast='float')print(mem_usage(gl_float))print(mem_usage(converted_float))compare_floats = pd.concat([gl_float.dtypes,converted_float.dtypes],axis=1)compare_floats.columns = ['before','after']compare_floats.apply(pd.Series.value_counts) Créez une copie pour les données d'origine et remplacez la colonne d'origine avec ces colonnes optimisées, puis surveillez notre mémoire globale actuelle.


100.99 MB50.49 MB


Bien que nous réduisions de manière significative les colonnes numériques, la quantité de mémoire utilisée, mais la mémoire globale ne diminue que 7%. La plupart de nos avantages proviendront d'objets optimisés pour des objets.

Avant de nousDémarrez les actions, regardez le mode de stockage de la chaîne et du type de mode de stockage de la chaîne de caractères et du mode de stockage du type de numéro dans le panda.


Comparaison du stockage en cinq ans, jeudi

Le type d'objet montrant la valeur de l'objet de la chaîne Python, la pièce de la raison est importante des chaînes manquantes. Parce que Python est une langue d'explication de haut niveau, il n'a pas la possibilité de contrôler des particules lisses stockées en mémoire.


Cette limite provoque le mode de stockage de chaînes fragmentées, consommera plus de mémoire et d'un accès plus lent. Chaque élément de la colonne Objet est en réalité un pointeur contenant l'adresse de la valeur réelle en mémoire.


L'image suivante permet de stocker des données de valeur dans le type de données numpumpy et de stocker des données de chaîne avec type Python intégré. optimized_gl = gl.copy()optimized_gl[converted_int.columns] = converted_intoptimized_gl[converted_float.columns] = converted_floatprint(mem_usage(gl))print(mem_usage(optimized_gl))


861.57 MB 804.69 MB Image Source: https: //jakevdp.github.io/blog/2014/09/why-pytHon-is -s -slow /


Dans la table précédente, vousOn peut constater que l'utilisation de la mémoire du type d'objet est variable. Bien que chaque curseur ne représente que 1 octet de mémoire, si chaque chaîne est stockée séparément dans Python, la série réelle est très grande. Nous pouvons utiliser la fonction SYS.GETSIZOOFOOFO () pour le prouver, vérifiez d'abord la chaîne unique, puis voir les éléments Pandas de la série.



, vous pouvez voir que lorsqu'il est stocké dans le Série Pandas, la taille de la chaîne est identique à la taille de la chaîne stockée séparément avec python.

6. Utilisez le type pour optimiser le type d'objet


Panda introduit la chaîne dans la version 0.15. Le type de liste utilise la valeur brute dans la partie inférieure pour afficher la valeur dans une colonne et non la valeur d'origine. Pandas utilise un dictionnaire de mappage distinct pour mapper ces interactions à la valeur d'origine. Cette méthode est très utile tant qu'une colonne contient une collection de valeurs limitées. Quand celaNous convertissons une colonne en une catégorie DTYPE, Pandas utilise un sous-type de la plus de distance pour exprimer toutes les valeurs différentes de la colonne.



Pour comprendre pourquoi nous pouvons utiliser ce type pour réduire l'utilisation de la mémoire, je vois que je vois le nombre de différentes valeurs de chaque entrée du type d'objet.



from sys import getsizeofs1 = 'working out's2 = 'memory usage for's3 = 'strings in python is fun!'s4 = 'strings in python is fun!'for s in [s1, s2, s3, s4]: print(getsizeof(s))


60657474 peuvent le regarder, peut constater que dans 172 000 jeux jouant dans notre Entier de données complètes, le seul nombre de valeurs peut être dit très petit.


Pour comprendre ce qui s'est passé lorsque nous sommes passés dans un type de classification, nous avons sorti un objet de colonne à voir. Nous utiliserons la deuxième colonne de jour_of_week. obj_series = pd.Series(['working out', 'memory usage for', 'strings in python is fun!', 'strings in python is fun!'])obj_series.apply(getsizeof) vous pouvez le voir contient seulement 7 valeurs différentes. Nous utiliserons la méthode .ASType () pour la convertir en un type de classification.
0 601 652 743 74dtype: int64



Comme vous le pouvezVoir, en plus de cette colonne, les données semblent identiques. Voyons ce qui s'est passé derrière ça.

Dans le code suivant, nous avons utilisé l'attribut série.CAT.Codes pour renvoyer le type de catégorie pour indiquer la valeur brute de chaque valeur.



Vous pouvez voir que chaque valeur différente est allouée en valeur brute et le type de données de base actuel Int8. Cette colonne n'a aucune valeur manquante, mais il est calculé que la sous-mère de catégorie peut également être traitée, le mettre juste en -1.

Enfin, voir Comparez l'utilisation de la mémoire entre la conversion de cette colonne vers le type de catégorie.



gl_obj = gl.select_dtypes(include=['object']).copy()gl_obj.describe() 9,8 Mo avec une capacité de mémoire tombée à 0,16 MB, sur 98%! Notez que cette colonne particulière peut représenter l'une de nos meilleures situations - il s'agit d'environ 172 000 mais seulement 7 valeurs différentes.


Bien que toutes les colonnes soient converties enCe type, qui est très important de comprendre qu'il est important de comprendre. Le plus gros inconvénient ne peut pas effectuer de calculs numériques. Si vous ne le convertissez pas en DTYPE numérique, nous ne pouvons pas dévoiler des activités pour la colonne de la liste, c'est-à-dire que la série.min () et la série.max () ne peut pas être utilisée.

Nous devrions souligner 50% du nombre total de colonnes d'objet pour différentes valeurs de différentes valeurs. Si toutes les valeurs d'une colonne sont différentes, la mémoire utilisée par type de catégorie sera plus. Étant donné que cette colonne stocke non seulement toutes les valeurs de chaîne rugueuses, elle stocke également son code de valeur brute. Vous pouvez en apprendre davantage sur les limitations du type de catégorie dans Pandas Document: http://pandas.pydata.org/pandas-docs/stable/cicalical.html.

Nous écrirons une fonction de boucle pour répéter la vérification si le nombre de valeurs différentes dans chaque colonne d'objet est supérieur à 50%; Si c'est le cas, transformez-le en un type de catégorie.


Par rapport au début:


dow = gl_obj.day_of_weekprint(dow.head())dow_cat = dow.astype('category')print(dow_cat.head())


0 Thu1 Fri2 Sat3 Mon4 TueName: day_of_week, dtype: object0 Thu1 Fri2 Sat3 Mon4 TueName: day_of_week, dtype: categoryCategories (7, object): [Fri, Mon, Sat, Sun, Thu, Tue, Wed]




dow_cat.head().cat.codes


0 41 02 23 14 5dtype: int8




print(mem_usage(dow))print(mem_usage(dow_cat))


9.84 MB0.16 MB





converted_obj = pd.DataFrame()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]




print(mem_usage(gl_obj))print(mem_usage(converted_obj))compare_obj = pd.concat([gl_obj.dtypes,converted_obj.dtypes],axis=1)compare_obj.columns = ['before','after']compare_obj.apply(pd.Series.value_counts)


752.72 MB51.67 MB





optimized_gl[converted_obj.columns] = converted_objmem_usage(optimized_gl)


'103.64 MB'




date = optimized_gl.dateprint(mem_usage(date))date.head()


0.66 MB


0 187105041 187105052 187105063 187105084 18710509Name: date, dtype: uint32




optimized_gl['date'] = pd.to_datetime(date,format='%Y%m%d')print(mem_usage(optimized_gl))optimized_gl.date.head()


104.29 MB


0 1871-05-041 1871-05-052 1871-05-063 1871-05-084 1871-05-09Name: date, dtype: datetime64[ns]




] . Dans ce cas, toutes les colonnes d'objet sont converties en catégories, mais toutes les données ne sont pas définies dans ce cas, car vous devez donc utiliser le processus ci-dessus pour vérifier. La quantité de mémoire dans la colonne Objet a été réduite de 752 Mo à 52 Mo, en baisse de 93%. Laissez-nous le combiner avec le reste de nos cadres de données pour voir le niveau de progression atteint au cours des 861 Mo d'avant. WOW, vraiment bon progrès! Nous pouvons également effectuer d'autres optimisations - si vous vous souvenez de la fiche de données fournie précédemment, vous saurez qu'il existe un type DateTime. Ce type peut être utilisé dans cLe premier de ces données définies. , vous pouvez vous rappeler que cette colonne commence à être un entier et maintenant a été optimisé dans UNINT32 TYPES. Par conséquent, convertissez-le en un type DateTime. Il va vraiment doubler la quantité de mémoire car le type DateTime est de 64 bits. Convertissez-la en une date de date précieuse car cela nous permet de mieux effectuer une analyse de la série chronologique. La fonction Pandas.Te_DateTime () peut nous aider à remplir ce commutateur, à utiliser ses paramètres de format pour stocker nos données de date dans AAAA-MM-DD. sept, choisissez le type lors de la lecture de données Maintenant, nous avons découvert comment réduire l'utilisation de la mémoire des cadres existants. En lisant la trame de données, ensuite dans ce processus dans ce processus pour réduire l'utilisation de la mémoire, nous avons compris le montant de la mémoire.moins la capacité de mémoire que chaque méthode d'optimisation peut être apportée. Mais comme nous l'avons mentionné plus tôt, nous avons tendance à avoir suffisamment de mémoire pour représenter toutes les valeurs de l'ensemble de données. Si nous ne pouvons même pas créer de cadres de données depuis le début, comment pouvons-nous appliquer une technologie d'économie de mémoire? Heureusement, nous pouvons spécifier le type de colonne optimal tout en lisant les données. Les fonctions pandas.read_csv () ont plusieurs paramètres différents pour nous faire faire cela. Le paramètre DTYPE accepte un dictionnaire nommé colonne (chaîne) comme une valeur de clé (clé) et l'objet de type numpy comme valeur. Tout d'abord, nous pouvons stocker le type final de chaque colonne d'un dictionnaire dans lequel la valeur de clé indique le nom de la colonne, supprimez d'abord la colonne Date, car la colonne Date nécessite les méthodes de manipulation différente. Maintenant, nous pouvons utiliser ce dictionnaire, plusieurs paramètres peuvent être utilisés pour lire la dateSous le bon type et juste quelques lignes de code: . . En optimisant ces colonnes, nous avons réduit les souvenirs de pandas de 861,6 Mo à 104,28 Mo - 88% de réduction! Huit, analyse concurrentielle de baseball Nous avons maintenant optimisé leurs données, nous pouvons effectuer une analyse. Commencez par commencer à comprendre la distribution de la date de ces jeux. Nous pouvons constater que la concurrence de baseball dimanche d'abord, mais les demiftanes au cours du siècle dernier sont devenues de plus en plus. Nous pouvons également voir clairement que la répartition de la journée du jeu a changé fondamentalement sans changement majeur de 50M à travers. Depuis les années 1940, le temps de la concurrence de baseball a plus long. Neuf, Résumé et suivant Nous avons appris que Pandas utilise différents types de données, puis nous utilisons des fourmis que cette éveil réduit la quantité de données de pandas diminuant progressivement par presque 90% et seulement un certain nombre de techniques simples utilisées: Convertissez des colonnes numériques en type Convertir la classification de catégorie .

Sujets

Catégories