Python
Pandas Unstack: Um Guia para Iniciantes sobre Reestruturação de Dados

Pandas Unstack: Um Guia para Iniciantes sobre Reestruturação de Dados

MoeNagy Dev

Entendendo o pandas unstack

Explicação do pandas unstack

O que é o pandas unstack?

unstack() é uma função do pandas que transforma um DataFrame de um formato longo para um formato amplo. Ela pega um índice de coluna multinível e "desempilha" (unstack) ele, criando um novo DataFrame com um ou mais níveis de índice se tornando colunas.

Como ele difere de pivot e melt?

A função unstack() é semelhante à função pivot(), mas elas servem a propósitos diferentes. pivot() é usada para reestruturar dados de formato longo para formato amplo, enquanto unstack() é usada para reestruturar dados de formato amplo para formato longo.

A função melt(), por outro lado, é usada para transformar dados de formato amplo para formato longo, que é o oposto do que unstack() faz.

Quando usar o pandas unstack?

Você deve usar unstack() quando tiver um DataFrame com um índice de coluna multinível e quiser transformá-lo em um formato amplo, onde os níveis do índice de coluna se tornam novas colunas no DataFrame.

Preparando os Dados

Importando as bibliotecas necessárias

import pandas as pd
import numpy as np

Criando um DataFrame de exemplo

# Criar um DataFrame de exemplo
data = {
    ('Loja A', 'Vendas'): [100, 120, 80, 90, 110],
    ('Loja A', 'Lucro'): [20, 25, 15, 18, 22],
    ('Loja B', 'Vendas'): [150, 180, 120, 160, 200],
    ('Loja B', 'Lucro'): [30, 35, 25, 32, 40]
}
 
df = pd.DataFrame(data)

Explorando a estrutura do DataFrame

print(df)
           (Loja A, Vendas)  (Loja A, Lucro)  (Loja B, Vendas)  (Loja B, Lucro)
0  .

100 20 150 30 1 120 25 180 35 2 80 15 120 25 3 90 18 160 32 4 110 22 200 40

Como você pode ver, o DataFrame tem um índice de coluna de vários níveis, com o primeiro nível representando a loja e o segundo nível representando a métrica (Vendas ou Lucro).

Noções básicas de unstack do pandas

Desempilhando um índice de nível único

Para desempilhar um índice de nível único, você pode usar a função unstack() sem nenhum argumento:

df_desempilhado = df.unstack()
print(df_desempilhado)
                 Vendas        Lucro
                 Loja A Loja B Loja A Loja B
0                    100     150       20       30
1                    120     180       25       35
2                     80     120       15       25
3                     90     160       18       32
4                    110     200       22       40

O DataFrame resultante tem os nomes das lojas como o índice de coluna, e os nomes de coluna originais (Vendas e Lucro) se tornaram o índice de linha.

Desempilhando um índice de vários níveis

Se o DataFrame tiver um índice de coluna de vários níveis, você pode especificar o nível a ser desempilhado:

df_desempilhado = df.unstack(level=0)
print(df_desempilhado)
                  (Vendas, Loja A)  (Vendas, Loja B)  (Lucro, Loja A)  (Lucro, Loja B)
0                             100               150                 20                 30
1                             120               180                 25                 35
2                              80               120                 15                 25
3                              90               160                 18                 32
4                             110            .

200 22 40


Neste caso, os nomes das lojas se tornaram o índice da coluna, e os nomes originais das colunas (Vendas e Lucro) agora fazem parte do índice de coluna de vários níveis.

#### Entendendo a estrutura resultante do DataFrame

O DataFrame desempilhado tem um índice de coluna de vários níveis, onde o primeiro nível representa os nomes originais das colunas e o segundo nível representa os valores que anteriormente estavam no índice da coluna.

Essa estrutura pode ser útil para certos tipos de análise e visualização de dados, pois permite acessar e manipular os dados de diferentes maneiras com facilidade.

### Lidando com Dados Ausentes no pandas unstack

#### Lidando com valores NaN

Se houver algum valor ausente no DataFrame original, a função `unstack()` introduzirá valores NaN no DataFrame resultante:

```python
# Adicione alguns valores ausentes ao DataFrame de exemplo
data = {
    ('Loja A', 'Vendas'): [100, 120, 80, np.nan, 110],
    ('Loja A', 'Lucro'): [20, 25, 15, 18, 22],
    ('Loja B', 'Vendas'): [150, 180, 120, 160, 200],
    ('Loja B', 'Lucro'): [30, 35, 25, 32, np.nan]
}

df = pd.DataFrame(data)
df_desempilhado = df.unstack()
print(df_desempilhado)
                 Vendas        Lucro
                 Loja A Loja B Loja A Loja B
0                    100     150       20     30.0
1                    120     180       25     35.0
2                     80     120       15     25.0
3                    NaN     160       18     32.0
4                    110     200       22      NaN

Você pode ver que os valores ausentes no DataFrame original foram transferidos para o DataFrame desempilhado.

Preenchendo valores ausentes

Para lidar com os valores ausentes, você pode usar o método fillna() para substituí-los por um valor específico:

df_desempilhado = df.unstack().fillna(0)
print(df_desempilhado)
                 Vendas        Lucro
                 Loja A Loja B Loja A Loja B
0                    100     150       20     0.0
1                    120     180       25     35.0
2                     80     120       15     25.0
3                      0     160       18     32.0
4                    110     200       22     0.0

30 1 120 180 25 35 2 80 120 15 25 3 0 160 18 32 4 110 200 22 0


Neste exemplo, preenchemos os valores ausentes com 0.

#### Especificando o valor de preenchimento

Você também pode especificar um valor de preenchimento diferente, como a média ou a mediana da coluna:

```python
# Preencher valores ausentes com a média da coluna
df_unstacked = df.unstack().fillna(df.mean())
print(df_unstacked)
                 Vendas        Lucro
                 Loja A Loja B Loja A Loja B
0                    100     150       20     32.5
1                    120     180       25     32.5
2                     80     120       15     32.5
3                    95.0     160       18     32.5
4                    110     200       22     22.0

Neste exemplo, preenchemos os valores ausentes com a média das respectivas colunas.

Técnicas avançadas com pandas unstack

Unstacking com níveis especificados

Você também pode desempilhar níveis específicos do índice de colunas, em vez de desempilhar todos os níveis:

# Desempilhar o segundo nível do índice de colunas
df_unstacked = df.unstack(level=1)
print(df_unstacked)
                   Vendas   Lucro
Loja A  0            100       20
        1            120       25
        2             80       15
        3            NaN       18
        4            110       22
Loja B  0            150       30
        1            180       35
        2            120       25
        3            160       32
        4            200       NaN

Neste caso, os nomes das lojas se tornaram o índice de linhas, e os nomes de colunas originais (Vendas e Lucro) se tornaram o índice de colunas.

Combinando unstack com outras operações do pandas

Você pode combinar a função unstack() com outras operações do pandas, como reset_index() ou rename(), para manipular ainda mais os dados:

# Desempilhar e redefinir .
df_unstacked = df.unstack().reset_index()
print(df_unstacked)
  level_0 level_1   0         1
0  Store A  Sales  100       20
1  Store A  Sales  120       25
2  Store A  Sales   80       15
3  Store A  Sales  NaN       18
4  Store A  Sales  110       22
5  Store B  Sales  150       30
6  Store B  Sales  180       35
7  Store B  Sales  120       25
8  Store B  Sales  160       32
9  Store B  Sales  200       NaN

Neste exemplo, nós desempilhamos (unstacked) o DataFrame e, em seguida, redefinimos o índice, o que cria um novo DataFrame com os valores desempilhados em uma única coluna.

Redefinindo o índice após o desempilhamento

Se você quiser redefinir o índice após o desempilhamento, você pode usar o método reset_index():

# Desempilhar e redefinir o índice
df_unstacked = df.unstack().reset_index()
print(df_unstacked)
  level_0 level_1   0         1
0  Store A  Sales  100       20
1  Store A  Sales  120       25
2  Store A  Sales   80       15
3  Store A  Sales  NaN       18
4  Store A  Sales  110       22
5  Store B  Sales  150       30
6  Store B  Sales  180       35
7  Store B  Sales  120       25
8  Store B  Sales  160       32
9  Store B  Sales  200       NaN

Isso cria um novo DataFrame com os valores desempilhados em uma única coluna, e os níveis de índice originais agora são colunas no DataFrame.

Visualizando Dados Desempilhados

Criando mapas de calor

Uma maneira de visualizar dados desempilhados é criar um mapa de calor usando a biblioteca seaborn:

import seaborn as sns
import matplotlib.pyplot as plt
 
# Desempilhar o DataFrame
df_unstacked = df.unstack()
 
# Criar um mapa de calor
plt.figure(figsize=(8, 6))
sns.heatmap(df_unstacked, annot=True, cmap="YlOrRd")
plt.title("Vendas e Lucro por Loja")
plt.show()

Isso criará um mapa de calor que visualiza os dados de vendas e lucro para cada loja.

Gerando tabelas dinâmicas

Você também pode usar a função pivot_table() para criar uma tabela dinâmica a partir dos dados desempilhados:

# Criar uma tabela dinâmica
pivot_table = ...

e = df.pivot_table(index=['Loja'], columns=['Métrica'], values=['Valor']) print(pivot_table)

Valor Métrica Lucro Vendas Loja A 20 100 25 120 15 80 18 NaN 22 110 Loja B 30 150 35 180 25 120 32 160 NaN 200


Esta tabela dinâmica tem os nomes das lojas como o índice de linha e os nomes das métricas como o índice de coluna, com os valores correspondentes nas células.

#### Plotando dados não empilhados

Você também pode plotar os dados não empilhados diretamente, como criar um gráfico de barras ou um gráfico de linha:

```python
# Plotar os dados não empilhados
df_unstacked.plot(kind="bar", figsize=(10, 6))
plt.title("Vendas e Lucro por Loja")
plt.xlabel("Loja")
plt.ylabel("Valor")
plt.show()

Isso criará um gráfico de barras que mostra os valores de vendas e lucro para cada loja.

Aplicações Práticas do unstack do pandas

Analisando dados de vendas

O unstack pode ser útil para analisar dados de vendas, especialmente quando você tem um índice de coluna multinível. Você pode usar os dados não empilhados para criar tabelas dinâmicas, mapas de calor ou outras visualizações para entender melhor as tendências e o desempenho das vendas em diferentes lojas, produtos ou períodos.

Remodelando dados de séries temporais

O unstack() também pode ser útil para remodelar dados de séries temporais, onde você tem um índice multinível com tempo e alguma outra dimensão (por exemplo, localização, produto). Ao desempilhar os dados, você pode criar um DataFrame de formato amplo que é mais fácil de trabalhar para certos tipos de análise e visualização.

Manipulando dados de pesquisa

No caso de dados de pesquisa, onde você tem respostas a diferentes perguntas para cada participante, o unstack() pode ser usado para transformar os dados de um formato longo para um formato amplo, facilitando a análise das relações entre as diferentes perguntas da pesquisa.

Solução de Problemas e Melhores Práticas

Problemas e mensagens de erro comuns

Um problema comum com o unstack() é que ele pode introduzir.

Funções

Funções são blocos de código reutilizáveis que executam uma tarefa específica. Elas podem receber parâmetros de entrada, realizar operações e retornar um valor. As funções ajudam a organizar e modularizar seu código, tornando-o mais legível e fácil de manter.

Aqui está um exemplo de uma função simples que calcula a área de um círculo:

def calcular_area_circulo(raio):
    """
    Calcula a área de um círculo.
 
    Args:
        raio (float): O raio do círculo.
 
    Returns:
        float: A área do círculo.
    """
    pi = 3.14159
    area = pi * (raio ** 2)
    return area
 
# Exemplo de uso
raio_circulo = 5.0
area_circulo = calcular_area_circulo(raio_circulo)
print(f"A área de um círculo com raio {raio_circulo} é {area_circulo:.2f} unidades quadradas.")

Neste exemplo, a função calcular_area_circulo recebe um parâmetro raio, calcula a área usando a fórmula pi * (raio ** 2) e retorna o resultado. A função também inclui uma docstring que fornece uma breve descrição do propósito da função, seu parâmetro de entrada e seu valor de retorno.

Módulos e Pacotes

O design modular do Python permite que você organize seu código em componentes reutilizáveis chamados módulos. Módulos são arquivos Python que contêm definições para variáveis, funções e classes. Importando módulos, você pode acessar e usar o código que eles fornecem.

Aqui está um exemplo de como criar e usar um módulo personalizado:

# my_module.py
def saudar(nome):
    print(f"Olá, {nome}!")
 
# main.py
import my_module
 
my_module.saudar("Alice")

Neste exemplo, criamos um módulo chamado my_module.py que contém uma função saudar. No arquivo main.py, importamos o my_module e chamamos a função saudar.

Pacotes são coleções de módulos relacionados. Eles ajudam a organizar seu código e fornecem uma maneira de agrupar e distribuir seu código Python. Aqui está um exemplo de uma estrutura de pacote simples:

meu_pacote/
    __init__.py
    modulo1.py

y module2.py subpackage/ init.py module3.py

Neste exemplo, my_package é um pacote que contém dois módulos (module1.py e module2.py) e um subpacote (subpackage). Os arquivos __init__.py no pacote e no subpacote são usados para definir a estrutura e o comportamento do pacote.

Programação Orientada a Objetos (POO)

A Programação Orientada a Objetos (POO) é um paradigma de programação que se concentra na criação de objetos que contêm tanto dados (atributos) quanto funções (métodos) para representar e manipular esses dados. A POO fornece conceitos como classes, herança e polimorfismo, que ajudam a criar um código mais organizado e reutilizável.

Aqui está um exemplo de uma classe simples em Python:

class Cachorro:
    def __init__(self, nome, raca):
        self.nome = nome
        self.raca = raca
 
    def latir(self):
        print("Au au!")
 
# Exemplo de uso
meu_cachorro = Cachorro("Buddy", "Labrador")
print(meu_cachorro.nome)  # Saída: Buddy
print(meu_cachorro.raca)  # Saída: Labrador
meu_cachorro.latir()  # Saída: Au au!

Neste exemplo, definimos uma classe Cachorro com um método __init__ que inicializa os atributos nome e raca. A classe também possui um método latir que imprime "Au au!". Em seguida, criamos uma instância da classe Cachorro e acessamos seus atributos e método.

A POO também fornece conceitos como herança, onde uma classe filha pode herdar atributos e métodos de uma classe pai. Aqui está um exemplo:

class CachorroGuia(Cachorro):
    def __init__(self, nome, raca, pode_guiar):
        super().__init__(nome, raca)
        self.pode_guiar = pode_guiar
 
    def guiar(self):
        print("Eu posso guiar meu dono.")
 
# Exemplo de uso
meu_cachorro_guia = CachorroGuia("Buddy", "Labrador", True)
print(meu_cachorro_guia.nome)  # Saída: Buddy
print(meu_cachorro_guia.raca)  # Saída: Labrador
print(meu_cachorro_guia.pode_guiar)  # Saída: True
meu_cachorro_guia.latir()  # Saída: Au au!
meu_cachorro_guia.guiar()  # Saída: Eu posso guiar meu dono.

Neste exemplo, a classe CachorroGuia herda da classe Cachorro.

Herança e Polimorfismo

O código a seguir cria uma subclasse GuideDog que herda da classe Dog e adiciona um novo atributo can_guide e um novo método guide. O método __init__ da classe GuideDog chama o método __init__ da classe pai Dog usando super().__init__ para inicializar os atributos name e breed.

Exceções e Tratamento de Erros

Exceções são eventos que ocorrem durante a execução de um programa e interrompem o fluxo normal das instruções do programa. O Python possui um mecanismo de tratamento de exceções integrado que permite antecipar e lidar com essas exceções.

Aqui está um exemplo de como lidar com uma exceção ZeroDivisionError:

def divide(a, b):
    try:
        result = a / b
        return result
    except ZeroDivisionError:
        print("Erro: Divisão por zero.")
        return None
 
# Exemplo de uso
print(divide(10, 2))  # Saída: 5.0
print(divide(10, 0))  # Saída: Erro: Divisão por zero.

Neste exemplo, a função divide tenta dividir a por b no bloco try. Se ocorrer uma ZeroDivisionError, o código no bloco except é executado e uma mensagem é impressa. A função então retorna None para indicar que a operação de divisão não foi bem-sucedida.

Você também pode usar o bloco finally para executar código independentemente de uma exceção ter sido levantada ou não. Isso é útil para limpar recursos, como fechar um arquivo ou uma conexão com o banco de dados.

try:
    file = open("file.txt", "r")
    content = file.read()
    print(content)
except FileNotFoundError:
    print("Erro: Arquivo não encontrado.")
finally:
    file.close()

Neste exemplo, o bloco finally garante que o arquivo seja fechado, mesmo que uma exceção seja levantada no bloco try.

Conclusão

Neste tutorial de Python, abordamos uma ampla gama de tópicos, incluindo funções, módulos e pacotes, programação orientada a objetos e tratamento de exceções. Esses conceitos são fundamentais para escrever código Python eficaz e mantível.

Ao entender e aplicar essas técnicas, você será capaz de . Fique no caminho certo para se tornar um programador Python proficiente. Lembre-se de praticar regularmente, experimentar diferentes exemplos de código e explorar o vasto ecossistema de bibliotecas e estruturas Python para expandir seus conhecimentos e habilidades.

Bom código!

MoeNagy Dev.