curso
Tutorial do Python Pickle: Serialização de objetos
A serialização é uma ótima coisa para você saber. Ele permite que você preserve o estado dos seus dados ou modelos, evitando a necessidade de reprocessar ou treinar novamente do zero.
Aqui, explorarei o conhecido módulo Python Pickle. Ao final, você saberá como serializar e desserializar estruturas de dados comuns, como listas e dicionários, e saberá como usar diferentes técnicas de otimização de desempenho.
Também recomendo nosso curso Projetando fluxos de trabalho de aprendizado de máquina em Python como a próxima etapa, em que você pode aprender a serializar e conteinerizar modelos de ML para produção.
Introdução à serialização de objetos
Você está cansado de executar novamente seu código Python toda vez que precisa acessar um quadro de dados, uma variável ou um modelo de aprendizado de máquina criado anteriormente?
A serialização de objetos pode ser a solução que você está procurando.
É o processo de armazenar uma estrutura de dados na memória para que você possa carregá-la ou transmiti-la quando necessário, sem perder seu estado atual.
Aqui está um diagrama simples que explica como a serialização funciona:
Imagem do autor
Em Python, trabalhamos com estruturas de dados de alto nível, como listas, tuplas e conjuntos. No entanto, quando queremos armazenar esses objetos na memória, eles precisam ser convertidos em uma sequência de bytes que o computador possa entender. Esse processo é chamado de serialização.
Na próxima vez que quisermos acessar a mesma estrutura de dados, essa sequência de bytes deverá ser convertida novamente no objeto de alto nível em um processo conhecido como desserialização.
Podemos usar formatos como JSON, XML, HDF5 e Pickle para serialização. Neste tutorial, aprenderemos sobre a biblioteca Python Pickle para serialização. Abordaremos seus usos e entenderemos quando você deve escolher o Pickle em vez de outros formatos de serialização.
Por fim, aprenderemos a usar a biblioteca Pickle Python para serializar listas, dicionários, quadros de dados do Pandas, modelos de aprendizado de máquina e muito mais.
Para executar facilmente todos os exemplos de código deste tutorial, você pode criar gratuitamente uma pasta de trabalho do DataLab que tenha o Python pré-instalado e contenha todos os exemplos de código. Para praticar mais o carregamento de arquivos em conserva do Python, confira este exercício prático do DataCamp.
Aprenda Python do zero
Por que precisamos da serialização de objetos?
Antes de começarmos a usar o Python Pickle, vamos entender por que a serialização de objetos é tão importante.
Você deve estar se perguntando por que não podemos simplesmente salvar as estruturas de dados em um arquivo de texto e acessá-las novamente quando necessário, em vez de precisar serializá-las.
Vamos ver um exemplo simples para que você entenda os benefícios da serialização.
Aqui está um dicionário aninhado que contém informações sobre o aluno, como nome, idade e gênero:
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
}
}
Vamos examinar o tipo de dados do objeto "students":
type(students)
dict
Agora que confirmamos que o objeto do aluno é um tipo de dicionário, vamos continuar a gravá-lo em um arquivo de texto sem serialização:
with open('student_info.txt','w') as data:
data.write(str(students))
Observe que, como só podemos gravar objetos de cadeia de caracteres em arquivos de texto, convertemos o dicionário em uma cadeia de caracteres usando a função str(). Isso significa que o estado original do nosso dicionário é perdido.
Agora, vamos ler o dicionário, imprimi-lo e verificar seu tipo novamente:
with open("student_info.txt", 'r') as f:
for students in f:
print(students)
type(students)
str
O dicionário aninhado agora está sendo impresso como uma string e retornará um erro quando tentarmos acessar suas chaves ou valores.
É aqui que entra a serialização.
Ao lidar com tipos de dados mais complexos, como dicionários, quadros de dados e listas aninhadas, a serialização permite que o usuário preserve o estado original do objeto sem perder nenhuma informação relevante.
Mais adiante neste artigo, aprenderemos a armazenar esse mesmo dicionário em um arquivo usando o Pickle e a desserializá-lo usando a biblioteca. Você pode ler mais sobre a compreensão do dicionário Python em um tutorial separado.
Introdução ao Pickle em Python
O módulo Pickle do Python é um formato popular usado para serializar e desserializar tipos de dados. Esse formato é nativo do Python, o que significa que os objetos Pickle não podem ser carregados usando qualquer outra linguagem de programação.
O Pickle tem suas próprias vantagens e desvantagens em comparação com outros formatos de serialização.
Vantagens de usar o Pickle para serializar objetos
- Diferentemente dos formatos de serialização como JSON, que não podem lidar com tuplas e objetos de data e hora, o Pickle pode serializar quase todos os tipos de dados internos do Python comumente usados. Ele também retém o estado exato do objeto, o que o JSON não pode fazer.
- O Pickle também é uma boa opção para armazenar estruturas recursivas, pois ele grava um objeto apenas uma vez.
- O Pickle permite flexibilidade ao desserializar objetos. Você pode salvar facilmente diferentes variáveis em um arquivo Pickle e carregá-las novamente em uma sessão diferente do Python, recuperando os dados exatamente como estavam, sem precisar editar o código.
Desvantagens do uso do Pickle
- O Pickle não é seguro porque pode executar callables maliciosos do Python para construir objetos. Ao desserializar um objeto, o Pickle não consegue distinguir entre um callable malicioso e um não malicioso. Devido a isso, os usuários podem acabar executando código arbitrário durante a desserialização.
- Conforme mencionado anteriormente, o Pickle é um módulo específico do Python, e você pode ter dificuldades para desserializar objetos decapados ao usar uma linguagem diferente.
- De acordo com vários benchmarks, o Pickle parece ser mais lento e produz valores serializados maiores do que formatos como JSON e ApacheThrift.
Salvando e carregando objetos com a função Pickle Dump Python e a função Load
O Pickle usa as seguintes funções para serializar e desserializar objetos 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)
As funções Pickle dump()
e dumps()
são usadas para serializar um objeto. A única diferença entre eles é que dump()
grava os dados em um arquivo, enquanto dumps()
os representa como um objeto de byte.
Da mesma forma, load()
lê objetos decapados de um arquivo, enquanto loads()
os desserializa de um objeto do tipo bytes.
Neste tutorial, usaremos as funções dump()
e load()
para coletar objetos do Python em um arquivo e desacoplá-los.
Serialização de estruturas de dados Python com Pickle
Listas
Primeiro, vamos criar uma lista Python simples:
import pickle
student_names = ['Alice','Bob','Elena','Jane','Kyle']
Agora, vamos abrir um arquivo de texto, gravar a lista nele usando a função dumps() e fechar o arquivo:
with open('student_file.pkl', 'wb') as f: # open a text file
pickle.dump(student_names, f) # serialize the list
Primeiro, criamos um arquivo chamado "student_file.pkl". A extensão não precisa ser .pkl. Você pode dar o nome que quiser, e o arquivo ainda será criado. No entanto, é uma boa prática usar a extensão .pkl para que você seja lembrado de que se trata de um arquivo Pickle.
Além disso, observe que abrimos o arquivo no modo wb
. Isso significa que você está gravando o arquivo em modo binário para que os dados sejam retornados em um objeto de bytes.
Em seguida, usamos a função dump()
para armazenar a lista student_names
no arquivo.
Por fim, você pode fechar o arquivo com a seguinte linha de código:
f.close()
Agora, vamos desserializar o arquivo e imprimir a lista:
with open('student_file.pkl', 'rb') as f:
student_names_loaded = pickle.load(f) # deserialize using load()
print(student_names_loaded) # print student names
O resultado do código acima deve ser o seguinte:
['Alice', 'Bob', 'Elena', 'Jane', 'Kyle']
Observe que, para desserializar o arquivo, precisamos usar o modo rb
, que significa read binary (ler binário). Em seguida, desempacotamos o objeto usando a função load()
, após o que podemos armazenar os dados em uma variável diferente e usá-los como acharmos adequado.
Agora, vamos verificar o tipo de dados da lista que acabamos de remover:
type(student_names_loaded)
list
Ótimo! Preservamos o estado original e o tipo de dados dessa lista.
Matrizes Numpy
Agora, vamos tentar serializar e desserializar um tipo de dados um pouco mais complexo: matrizes Numpy.
Primeiro, vamos criar uma matriz de 10 por 10 de unidades:
import numpy as np
numpy_array = np.ones((10,10)) # 10x10 array
Em seguida, assim como fizemos antes, vamos chamar a função dump()
para serializar essa matriz em um arquivo:
with open('my_array.pkl','wb') as f:
pickle.dump(numpy_array, f)
Por fim, vamos desfazer esse array e verificar sua forma e tipo de dados para garantir que ele tenha mantido seu estado original:
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)))
Você deve obter o seguinte resultado:
Array shape: (10, 10)
Data type: <class 'numpy.ndarray'>
O objeto não picotado é uma matriz Numpy 10X10, que tem a mesma forma e o mesmo tipo de dados que o objeto que acabamos de serializar.
pandas DataFrames
Um quadro de dados é um objeto com o qual os cientistas de dados trabalham diariamente. A maneira mais comum de carregar e salvar um Pandas DataFrame é ler e gravar como um arquivo CSV. Saiba mais sobre a importação de dados em nosso tutorial pandas read_csv().
No entanto, esse processo é mais lento do que a serialização e pode se tornar extremamente demorado se o quadro de dados for grande.
Vamos comparar a eficiência de salvar e carregar um dataframe do pandas usando o Pickle e o CSV, comparando o tempo gasto.
Primeiro, vamos criar um dataframe do pandas com 100.000 linhas de dados falsos:
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)
Agora, vamos calcular o tempo necessário para salvar esse dataframe como um arquivo csv:
import time
start = time.time()
df.to_csv('pandas_dataframe.csv')
end = time.time()
print(end - start)
0.19349145889282227
Levamos 0,19 segundos para salvar um dataframe do Pandas com três linhas e 100.000 colunas em um arquivo csv.
Vamos ver se o uso do Pickle pode ajudar a melhorar o desempenho. A biblioteca pandas tem um método chamado to_pickle()
que nos permite serializar dataframes em arquivos pickle com apenas uma linha de código:
start = time.time()
df.to_pickle("my_pandas_dataframe.pkl")
end = time.time()
print(end - start)
0.0059659481048583984
Levamos apenas 5 milissegundos para salvar o mesmo Pandas DataFrame em um arquivo Pickle, o que representa uma melhoria significativa de desempenho quando comparado a salvá-lo como um csv.
Agora, vamos ler o arquivo de volta para o Pandas e ver se o carregamento de um arquivo Pickle oferece alguma vantagem de desempenho em comparação com a simples leitura de um arquivo 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))
O código acima deve gerar o seguinte resultado:
Time taken to read the csv file: 0.00677490234375
Time taken to read the Pickle file: 0.0009608268737792969
Foram necessários 6 milissegundos para ler o arquivo CSV no Pandas e apenas 0,9 milissegundos para que pudéssemos lê-lo no Pickle.
Embora essa diferença possa parecer pequena, a serialização de grandes quadros de dados do Pandas com o Pickle pode resultar em uma economia de tempo considerável. O Pickle também nos ajudará a preservar o tipo de dados de cada coluna em todos os casos e ocupará menos espaço em disco do que um arquivo CSV.
Dicionários
Por fim, vamos serializar o dicionário que escrevemos em um arquivo de texto na primeira seção do tutorial:
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
}
}
Lembre-se de que, quando salvamos esse dicionário como um arquivo de texto, tivemos de convertê-lo em uma cadeia de caracteres e perdemos seu estado original.
Vamos agora serializá-lo usando o Pickle e lê-lo de volta para garantir que ele ainda contenha todas as propriedades de um dicionário 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)
Você deve obter o seguinte resultado:
{'Student 1': {'Name': 'Alice', 'Age': 10, 'Grade': 4}, 'Student 2': {'Name': 'Bob', 'Age': 11, 'Grade': 5}, 'Student 3': {'Name': 'Elena', 'Age': 14, 'Grade': 8}}
Vamos agora verificar o tipo dessa variável:
type(deserialized_dict)
dict
Vamos tentar acessar algumas informações sobre o primeiro aluno nesse dicionário:
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.
Ótimo! O dicionário manteve todas as suas propriedades originais e pode ser acessado exatamente como era antes da serialização. Confira nosso tutorial de compreensão de dicionário Python para saber mais.
Serialização de modelos de aprendizado de máquina com Pickle
O treinamento de um modelo de aprendizado de máquina é um processo demorado que pode levar horas e, às vezes, até mesmo muitos dias. Simplesmente não é viável treinar novamente um algoritmo do zero quando você precisa reutilizá-lo ou transferi-lo para um ambiente diferente.
Se quiser saber mais sobre as práticas recomendadas ao criar algoritmos de aprendizado de máquina, você pode fazer nosso curso Designing Machine Learning Workflows in Python.
O Pickle permite que você serialize modelos de aprendizado de máquina em seu estado atual, possibilitando usá-los novamente quando necessário.
Nesta seção, aprenderemos a serializar um modelo de aprendizado de máquina com o Pickle.
Para fazer isso, vamos primeiro gerar alguns dados falsos e criar um modelo de regressão linear com a biblioteca 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)
Agora, vamos imprimir alguns parâmetros resumidos do modelo:
# 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
Em seguida, podemos serializar esse modelo usando a função dump()
do Pickle:
with open("linear_regression.pkl", "wb") as f:
pickle.dump(linear_model, f)
O modelo agora é salvo como um arquivo Pickle. Vamos desserializá-lo usando a função load()
:
with open("linear_regression.pkl", "rb") as f:
unpickled_linear_model = pickle.load(f)
O modelo serializado agora é carregado e salvo na variável unpickled_linear_model
. Vamos verificar os parâmetros desse modelo para garantir que ele seja igual ao que criamos inicialmente:
# 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))
Você deve obter o seguinte resultado:
Model intercept : -0.010109549594702116
Model coefficients : [44.18793068 98.97389468 58.17121618]
Model score : 0.9999993081899219
Ótimo! Os parâmetros do modelo que acabamos de remover são os mesmos do modelo que criamos inicialmente.
Agora, podemos continuar a usar esse modelo para fazer previsões em um conjunto de dados de teste, treinar com base nele ou transferi-lo para um ambiente diferente.
Aumentando o desempenho do Python Pickle para objetos grandes
O Pickle é um formato de serialização eficiente que muitas vezes se mostrou mais rápido do que JSON, XML e HDF5 em vários benchmarks.
No entanto, ao lidar com estruturas de dados extremamente grandes ou modelos enormes de aprendizado de máquina, o Pickle pode ficar consideravelmente mais lento, e a serialização pode se tornar um gargalo no seu fluxo de trabalho.
Aqui estão algumas maneiras de você reduzir o tempo necessário para salvar e carregar arquivos Pickle:
Use o argumento PROTOCOL
O protocolo padrão usado ao salvar e carregar arquivos Pickle é atualmente o 4, que é o protocolo mais compatível com diferentes versões do Python.
No entanto, se quiser acelerar seu fluxo de trabalho, você pode usar o argumento HIGHEST_PROTOCOL
, que é o protocolo mais rápido disponível do Pickle.
Para comparar a diferença de desempenho entre o protocolo mais compatível do Pickle e o protocolo padrão, vamos primeiro serializar um DataFrame do Pandas usando o protocolo padrão. Observe que essa é a versão do protocolo que o Pickle usa se nenhum protocolo específico for explicitamente indicado:
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
Levamos cerca de 6 milissegundos para serializar o DataFrame usando o protocolo padrão do Pickle.
Agora, vamos selecionar o DataFrame usando o protocolo mais alto:
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
Com o protocolo mais alto, conseguimos serializar o DataFrame na metade do tempo.
Use o cPickle em vez do Pickle
O módulo cPickle
é uma versão mais rápida do Pickle escrita em C. Isso o torna mais rápido do que a biblioteca Pickle, que é implementada exclusivamente em Python.
Observe que, no Python3, cPickle
foi renomeado para _pickle
, que é a biblioteca que estaremos importando.
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
A serialização com cPickle
levou aproximadamente 4 milissegundos, o que representa uma melhoria substancial em relação ao módulo Pickle Python.
Serialize apenas o que você precisa
Mesmo com soluções alternativas para tornar a serialização mais rápida, o processo ainda pode ser muito lento para objetos grandes.
Para melhorar o desempenho, você pode dividir a estrutura de dados e serializar apenas os subconjuntos necessários.
Ao trabalhar com dicionários, por exemplo, você pode especificar pares de valores-chave que deseja acessar novamente. Reduza o tamanho do dicionário antes de serializá-lo, pois isso reduzirá a complexidade do objeto e acelerará significativamente o processo.
Serialização com Pickle em Python: Próximas etapas
Parabéns! Você aprendeu uma ampla gama de tópicos relacionados à serialização em Python e ao uso da biblioteca Pickle.
Agora você deve ter uma sólida compreensão do que é serialização, como usar o Pickle para serializar estruturas de dados Python e como otimizar o desempenho do Pickle usando diferentes argumentos e módulos.
Aqui estão algumas etapas que você pode seguir para melhorar sua compreensão da serialização e aproveitá-la para aprimorar seus fluxos de trabalho de ciência de dados:
- Saiba mais sobre os novos formatos de serialização. Embora tenhamos abordado apenas o módulo Pickle neste tutorial, ele não é necessariamente o melhor formato de serialização a ser usado em todos os cenários. Vale a pena aprender sobre outros formatos, como JSON, XML e HDF5, para que você saiba qual deles escolher para diferentes casos de uso.
- Experimente você mesmo. Aplique os conceitos ensinados neste tutorial aos seus fluxos de trabalho de ciência de dados. Na próxima vez que você criar uma nova estrutura de dados ou armazenar o resultado de um cálculo em uma variável, serialize-a para uso posterior, em vez de executar todo o seu código repetidamente.
- Faça um curso on-line. Para otimizar seus fluxos de trabalho de ciência de dados e executar tarefas como a serialização de forma eficiente, é imprescindível que você tenha um sólido conhecimento das estruturas de dados e objetos do Python. Para isso, você pode fazer nosso curso Data Types for Data Science in Python.

Natassha é uma consultora de dados que trabalha na interseção da ciência de dados e do marketing. Ela acredita que os dados, quando usados com sabedoria, podem inspirar um enorme crescimento para indivíduos e organizações. Como uma profissional de dados autodidata, Natassha adora escrever artigos que ajudem outros aspirantes à ciência de dados a entrar no setor. Seus artigos em seu blog pessoal, bem como em publicações externas, obtêm uma média de 200 mil visualizações mensais.
Saiba mais sobre Python e aprendizado de máquina
curso
Aprendizado de máquina com modelos baseados em árvores em Python
curso