Pandas: Remodelagem e Pivoteamento

Última atualização: 2026-08-26

Os mesmos dados podem ser armazenados como uma "tabela larga" para legibilidade humana ou uma "tabela longa" para análise programática. O Pandas fornece quatro ferramentas essenciais para converter entre esses formatos: pivot / melt / stack / unstack. Esta aula usa diagramas Mermaid para ilustrar a direção de cada operação de remodelagem, dando uma compreensão intuitiva do que realmente significam "melting" e "pivoting" — uma visualização que a maioria dos tutoriais concorrentes não possui.

⚠️ Nota: O código abaixo requer um ambiente Python local para ser executado.

1. What You Will Learn


2. Transformação do Relatório de Vendas de Alice

(1) O Ponto de Dor: Formato do Relatório ≠ Formato de Análise

O relatório mensal de vendas de Alice está em formato amplo (meses espalhados pelas colunas), mas a análise requer o formato longo (meses como uma única coluna):

PYTHON
import pandas as pd

# Formato amplo — fácil de ler, difícil de analisar
wide = pd.DataFrame({
    'product': ['Latte', 'Mocha', 'Americano'],
    'Jan': [320, 280, 200],
    'Feb': [350, 300, 220],
    'Mar': [380, 310, 240]
})
print(wide)
#     product  Jan  Feb  Mar
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e siga o exemplo. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

(2) A Solução: Converter para Formato Longo com melt

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e siga o exemplo. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: transformar formato amplo em longo (Dificuldade ⭐)

PYTHON
import pandas as pd

wide = pd.DataFrame({
    'product': ['Latte', 'Mocha', 'Americano'],
    'Jan': [320, 280, 200],
    'Feb': [350, 300, 220],
    'Mar': [380, 310, 240]
})

# Melt: as colunas de meses se tornam linhas
long = wide.melt(id_vars='product', var_name='month', value_name='sales')
print(long)
#     product month  sales
# 0     Latte   Jan    320
# 1     Mocha   Jan    280
# 2 Americano   Jan    200
# 3     Latte   Feb    350
# ...
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e siga o exemplo. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

3. Tabelas Largas vs. Tabelas Longas

(1) Diagrama Mermaid: Larga ⇄ Longa

100%
graph LR
    subgraph Wide["Tabela Larga — Amigável para Humanos"]
        W["product | Jan | Feb | Mar<br>Latte   | 320 | 350 | 380<br>Mocha  | 280 | 300 | 310"]
    end
    subgraph Long["Tabela Longa — Amigável para Análise por Máquinas"]
        L["product | month | sales<br>Latte   | Jan   | 320<br>Latte   | Feb   | 350<br>Latte   | Mar   | 380<br>Mocha  | Jan   | 280<br>..."]
    end
    Wide -->|"melt()"| Long
    Long -->|"pivot()"| Wide
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeramente dependendo da versão do pandas.

(2) Comparação Larga vs. Longa

Característica Tabela Larga Tabela Longa
Onde ficam os valores Nos nomes das colunas Nas linhas
Melhor para Leitura humana / relatórios Análise por máquinas / ggplot
Adicionar um novo mês Adicionar uma coluna (a estrutura muda) Adicionar linhas (a estrutura não muda)
groupby Inconveniente Naturalmente suportado
Uso típico Relatórios Excel Bancos de dados / Tidy Data

4. pivot — Pivoting Básico

(1) Pivot Básico

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e siga junto. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: pivot longo para amplo (Dificuldade ⭐)

PYTHON
import pandas as pd

long = pd.DataFrame({
    'produto': ['Latte', 'Latte', 'Latte', 'Mocha', 'Mocha', 'Mocha'],
    'mês': ['Jan', 'Fev', 'Mar', 'Jan', 'Fev', 'Mar'],
    'vendas': [320, 350, 380, 280, 300, 310]
})

# Pivot: linha única=produto, coluna única=mês, valores=vendas
wide = long.pivot(index='produto', columns='mês', values='vendas')
print(wide)
# mês        Fev   Jan   Mar
# produto
# Americano  220   200   240
# Latte      350   320   380
# Mocha      300   280   310

# Redefinir índice para transformar produto em uma coluna regular
wide = wide.reset_index()
print(wide.columns)  # MultiIndex → achatamento
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e siga junto. Os valores reais podem variar ligeiramente dependendo da versão do pandas.
⚠️ Nota: pivot requer que a combinação índice+colunas seja única. Se houver duplicatas (ex.: múltiplos registros para o mesmo produto no mesmo mês), um erro será levantado. Nesse caso, use pivot_table (que agrega automaticamente).


5. pivot_table — Agregação e Dinamização

(1) Dinamização com Agregação

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e siga junto. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: Agregação com pivot_table (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

# Várias entradas por produto+mês (precisa de agregação)
df = pd.DataFrame({
    'product': ['Latte', 'Latte', 'Latte', 'Latte', 'Mocha', 'Mocha'],
    'month': ['Jan', 'Jan', 'Feb', 'Feb', 'Jan', 'Feb'],
    'sales': [150, 170, 180, 170, 140, 160],
    'quantity': [30, 34, 36, 34, 28, 32]
})

# pivot_table com função de agregação
result = pd.pivot_table(
    df,
    values='sales',
    index='product',
    columns='month',
    aggfunc='sum'   # o padrão é 'mean'
)
print(result)
# month     Feb   Jan
# product
# Latte     350   320
# Mocha     160   140

# Várias funções de agregação
result2 = pd.pivot_table(
    df,
    values=['sales', 'quantity'],
    index='product',
    columns='month',
    aggfunc={'sales': 'sum', 'quantity': 'mean'}
)

# Margins — adicionar totais de linha/coluna
result3 = pd.pivot_table(
    df, values='sales', index='product', columns='month',
    aggfunc='sum', margins=True, margins_name='Total'
)
print(result3)
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e siga junto. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

(2) pivot vs. pivot_table

Característica pivot pivot_table
Valores duplicados Lança erro Agrega
Função de agregação Nenhuma sum/mean/count, etc.
margins Não suportado ✅ Totais de linha/coluna
Múltiplas colunas de valor Coluna única Múltiplas colunas
Ideal para Dados limpos sem duplicatas Dados com duplicatas que necessitam de agregação

6. melt — Em Profundidade

(1) Parâmetros do melt

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente local do Python (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: explicação dos parâmetros do melt (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'product': ['Latte', 'Mocha'],
    'region': ['North', 'South'],
    'Jan_sales': [320, 280],
    'Feb_sales': [350, 300],
    'Jan_quantity': [64, 56],
    'Feb_quantity': [70, 60]
})

# Basic melt — todas as colunas não-id viram linhas
result1 = df.melt(id_vars=['product', 'region'])
print(result1)

# Especificar value_vars — fundir apenas certas colunas
result2 = df.melt(
    id_vars=['product', 'region'],
    value_vars=['Jan_sales', 'Feb_sales'],
    var_name='month',
    value_name='sales'
)
print(result2)

# Múltiplos id_vars
result3 = df.melt(
    id_vars=['product'],
    value_vars=['Jan_sales', 'Feb_sales'],
    var_name='month_sales',
    value_name='amount'
)
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente local do Python (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

7. stack / unstack

(1) stack — Colunas para Linhas

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado. Instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: stack/unstack com MultiIndex (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'Jan': [320, 280],
    'Feb': [350, 300],
    'Mar': [380, 310]
}, index=['Latte', 'Mocha'])
df.index.name = 'product'

# stack: colunas → nível de linha (largo → longo)
stacked = df.stack()
print(stacked)
# product  month
# Latte    Jan      320
#          Feb      350
#          Mar      380
# Mocha    Jan      280
# ...

# unstack: nível de linha → colunas (longo → largo)
unstacked = stacked.unstack()
print(unstacked)
#          Jan   Feb   Mar
# product
# Latte    320   350   380
# Mocha    280   300   310

# Com MultiIndex: escolha qual nível fazer unstack
multi = pd.DataFrame({
    'sales': [320, 350, 280, 300],
    'region': ['North', 'North', 'South', 'South'],
    'month': ['Jan', 'Feb', 'Jan', 'Feb']
})
pivot = multi.set_index(['region', 'month'])['sales']
print(pivot.unstack(level='month'))
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado. Instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

(2) Comparação de Quatro Métodos de Remodelagem

Método Direção Entrada → Saída Melhor Para
pivot Longo → Largo Especificar índice/colunas/valores Tabelas longas sem duplicatas
pivot_table Longo → Largo + agregação com aggfunc Tabelas longas com duplicatas
melt Largo → Longo Especificar id_vars Nomes de colunas se tornam valores de linha
stack Colunas → Linhas colunas → nível do índice Operações com MultiIndex
unstack Linhas → Colunas nível do índice → colunas Inverso do stack

8. Exemplo Completo: Pipeline Completa de Conversão Wide-Long

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: Pipeline completa de conversão wide-long (Dificuldade ⭐⭐⭐)

PYTHON
import pandas as pd
import numpy as np

# ============================================
# Exemplo abrangente: Wide ↔ Long
# Pipeline de reestruturação de dados de vendas
# ============================================

# 1. Começar com formato wide (estilo relatório)
np.random.seed(42)
wide = pd.DataFrame({
    'produto': ['Latte', 'Mocha', 'Americano', 'Espresso', 'Cappuccino'],
    'região': ['Norte', 'Sul', 'Leste', 'Oeste', 'Norte'],
    'Jan': np.random.randint(200, 500, 5),
    'Fev': np.random.randint(220, 520, 5),
    'Mar': np.random.randint(240, 540, 5),
    'Abr': np.random.randint(250, 550, 5)
})

print("=== Formato Wide (5 produtos × 4 meses) ===")
print(wide)

# 2. Melt para formato long
long = wide.melt(
    id_vars=['produto', 'região'],
    var_name='mês',
    value_name='vendas'
)
print(f"\n=== Formato Long: {len(long)} linhas ===")
print(long.head(8))

# 3. Analisar em formato long (groupby é natural)
total_mensal = long.groupby('mês')['vendas'].sum()
print(f"\n=== Totais Mensais ===\n{total_mensal}")

média_região = long.groupby('região')['vendas'].mean().round(0)
print(f"\n=== Média por Região ===\n{média_região}")

# 4. Pivote de volta para wide (resumo produto × mês)
resumo_wide = pd.pivot_table(
    long, values='vendas', index='produto', columns='mês',
    aggfunc='sum', margins=True, margins_name='Total'
)
print(f"\n=== Tabela Dinâmica de Resumo ===")
print(resumo_wide)

# 5. Stack/unstack com MultiIndex
multi = long.set_index(['região', 'produto', 'mês'])['vendas']
por_região = multi.unstack(level='mês')
print(f"\n=== Unstack por Mês (Região×Produto) ===")
print(por_região.head(8))
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado. Por favor, instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

❓ Perguntas Frequentes

P: Qual é a diferença entre pivot e pivot_table? R: pivot exige que a combinação de índice+colunas seja única — gera um erro se houver duplicatas. pivot_table lida com duplicatas agregando-as (padrão é a média, mas você pode especificar soma/contagem, etc.) e também suporta totais (somas de linha/coluna). Use pivot para dados simples sem duplicatas; use pivot_table quando houver duplicatas ou for necessária agregação. Na prática, pivot_table é a escolha mais segura para 80% dos cenários do dia a dia.

P: O que são id_vars no melt? R: id_vars são as colunas que NÃO são derretidas — permanecem como identificadores de linha. Todas as outras colunas têm seus nomes coletados em uma coluna de variável (var_name) e seus valores coletados em uma coluna de valor (value_name). Por exemplo, após derreter as colunas de meses Jan/Fev/Mar, as strings 'Jan'/'Fev'/'Mar' tornam-se valores na coluna de mês, e os números correspondentes tornam-se valores na coluna de vendas.

P: stack e unstack são inversas uma da outra? R: Sim — stack empurra colunas para linhas (largo → longo), e unstack espalha linhas em colunas (longo → largo). df.stack().unstack() restaura a tabela original. Eles operam em níveis de MultiIndex — stack adiciona um nível de linha, e unstack adiciona um nível de coluna. O parâmetro level controla qual nível é afetado.

P: Quando devo usar tabelas largas vs. longas? R: Tabelas largas são ideais para leitura humana (relatórios, apresentações, Excel). Tabelas longas são ideais para análise programática (groupby, mesclagem, visualização). O princípio Tidy Data recomenda o formato longo: uma variável por coluna, uma observação por linha. Armazene dados no formato longo (estrutura estável) e exiba-os no formato largo (saída do pivot).

P: O que faço quando o pivot reporta valores duplicados? R: Isso significa que a combinação de índice+colunas tem linhas duplicadas (ex.: múltiplos registros para o mesmo produto no mesmo mês). Você tem duas opções: ① Usar pivot_table com aggfunc='sum'/'mean' para agregar automaticamente; ② Agregar primeiro com groupby, depois fazer pivot. pivot_table é mais conciso e geralmente preferido.

P: Como inverto uma operação de melt? R: Use pivot ou pivot_table para restaurar o formato original: long.pivot(index='product', columns='month', values='sales'). melt e pivot são operações inversas. Observe que os tipos de dados podem mudar após o derretimento (colunas numéricas podem se tornar objeto), então pode ser necessário conversão com astype antes de restaurar.

P: O que é Tidy Data? R: Tidy Data é um princípio de organização de dados proposto por Hadley Wickham: ① Cada variável ocupa uma coluna; ② Cada observação ocupa uma linha; ③ Cada tipo de unidade observacional ocupa uma tabela. Tabelas longas naturalmente atendem ao Tidy Data; tabelas largas não (a variável de mês está oculta nos nomes das colunas). O melt do Pandas existe justamente para "organizar" tabelas largas no formato Tidy Data.


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Crie uma tabela ampla (3 produtos × 3 meses), use melt para convertê-la para o formato longo, depois use pivot para convertê-la de volta para o formato amplo e verifique se os resultados coincidem.
  2. Intermediário (Dificuldade ⭐⭐): Crie dados de vendas com valores duplicados (vários registros para o mesmo produto no mesmo mês), depois use pivot_table(aggfunc='sum') + margins=True para gerar uma tabela dinâmica com totais de linha e coluna.
  3. Desafio (Dificuldade ⭐⭐⭐): Simule dados no formato longo para 3 regiões × 4 produtos × 3 meses, depois complete o seguinte: use set_index para criar um MultiIndex → unstack para espalhar por mês → stack para comprimir de volta → melt para uma transformação alternativa → pivot_table para análise cruzada.

← Previous: Concatenation and Appending · Next: String Operations →

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%