Skip to content

Tutorial Python Pickle: Serialização de Objetos

    python pickle

    Introdução à Serialização de Objetos

    Você já se cansou de ter que rodar seu código Python toda vez que precisa acessar um dataframe, variável ou modelo de aprendizado de máquina criado anteriormente?

    A serialização de objetos pode ser a solução que você procura.

    Ela é 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.

    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 em que quisermos acessar a mesma estrutura de dados, essa sequência de bytes deve ser convertida de volta ao 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 Pickle do Python para serialização. Abordaremos seus usos e entenderemos quando você deve escolher o Pickle em relação a outros formatos de serialização.

    Por fim, aprenderemos como usar a biblioteca Pickle do Python para serializar listas, dicionários, dataframes Pandas, modelos de aprendizado de máquina e muito mais.

    Por que Precisamos de Serialização de Objetos?

    Antes de começarmos com o Pickle em Python, vamos entender por que a serialização de objetos é tão importante.

    Você pode estar se perguntando por que não podemos simplesmente salvar estruturas de dados em um arquivo de texto e acessá-las quando necessário, em vez de ter que serializá-las.

    Vamos passar por um exemplo simples para entender os benefícios da serialização.

    Aqui está um dicionário aninhado contendo informações de estudantes, como nome, idade e gênero:

    estudantes = {
        'Estudante 1': {
            'Nome': "Alice", 'Idade': 10, 'Nota': 4,
        },
        'Estudante 2': {
            'Nome': 'Bob', 'Idade': 11, 'Nota': 5
        },
        'Estudante 3': {
            'Nome': 'Elena', 'Idade': 14, 'Nota': 8
        }
    }

    Vamos verificar o tipo de dados do objeto “estudantes”:

    type(estudantes)

    Agora que confirmamos que o objeto “estudantes” é do tipo dicionário, vamos prosseguir e gravá-lo em um arquivo de texto sem serialização:

    with open('informacoes_estudantes.txt', 'w') as arquivo:
        arquivo.write(str(estudantes))

    Observe que, como só podemos escrever objetos de string em arquivos de texto, convertemos o dicionário em uma string 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("informacoes_estudantes.txt", 'r') as arquivo:
        for linha in arquivo:
            print(linha)
    
    type(estudantes)

    O dicionário aninhado agora está sendo impresso como uma string e gerará um erro quando tentarmos acessar suas chaves ou valores.

    É aqui que a serialização se torna útil.

    Ao lidar com tipos de dados mais complexos, como dicionários, dataframes e listas aninhadas, a serialização permite ao usuário preservar o estado original do objeto sem perder informações relevantes.

    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 de dicionários em 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. Este formato é nativo do Python, o que significa que objetos Pickle não podem ser carregados por nenhuma 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

    • Ao contrário de formatos de serialização como JSON, que não podem lidar com tuplas e objetos datetime, o Pickle pode serializar quase todos os tipos de dados Python embutidos comumente usados. Além disso, ele mantém o estado exato do objeto, o que o JSON não pode fazer.
    • O Pickle é uma boa escolha ao armazenar estruturas recursivas, pois escreve o objeto apenas uma vez.
    • O Pickle permite flexibilidade ao desserializar objetos. Você pode facilmente salvar diferentes variáveis em um arquivo Pickle e carregá-las novamente em uma sessão Python diferente, recuperando seus dados exatamente da mesma forma, sem precisar editar seu código.

    Desvantagens de usar o Pickle

    • O Pickle não é seguro, porque pode executar chamadas Python maliciosas para construir objetos. Ao desserializar um objeto, o Pickle não pode distinguir entre um chamável malicioso e um não malicioso. Devido a isso, os usuários podem acabar executando código arbitrário durante a desserialização.
    • Como mencionado anteriormente, o Pickle é um módulo específico do Python, e você pode ter dificuldades para desserializar objetos Pickle ao usar uma linguagem diferente.
    • De acordo com diversos benchmarks, o Pickle parece ser mais lento e produz valores serializados maiores do que formatos como JSON e Apache Thrift.

    Salvando e Carregando Objetos

    com as Funções Dump e Load do Pickle em Python

    O Pickle utiliza as seguintes funções para serializar e desserializar objetos Python:

    • pickle.dump(objeto, arquivo, protocolo=None, *, fix_imports=True, buffer_callback=None)
    • pickle.dumps(objeto, protocolo=None, *, fix_imports=True, buffer_callback=None)
    • pickle.load(arquivo, *, fix_imports=True, encoding=’ASCII’, errors=’strict’, buffers=None)
    • pickle.loads(dados, /, *, fix_imports=True, encoding=”ASCII”, errors=”strict”, buffers=None)

    As funções dump() e dumps() do Pickle são usadas para serializar um objeto. A única diferença entre elas é que dump() escreve os dados em um arquivo, enquanto dumps() os representa como um objeto de bytes.

    Da mesma forma, load() lê objetos serializados de um arquivo, enquanto loads() desserializa objetos de um objeto do tipo bytes.

    Neste tutorial, usaremos as funções dump() e load() para serializar objetos Python em um arquivo Pickle e desserializá-los posteriormente.

    Serialização de Estruturas de Dados Python com Pickle

    Listas

    Primeiro, vamos criar uma lista Python simples:

    import pickle 
    
    nomes_estudantes = ['Alice', 'Bob', 'Elena', 'Jane', 'Kyle']

    Agora, vamos abrir um arquivo de texto, escrever a lista nele usando a função dumps() e fechar o arquivo:

    with open('arquivo_estudantes.pkl', 'wb') as arquivo:
        pickle.dump(nomes_estudantes, arquivo) # serializa a lista

    Primeiro, criamos um arquivo chamado “arquivo_estudantes.pkl”. A extensão não precisa ser .pkl. Você pode escolher qualquer nome, e o arquivo ainda será criado. No entanto, é uma boa prática usar a extensão .pkl para lembrá-lo de que este é um arquivo Pickle.

    Também observe que abrimos o arquivo no modo “wb”, o que significa que estamos escrevendo o arquivo no modo binário para que os dados sejam retornados como um objeto de bytes.

    Em seguida, usamos a função dump() para armazenar a lista de “nomes_estudantes” no arquivo.

    Finalmente, você pode fechar o arquivo com a seguinte linha de código:

    arquivo.close()

    Agora, vamos desserializar o arquivo e imprimir a lista:

    with open('arquivo_estudantes.pkl', 'rb') as arquivo:
        nomes_estudantes_carregados = pickle.load(arquivo) # desserializa usando load()
        print(nomes_estudantes_carregados) # imprime os nomes dos estudantes

    A saída do código acima deve ser a seguinte:

    ['Alice', 'Bob', 'Elena', 'Jane', 'Kyle']

    Observe que, para desserializar o arquivo, precisamos usar o modo “rb”, que significa ler em binário. Em seguida, desserializamos o objeto usando a função load(), após o qual podemos armazenar os dados em uma variável diferente e usá-los como desejado.

    Agora, vamos verificar o tipo de dados da lista que acabamos de desserializar:

    type(nomes_estudantes_carregados)

    Ótimo! Preservamos o estado original e o tipo de dados desta lista.

    Arrays Numpy

    Agora, vamos tentar serializar e desserializar um tipo de dado ligeiramente mais complexo – arrays Numpy.

    Primeiro, vamos criar um array de 10 por 10 de uns:

    import numpy as np
    
    array_numpy = np.ones((10, 10)) # array de 10x10

    Em seguida, da mesma forma que fizemos antes, vamos chamar a função dump() para serializar este array em um arquivo:

    with open('meu_array.pkl','wb') as arquivo:
        pickle.dump(array_numpy, arquivo)

    Finalmente, vamos desserializar este array e verificar sua forma e tipo de dados para garantir que ele manteve seu estado original:

    with open('meu_array.pkl','rb') as arquivo:
        array_desterializado = pickle.load(arquivo)
        print('Forma do array: '+str(array_desterializado.shape))
        print('Tipo de dados: '+str(type(array_desterializado)))

    A saída deve ser a seguinte:

    Forma do array: (10, 10)
    Tipo de dados: <class 'numpy.ndarray'>

    O objeto desserializado é um array Numpy 10×10, que possui a mesma forma e tipo de dados que o objeto que serializamos.

    Dataframes Pandas

    Um dataframe é um objeto com o qual os cientistas de dados trabalham diariamente. A forma mais popular de carregar e salvar um dataframe Pandas é lê-lo e escrevê-lo 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 dataframe for grande.

    Vamos contrastar a eficiência de salvar e carregar um dataframe Pandas usando o Pickle em relação a um arquivo CSV, comparando o tempo necessário em cada caso.

    Primeiro, vamos criar um dataframe Pandas com 100.000 linhas de dados fictícios:

    import pandas as pd
    import numpy as np
    
    # Configurando uma semente aleatória
    np.random.seed(123)
    
    dados = {'Coluna1': np.random.randint(0, 10, size=100000),
            'Coluna2': np.random.choice(['A', 'B', 'C'], size=100000),
            'Coluna3': np.random.rand(100000)}
    
    # Criando o dataframe Pandas
    df = pd.DataFrame(dados)

    Agora, vamos calcular o tempo necessário para salvar este dataframe como um arquivo CSV:

    import time
    
    inicio
    
     = time.time()
    
    df.to_csv('dataframe_pandas.csv')
    
    fim = time.time()
    print(fim - inicio)

    Levou cerca de 0,19 segundos para salvar um dataframe Pandas com três colunas e 100.000 linhas como um arquivo CSV.

    Agora, vamos ver se usar o 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 em apenas uma linha de código:

    inicio = time.time()
    
    df.to_pickle("meu_dataframe_pandas.pkl")
    
    fim = time.time()
    print(fim - inicio)

    Levou apenas 5 milissegundos para salvar o mesmo dataframe Pandas em um arquivo Pickle, o que representa uma melhoria significativa de desempenho em comparação com a gravação em um arquivo CSV.

    Agora, vamos ler o arquivo de volta para o Pandas e ver se carregar um arquivo Pickle oferece benefícios de desempenho em comparação com a simples leitura de um arquivo CSV:

    # Lendo o arquivo CSV para o Pandas:
    
    inicio1 = time.time()
    df_csv = pd.read_csv("meu_dataframe_pandas.csv")
    fim1 = time.time()
    print("Tempo para ler o arquivo CSV: " + str(fim1 - inicio1) + "\n")
    
    # Lendo o arquivo Pickle para o Pandas:
    
    inicio2 = time.time()
    df_pkl = pd.read_pickle("meu_dataframe_pandas.pkl")
    fim2 = time.time()
    print("Tempo para ler o arquivo Pickle: " + str(fim2 - inicio2))

    O código acima deve gerar a seguinte saída:

    Tempo para ler o arquivo CSV: 0.00677490234375
    
    Tempo para ler o arquivo Pickle: 0.0009608268737792969

    Levou 6 milissegundos para ler o arquivo CSV para o Pandas e apenas 0,9 milissegundos para ler o arquivo Pickle. Embora essa diferença possa parecer pequena, a serialização de grandes dataframes Pandas com o Pickle pode resultar em economia de tempo considerável. Além disso, o Pickle nos ajuda a preservar o tipo de dados de cada coluna em todos os casos e ocupa menos espaço em disco do que um arquivo CSV.

    Dicionários

    Finalmente, vamos serializar o dicionário que escrevemos em um arquivo de texto na primeira seção do tutorial:

    estudantes = {
      'Estudante 1': {
            'Nome': "Alice", 'Idade' :10, 'Nota':4,
        },
    
        'Estudante 2': {
            'Nome':'Bob', 'Idade':11, 'Nota':5
        },
    
        'Estudante 3': {
            'Nome':'Elena', 'Idade':14, 'Nota':8
        }
    }

    Lembre-se de que, quando salvamos este dicionário como um arquivo de texto, tivemos que convertê-lo em uma string e perdemos seu estado original.

    Agora, vamos serializá-lo usando o Pickle e lê-lo novamente para garantir que ele ainda contenha todas as propriedades de um dicionário Python:

    # serializa o dicionário para um arquivo Pickle
    
    with open("dicionario_estudantes.pkl", "wb") as arquivo:
        pickle.dump(estudantes, arquivo)
    
    # desserializa o dicionário e o imprime
    
    with open("dicionario_estudantes.pkl", "rb") as arquivo:
        dicionario_desserializado = pickle.load(arquivo)
        print(dicionario_desserializado)

    Você deve obter a seguinte saída:

    {'Estudante 1': {'Nome': 'Alice', 'Idade': 10, 'Nota': 4}, 'Estudante 2': {'Nome': 'Bob', 'Idade': 11, 'Nota': 5}, 'Estudante 3': {'Nome': 'Elena', 'Idade': 14, 'Nota': 8}}

    Agora, vamos verificar o tipo dessa variável:

    type(dicionario_desserializado)

    Ótimo! O dicionário manteve todas as suas propriedades originais e pode ser acessado da mesma forma que antes da serialização.

    Serialização de Modelos de Aprendizado de Máquina com Pickle

    Treinar um modelo de aprendizado de máquina é um processo demorado que pode levar horas, e às vezes até muitos dias. Simplesmente não é viável treinar um algoritmo do zero quando você precisa reutilizá-lo ou transferi-lo para um ambiente diferente.

    Se você deseja aprender boas práticas ao construir algoritmos de aprendizado de máquina, 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 existente, tornando possível usá-los novamente conforme 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 fictícios e construir um modelo de regressão linear com a biblioteca Scikit-Learn:

    from sklearn.linear_model import LinearRegression
    from sklearn.datasets import make_regression
    
    # gerar conjunto de dados de regressão
    X, y = make_regression(n_samples=100, n_features=3, noise=0.1, random_state=1)
    
    # treinar modelo de regressão
    modelo_linear = LinearRegression()
    modelo_linear.fit(X, y)

    Agora, vamos imprimir alguns parâmetros resumidos do modelo:

    # resumo do modelo
    print('Interceptação do modelo:', modelo_linear.intercept_)
    print('Coeficientes do modelo : ', modelo_linear.coef_)
    print('Pontuação do modelo : ', modelo_linear.score(X, y))

    Você deve obter a seguinte saída:

    Interceptação do modelo: -0.010109549594702116
    Coeficientes do modelo :  [44.18793068 98.97389468 58.17121618]
    Pontuação do modelo :  0.9999993081899219

    Em seguida, podemos serializar este modelo usando a função dump() do Pickle:

    with open("regressao_linear.pkl", "wb") as arquivo:
        pickle.dump(modelo_linear, arquivo)

    O modelo agora está salvo como um arquivo Pickle. Vamos desserializá-lo usando a função load():

    with open("regressao_linear.pkl", "rb") as arquivo:
        modelo_linear_desserializado = pickle.load(arquivo)

    O modelo serializado agora está carregado e

    pode ser usado da mesma forma que antes:

    # resumo do modelo desserializado
    print('Interceptação do modelo:', modelo_linear_desserializado.intercept_)
    print('Coeficientes do modelo : ', modelo_linear_desserializado.coef_)
    print('Pontuação do modelo : ', modelo_linear_desserializado.score(X, y))

    Você deve obter a mesma saída que antes:

    Interceptação do modelo: -0.010109549594702116
    Coeficientes do modelo :  [44.18793068 98.97389468 58.17121618]
    Pontuação do modelo :  0.9999993081899219

    Assim, você pode ver como o Pickle pode ser usado para salvar e carregar modelos de aprendizado de máquina. Isso pode ser útil em uma variedade de cenários, como desenvolvimento de modelos em um ambiente e implantação em outro.

    Melhorando o Desempenho do Pickle Python Para Objetos Grandes

    Embora o Pickle seja uma ferramenta poderosa para serialização de objetos Python, ele pode não ser a escolha ideal para objetos muito grandes. Isso ocorre porque o Pickle tende a ser mais lento e produzir arquivos serializados maiores em comparação com outros formatos de serialização, como JSON e Apache Thrift.

    Para objetos grandes, você pode melhorar o desempenho do Pickle em Python da seguinte forma:

    1. Usar um protocolo de serialização diferente: O Pickle suporta diferentes protocolos de serialização, que afetam o desempenho e o tamanho do arquivo serializado. O protocolo padrão é o mais versátil, mas não o mais eficiente em termos de desempenho e tamanho. Você pode especificar um protocolo diferente ao usar pickle.dump() e pickle.dumps(). Por exemplo, pickle.dump(objeto, arquivo, protocol=2) usará o protocolo 2, que é mais eficiente em termos de tamanho, mas pode não ser compatível com versões mais antigas do Python.
    2. Usar a biblioteca joblib: A biblioteca joblib é uma alternativa ao Pickle que é mais eficiente em termos de desempenho e tamanho para objetos grandes, como arrays Numpy e modelos de aprendizado de máquina. Você pode usá-la da mesma forma que o Pickle para serializar e desserializar objetos. Para objetos grandes, joblib é uma escolha comum.
    3. Dividir o objeto em partes menores: Se você estiver lidando com um objeto muito grande que não pode ser facilmente serializado, considere dividi-lo em partes menores e serializar cada parte separadamente. Você pode então carregar e combinar as partes conforme necessário.

    Lembre-se de que a escolha entre Pickle e outras formas de serialização depende das necessidades específicas do seu projeto. Para objetos pequenos a médios, o Pickle é uma opção conveniente e fácil de usar. No entanto, para objetos grandes e preocupações de desempenho, pode ser necessário explorar outras alternativas.

    Próximos Passos com a Serialização Pickle em Python

    Neste tutorial, exploramos a serialização de objetos em Python usando a biblioteca Pickle. Aprendemos como serializar e desserializar tipos de dados comuns, como listas, arrays Numpy, dataframes Pandas e modelos de aprendizado de máquina. Também discutimos as vantagens e desvantagens do Pickle em comparação com outros formatos de serialização.

    Aqui estão alguns próximos passos que você pode seguir para continuar aprendendo sobre a serialização Pickle em Python:

    1. Explorar outros formatos de serialização: Além do Pickle, existem outros formatos de serialização, como JSON, XML, HDF5 e MessagePack. Cada um tem suas próprias características e casos de uso. Experimente usar esses formatos para serializar objetos e compare-os com o Pickle em termos de desempenho e tamanho.
    2. Aprender a usar a biblioteca joblib: A biblioteca joblib é uma alternativa popular ao Pickle para serialização de objetos grandes. Aprenda como usá-la para serializar e desserializar objetos grandes, como arrays Numpy e modelos de aprendizado de máquina.
    3. Explorar a segurança da serialização: Como mencionado anteriormente, o Pickle não é seguro contra ataques de desserialização maliciosos. Pesquise maneiras de melhorar a segurança ao usar a serialização Pickle, como validar objetos desserializados antes de usá-los.
    4. Aprofundar-se em tópicos relacionados: Se você estiver interessado em aprender mais sobre Python, serialização de objetos e tópicos relacionados, considere explorar recursos adicionais, como tutoriais avançados sobre manipulação de dados com Pandas, treinamento de modelos de aprendizado de máquina e segurança de software.

    Em resumo, a serialização de objetos é uma técnica importante em Python para preservar o estado e a estrutura de dados de objetos complexos. O Pickle é uma opção conveniente e versátil para serialização, mas é importante entender suas limitações e considerar outras alternativas quando apropriado. Com o conhecimento adquirido neste tutorial, você estará bem preparado para usar a serialização Pickle em seus próprios projetos Python.

    Tags:

    Leave a Reply

    Your email address will not be published. Required fields are marked *