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.
1. What You Will Learn
- ❶ pivot — basic pivoting
- ❷ pivot_table — aggregation pivoting
- ❸ melt — wide to long
- ❹ stack / unstack
- ❺ Wide vs. long tables and Tidy Data
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):
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
> **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
> **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 ⭐)
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
# ...
> **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
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
> **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
> **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 ⭐)
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
> **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.
5. pivot_table — Agregação e Dinamização
(1) Dinamização com Agregação
▶ Exemplo
> **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 ⭐⭐)
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)
> **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
> **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 ⭐⭐)
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'
)
> **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
> **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 ⭐⭐)
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'))
> **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
> **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 ⭐⭐⭐)
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))
> **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
- pivot converte formato longo para largo (quando não há duplicatas); pivot_table converte formato longo para largo com agregação (quando existem duplicatas)
- melt converte formato largo para longo: id_vars são as colunas preservadas; os nomes das colunas restantes se tornam uma coluna de variável, e seus valores se tornam uma coluna de valor
- stack empurra colunas para linhas (largo → longo); unstack espalha linhas em colunas (longo → largo) — são operações inversas
- Tabelas no formato largo são amigáveis para humanos; tabelas no formato longo são amigáveis para análise por máquina; o Tidy Data recomenda o formato longo
- Fluxo de trabalho típico: dados brutos → melt para tidy → groupby para análise → pivot_table para relatório
- Se o pivot gerar um erro de duplicata → mudar para pivot_table + aggfunc
📝 Exercícios
- Básico (Dificuldade ⭐): Crie uma tabela ampla (3 produtos × 3 meses), use
meltpara convertê-la para o formato longo, depois usepivotpara convertê-la de volta para o formato amplo e verifique se os resultados coincidem. - 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=Truepara gerar uma tabela dinâmica com totais de linha e coluna. - Desafio (Dificuldade ⭐⭐⭐): Simule dados no formato longo para 3 regiões × 4 produtos × 3 meses, depois complete o seguinte: use
set_indexpara criar um MultiIndex →unstackpara espalhar por mês →stackpara comprimir de volta →meltpara uma transformação alternativa →pivot_tablepara análise cruzada.
← Previous: Concatenation and Appending · Next: String Operations →