cours
Tutoriel Python Pickle : Sérialisation des objets
Introduction à la sérialisation d'objets
Êtes-vous fatigué de réexécuter votre code Python à chaque fois que vous avez besoin d'accéder à une base de données, à une variable ou à un modèle d'apprentissage automatique créé précédemment ?
La sérialisation d'objets est peut-être la solution que vous recherchez.
Il s'agit du processus de stockage d'une structure de données en mémoire, de sorte que vous puissiez la charger ou la transmettre en cas de besoin sans perdre son état actuel.
Voici un schéma simple expliquant le fonctionnement de la sérialisation :
Image de l'auteur
En Python, nous travaillons avec des structures de données de haut niveau telles que les listes, les tuples et les ensembles. Cependant, lorsque nous voulons stocker ces objets en mémoire, ils doivent être convertis en une séquence d'octets que l'ordinateur peut comprendre. Ce processus est appelé sérialisation.
La prochaine fois que nous voudrons accéder à la même structure de données, cette séquence d'octets devra être reconvertie en objet de haut niveau dans le cadre d'un processus connu sous le nom de désérialisation.
Nous pouvons utiliser des formats tels que JSON, XML, HDF5 et Pickle pour la sérialisation. Dans ce tutoriel, nous allons découvrir la bibliothèque Pickle de Python pour la sérialisation. Nous allons couvrir ses utilisations et comprendre quand vous devriez choisir Pickle plutôt que d'autres formats de sérialisation.
Enfin, nous apprendrons à utiliser la bibliothèque Pickle Python pour sérialiser des listes, des dictionnaires, des cadres de données Pandas, des modèles d'apprentissage automatique, etc.
Pour exécuter facilement vous-même tous les exemples de code de ce tutoriel, vous pouvez créer gratuitement un classeur DataLab dans lequel Python est préinstallé et qui contient tous les exemples de code. Pour plus de pratique sur le chargement de fichiers Python, consultez cet exercice pratique de DataCamp.
Apprenez Python à partir de zéro
Pourquoi avons-nous besoin de la sérialisation des objets ?
Avant de commencer à utiliser Python Pickle, nous allons comprendre pourquoi la sérialisation des objets est si importante.
Vous vous demandez peut-être pourquoi nous ne pouvons pas simplement enregistrer les structures de données dans un fichier texte et y accéder à nouveau lorsque c'est nécessaire, au lieu de devoir les sérialiser.
Prenons un exemple simple pour comprendre les avantages de la sérialisation.
Voici un dictionnaire imbriqué contenant des informations sur les élèves telles que le nom, l'âge et le sexe :
students = {
'Student 1': {
'Name': "Alice", 'Age' :10, 'Grade':4,
},
'Student 2': {
'Name':'Bob', 'Age':11, 'Grade':5
},
'Student 3': {
'Name':'Elena', 'Age':14, 'Grade':8
}
}
Examinons le type de données de l'objet "étudiants" :
type(students)
dict
Maintenant que nous avons confirmé que l'objet élève est de type dictionnaire, nous allons l'écrire dans un fichier texte sans sérialisation :
with open('student_info.txt','w') as data:
data.write(str(students))
Notez que, comme nous ne pouvons écrire que des objets de type chaîne dans des fichiers texte, nous avons converti le dictionnaire en chaîne de caractères à l'aide de la fonction str(). Cela signifie que l'état d'origine de notre dictionnaire est perdu.
Lisons maintenant le dictionnaire, imprimons-le et vérifions à nouveau son type :
with open("student_info.txt", 'r') as f:
for students in f:
print(students)
type(students)
str
Le dictionnaire imbriqué est maintenant imprimé sous la forme d'une chaîne de caractères et renverra une erreur si nous essayons d'accéder à ses clés ou à ses valeurs.
C'est là que la sérialisation intervient.
Lorsqu'il s'agit de types de données plus complexes tels que les dictionnaires, les cadres de données et les listes imbriquées, la sérialisation permet à l'utilisateur de préserver l'état d'origine de l'objet sans perdre d'informations pertinentes.
Plus loin dans cet article, nous apprendrons à stocker ce même dictionnaire dans un fichier à l'aide de Pickle et à le désérialiser à l'aide de la bibliothèque. Vous pouvez en savoir plus sur la compréhension des dictionnaires Python dans un autre tutoriel.
Introduction à Pickle en Python
Le module Pickle de Python est un format populaire utilisé pour sérialiser et désérialiser les types de données. Ce format est natif de Python, ce qui signifie que les objets Pickle ne peuvent pas être chargés à l'aide d'un autre langage de programmation.
Pickle présente ses propres avantages et inconvénients par rapport aux autres formats de sérialisation.
Avantages de l'utilisation de Pickle pour sérialiser des objets
- Contrairement aux formats de sérialisation tels que JSON, qui ne peuvent pas gérer les tuples et les objets de type datetime, Pickle peut sérialiser presque tous les types de données intégrés Python couramment utilisés. Il conserve également l'état exact de l'objet, ce que JSON ne peut pas faire.
- Pickle est également un bon choix pour stocker des structures récursives, car il n'écrit un objet qu'une seule fois.
- Pickle permet une certaine flexibilité lors de la désérialisation des objets. Vous pouvez facilement enregistrer différentes variables dans un fichier Pickle et les charger à nouveau dans une autre session Python, récupérant ainsi vos données à l'identique sans avoir à modifier votre code.
Inconvénients de l'utilisation des cornichons
- Pickle n'est pas sûr car il peut exécuter des callables Python malveillants pour construire des objets. Lors de la désérialisation d'un objet, Pickle ne peut pas faire la différence entre un callable malveillant et un callable non malveillant. De ce fait, les utilisateurs peuvent finir par exécuter un code arbitraire pendant la désérialisation.
- Comme indiqué précédemment, Pickle est un module spécifique à Python, et il se peut que vous ayez du mal à désérialiser des objets picklés lorsque vous utilisez un autre langage.
- D'après de nombreux benchmarks, Pickle semble être plus lent et produit des valeurs sérialisées plus grandes que des formats tels que JSON et ApacheThrift.
Sauvegarde et chargement d'objets avec les fonctions Pickle Dump Python et Load
Pickle utilise les fonctions suivantes pour sérialiser et désérialiser les objets Python :
pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)
pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)
pickle.load(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)
pickle.loads(data, /, *, fix_imports=True, encoding=”ASCII”, errors=”strict”, buffers=None)
Les fonctions Pickle dump() et dumps() sont utilisées pour sérialiser un objet. La seule différence entre ces deux méthodes est que dump() écrit les données dans un fichier, alors que dumps() les représente sous la forme d'un objet de type octet.
De la même manière, load() lit des objets piochés dans un fichier, tandis que loads() les désérialise à partir d'un objet de type bytes.
Dans ce tutoriel, nous utiliserons les fonctions dump() et load() pour récupérer des objets Python dans un fichier et les décompiler.
Sérialisation des structures de données Python avec Pickle
Listes
Tout d'abord, créons une simple liste Python :
import pickle
student_names = ['Alice','Bob','Elena','Jane','Kyle']
Maintenant, ouvrons un fichier texte, écrivons-y la liste à l'aide de la fonction dumps() et fermons le fichier :
with open('student_file.pkl', 'wb') as f: # open a text file
pickle.dump(student_names, f) # serialize the list
Nous avons d'abord créé un fichier appelé "fichier_élève.pkl". L'extension ne doit pas nécessairement être .pkl. Vous pouvez lui donner le nom que vous souhaitez, et le fichier sera toujours créé. Cependant, il est conseillé d'utiliser l'extension .pkl pour vous rappeler qu'il s'agit d'un fichier Pickle.
Notez également que nous avons ouvert le fichier en mode "wb". Cela signifie que vous écrivez le fichier en mode binaire et que les données sont renvoyées dans un objet de type bytes.
Ensuite, nous utilisons la fonction dump() pour stocker la liste "noms_élèves" dans le fichier.
Enfin, vous pouvez fermer le fichier avec la ligne de code suivante :
f.close()
Maintenant, désérialisons le fichier et imprimons la liste :
with open('student_file.pkl', 'rb') as f:
student_names_loaded = pickle.load(f) # deserialize using load()
print(student_names_loaded) # print student names
Le résultat du code ci-dessus devrait être le suivant :
['Alice', 'Bob', 'Elena', 'Jane', 'Kyle']
Notez que pour désérialiser le fichier, nous devons utiliser le mode "rb" qui signifie read binary. Ensuite, nous décomposons l'objet à l'aide de la fonction load(), après quoi nous pouvons stocker les données dans une autre variable et les utiliser comme bon nous semble.
Vérifions maintenant le type de données de la liste que nous venons de dépiler :
type(student_names_loaded)
list
Excellent ! Nous avons préservé l'état et le type de données d'origine de cette liste.
Tableaux Numpy
Essayons maintenant de sérialiser et de désérialiser un type de données un peu plus complexe : les tableaux Numpy.
Commençons par créer un tableau de 10 par 10 :
import numpy as np
numpy_array = np.ones((10,10)) # 10x10 array
Ensuite, comme nous l'avons fait précédemment, appelons la fonction dump() pour sérialiser ce tableau dans un fichier :
with open('my_array.pkl','wb') as f:
pickle.dump(numpy_array, f)
Enfin, déconstruisons ce tableau et vérifions sa forme et son type de données pour nous assurer qu'il a conservé son état d'origine :
with open('my_array.pkl','rb') as f:
unpickled_array = pickle.load(f)
print('Array shape: '+str(unpickled_array.shape))
print('Data type: '+str(type(unpickled_array)))
Vous devriez obtenir le résultat suivant :
Array shape: (10, 10)
Data type: <class 'numpy.ndarray'>
L'objet non sérialisé est un tableau Numpy 10X10, qui a la même forme et le même type de données que l'objet que nous venons de sérialiser.
pandas DataFrames
Un cadre de données est un objet avec lequel les scientifiques travaillent quotidiennement. La façon la plus courante de charger et d'enregistrer un dataframe Pandas est de le lire et de l'écrire sous la forme d'un fichier csv. Pour en savoir plus sur l'importation de données, consultez notre tutoriel pandas read_csv().
Toutefois, ce processus est plus lent que la sérialisation et peut prendre beaucoup de temps si la base de données est volumineuse.
Comparons l'efficacité de l'enregistrement et du chargement d'un cadre de données pandas à l'aide de Pickle et de csv en comparant les temps respectifs.
Tout d'abord, créons un cadre de données pandas avec 100 000 lignes de données fictives :
import pandas as pd
import numpy as np
# Set random seed
np.random.seed(123)
data = {'Column1': np.random.randint(0, 10, size=100000),
'Column2': np.random.choice(['A', 'B', 'C'], size=100000),
'Column3': np.random.rand(100000)}
# Create Pandas dataframe
df = pd.DataFrame(data)
Calculons maintenant le temps nécessaire pour enregistrer ce cadre de données dans un fichier csv :
import time
start = time.time()
df.to_csv('pandas_dataframe.csv')
end = time.time()
print(end - start)
0.19349145889282227
Il nous a fallu 0,19 seconde pour enregistrer un cadre de données Pandas de trois lignes et 100 000 colonnes dans un fichier csv.
Voyons si l'utilisation de Pickle peut contribuer à améliorer les performances. La bibliothèque pandas dispose d'une méthode appelée to_pickle() qui nous permet de sérialiser les cadres de données dans des fichiers pickle en une seule ligne de code :
start = time.time()
df.to_pickle("my_pandas_dataframe.pkl")
end = time.time()
print(end - start)
0.0059659481048583984
Il ne nous a fallu que 5 millisecondes pour enregistrer le même cadre de données Pandas dans un fichier Pickle, ce qui représente une amélioration significative des performances par rapport à l'enregistrement au format csv.
Maintenant, lisons le fichier dans Pandas et voyons si le chargement d'un fichier Pickle offre des avantages en termes de performances par rapport à la simple lecture d'un fichier csv :
# Reading the csv file into Pandas:
start1 = time.time()
df_csv = pd.read_csv("my_pandas_dataframe.csv")
end1 = time.time()
print("Time taken to read the csv file: " + str(end1 - start1) + "\n")
# Reading the Pickle file into Pandas:
start2 = time.time()
df_pkl = pd.read_pickle("my_pandas_dataframe.pkl")
end2 = time.time()
print("Time taken to read the Pickle file: " + str(end2 - start2))
Le code ci-dessus devrait produire le résultat suivant :
Time taken to read the csv file: 0.00677490234375
Time taken to read the Pickle file: 0.0009608268737792969
Il a fallu 6 millisecondes pour lire le fichier csv dans Pandas, et seulement 0,9 millisecondes pour le lire dans Pickle.
Bien que cette différence puisse paraître mineure, la sérialisation de grands blocs de données Pandas à l'aide de Pickle permet de gagner un temps considérable. Pickle nous aidera également à préserver le type de données de chaque colonne dans tous les cas et occupera moins d'espace disque qu'un fichier csv.
Dictionnaires
Enfin, sérialisons le dictionnaire que nous avons écrit dans un fichier texte dans la première section du tutoriel :
students = {
'Student 1': {
'Name': "Alice", 'Age' :10, 'Grade':4,
},
'Student 2': {
'Name':'Bob', 'Age':11, 'Grade':5
},
'Student 3': {
'Name':'Elena', 'Age':14, 'Grade':8
}
}
Rappelez-vous que lorsque nous avons enregistré ce dictionnaire en tant que fichier texte, nous avons dû le convertir en chaîne de caractères et avons perdu son état d'origine.
Nous allons maintenant le sérialiser à l'aide de Pickle et le relire pour nous assurer qu'il contient toujours toutes les propriétés d'un dictionnaire Python :
# serialize the dictionary to a pickle file
with open("student_dict.pkl", "wb") as f:
pickle.dump(students, f)
# deserialize the dictionary and print it out
with open("student_dict.pkl", "rb") as f:
deserialized_dict = pickle.load(f)
print(deserialized_dict)
Vous devriez obtenir le résultat suivant :
{'Student 1': {'Name': 'Alice', 'Age': 10, 'Grade': 4}, 'Student 2': {'Name': 'Bob', 'Age': 11, 'Grade': 5}, 'Student 3': {'Name': 'Elena', 'Age': 14, 'Grade': 8}}
Vérifions maintenant le type de cette variable :
type(deserialized_dict)
dict
Essayons d'accéder à des informations sur le premier élève de ce dictionnaire :
print(
"The first student's name is "
+ deserialized_dict["Student 1"]["Name"]
+ " and she is "
+ (str(deserialized_dict["Student 1"]["Age"]))
+ " years old."
)
The first student's name is Alice and she is 10 years old.
Excellent ! Le dictionnaire a conservé toutes ses propriétés d'origine et peut être consulté comme il l'était avant la sérialisation. Consultez notre tutoriel sur la compréhension du dictionnaire Python pour en savoir plus.
Sérialisation des modèles d'apprentissage automatique avec Pickle
La formation d'un modèle d'apprentissage automatique est un processus qui prend du temps et qui peut durer des heures, voire des jours. Il n'est tout simplement pas possible d'entraîner à nouveau un algorithme à partir de zéro lorsque vous devez le réutiliser ou le transférer dans un environnement différent.
Si vous souhaitez en savoir plus sur les meilleures pratiques en matière de construction d'algorithmes d'apprentissage automatique, vous pouvez suivre notre cours Designing Machine Learning Workflows in Python ( Conception de flux d'apprentissage automatique en Python).
Pickle vous permet de sérialiser les modèles d'apprentissage automatique dans leur état actuel, ce qui permet de les réutiliser en cas de besoin.
Dans cette section, nous allons apprendre à sérialiser un modèle d'apprentissage automatique avec Pickle.
Pour ce faire, commençons par générer des données fictives et construisons un modèle de régression linéaire à l'aide de la bibliothèque Scikit-Learn :
from sklearn.linear_model import LinearRegression
from sklearn.datasets import make_regression
# generate regression dataset
X, y = make_regression(n_samples=100, n_features=3, noise=0.1, random_state=1)
# train regression model
linear_model = LinearRegression()
linear_model.fit(X, y)
Imprimons maintenant quelques paramètres sommaires du modèle :
# summary of the model
print('Model intercept :', linear_model.intercept_)
print('Model coefficients : ', linear_model.coef_)
print('Model score : ', linear_model.score(X, y))
Model intercept : -0.010109549594702116
Model coefficients : [44.18793068 98.97389468 58.17121618]
Model score : 0.9999993081899219
Nous pouvons ensuite sérialiser ce modèle à l'aide de la fonction dump() de Pickle :
with open("linear_regression.pkl", "wb") as f:
pickle.dump(linear_model, f)
Le modèle est maintenant enregistré sous la forme d'un fichier Pickle. Désérialisons-le à l'aide de la fonction load() :
with open("linear_regression.pkl", "rb") as f:
unpickled_linear_model = pickle.load(f)
Le modèle sérialisé est maintenant chargé et enregistré dans la variable "unpickled_linear_model". Vérifions les paramètres de ce modèle pour nous assurer qu'il est identique à celui que nous avons créé initialement :
# summary of the model
print('Model intercept :', unpickled_linear_model.intercept_)
print('Model coefficients : ', unpickled_linear_model.coef_)
print('Model score : ', unpickled_linear_model.score(X, y))
Vous devriez obtenir le résultat suivant :
Model intercept : -0.010109549594702116
Model coefficients : [44.18793068 98.97389468 58.17121618]
Model score : 0.9999993081899219
Excellent ! Les paramètres du modèle que nous venons de dépiler sont les mêmes que ceux du modèle que nous avons créé initialement.
Nous pouvons maintenant utiliser ce modèle pour faire des prédictions sur un ensemble de données de test, nous entraîner dessus ou le transférer dans un environnement différent.
Augmenter les performances de Python Pickle pour les gros objets
Pickle est un format de sérialisation efficace qui s'est souvent avéré plus rapide que JSON, XML et HDF5 dans divers benchmarks.
Cependant, lorsqu'il s'agit de structures de données extrêmement volumineuses ou d'énormes modèles d'apprentissage automatique, Pickle peut ralentir considérablement et la sérialisation peut devenir un goulot d'étranglement dans votre flux de travail.
Voici quelques moyens de réduire le temps nécessaire à l'enregistrement et au chargement des fichiers Pickle :
Utilisez l'argument "PROTOCOL".
Le protocole par défaut utilisé lors de l'enregistrement et du chargement des fichiers Pickle est actuellement le protocole 4, qui est le plus compatible avec les différentes versions de Python.
Cependant, si vous souhaitez accélérer votre flux de travail, vous pouvez utiliser l'argument HIGHEST_PROTOCOL qui est le protocole Pickle le plus rapide.
Pour comparer la différence de performance entre le protocole Pickle le plus compatible et le protocole par défaut, sérialisons d'abord un cadre de données Pandas en utilisant le protocole par défaut. Notez qu'il s'agit de la version du protocole que Pickle utilise si aucun protocole spécifique n'est explicitement indiqué :
import pickle
import time
import numpy as np
# Set random seed
np.random.seed(100)
data = {'Column1': np.random.randint(0, 10, size=100000),
'Column2': np.random.choice(['A', 'B', 'C'], size=100000),
'Column3': np.random.rand(100000)}
# serialize to a file
start = time.time()
with open("df1.pkl", "wb") as f:
pickle.dump(data, f)
end = time.time()
print(end - start)
0.006001710891723633
Il nous a fallu environ 6 millisecondes pour sérialiser la base de données en utilisant le protocole par défaut de Pickle.
Maintenant, nous allons décaper la base de données en utilisant le protocole le plus élevé :
start = time.time()
with open("df2.pkl", "wb") as f:
pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL)
end = time.time()
print(end - start)
0.0030384063720703125
Avec le protocole le plus élevé, nous avons réussi à sérialiser le cadre de données en deux fois moins de temps.
Utilisez "cPickle" au lieu de "Pickle".
Le module "cPickle" est une version plus rapide de "Pickle" écrite en C. Il est donc plus rapide que la bibliothèque "Pickle" qui est implémentée uniquement en Python.
Notez que dans Python3, "cPickle" a été renommé en "_pickle", qui est la bibliothèque que nous allons importer.
import _pickle as cPickle
start = time.time()
with open("df3.pkl", "wb") as f:
cPickle.dump(data, f)
end = time.time()
print(end-start)
0.004027366638183594
La sérialisation avec "cPickle" a pris environ 4 millisecondes, ce qui représente une amélioration substantielle par rapport au module Python "Pickle".
Ne sérialisez que ce dont vous avez besoin
Même avec des solutions de contournement pour accélérer la sérialisation, le processus peut encore être très lent pour les objets de grande taille.
Pour améliorer les performances, vous pouvez décomposer la structure de données et ne sérialiser que les sous-ensembles nécessaires.
Lorsque vous travaillez avec des dictionnaires, par exemple, vous pouvez spécifier des paires clé-valeur auxquelles vous souhaitez accéder à nouveau. Réduisez la taille du dictionnaire avant de le sérialiser, car cela réduira la complexité de l'objet et accélérera considérablement le processus.
Sérialisation avec Pickle en Python : Prochaines étapes
Félicitations ! Vous avez appris un grand nombre de sujets liés à la sérialisation en Python et à l'utilisation de la bibliothèque Pickle.
Vous devriez maintenant avoir une bonne compréhension de ce qu'est la sérialisation, comment utiliser Pickle pour sérialiser des structures de données Python, et comment optimiser les performances de Pickle en utilisant différents arguments et modules.
Voici quelques mesures que vous pouvez prendre pour améliorer votre compréhension de la sérialisation et l'exploiter pour améliorer vos flux de travail en science des données :
- Découvrez les nouveaux formats de sérialisation. Bien que nous n'ayons abordé que le module Pickle dans ce tutoriel, ce n'est pas nécessairement le meilleur format de sérialisation à utiliser dans tous les cas de figure. Il est utile de se familiariser avec d'autres formats tels que JSON, XML et HDF5, afin de savoir lequel choisir en fonction des différents cas d'utilisation.
- Essayez vous-même. Appliquez les concepts enseignés dans ce tutoriel à vos flux de travail en science des données. La prochaine fois que vous créerez une nouvelle structure de données ou que vous stockerez le résultat d'un calcul dans une variable, sérialisez-la pour une utilisation ultérieure au lieu d'exécuter tout votre code encore et encore.
- Suivez un cours en ligne. Pour optimiser vos flux de travail en science des données et exécuter efficacement des tâches telles que la sérialisation, il est impératif de bien comprendre les structures de données et les objets Python. Pour y parvenir, vous pouvez suivre notre cours Data Types for Data Science in Python.
En savoir plus sur Python et l'apprentissage automatique
cours
Machine Learning with Tree-Based Models in Python
cours
Unsupervised Learning in Python
blog
Les 20 meilleures questions d'entretien pour les flocons de neige, à tous les niveaux

Nisha Arya Ahmed
20 min
blog
Q2 2023 DataCamp Donates Digest
blog
Célébration de Saghar Hazinyar : Une boursière de DataCamp Donates et une diplômée de Code to Inspire

Fereshteh Forough
4 min
blog
2022-2023 Rapport annuel DataCamp Classrooms
blog