Pandas: Índice Múltiplo

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

Quando os dados possuem uma estrutura hierárquica — agrupados por cidade e depois por produto, ou por ano e depois por trimestre — um índice de nível único não é suficiente. O MultiIndex (indexação hierárquica) oferece uma indexação em camadas para dados estruturados em camadas: selecione o primeiro nível e depois aprofunde-se no segundo, navegando exatamente como uma hierarquia de pastas. Esta seção aborda a criação, seleção, reordenação e combinação de MultiIndex com stack/unstack.

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

1. O Que Você Aprenderá


2. Dados de Vendas de Múltiplas Cidades e Categorias do Bob

(1) Ponto de Dificuldade: Resultados Agrupados em Dois Níveis São Difíceis de Selecionar

Após agrupar por cidade + categoria, Bob acaba com um índice de dois níveis e não sabe como selecionar uma cidade específica:

PYTHON
import pandas as pd

df = pd.DataFrame({
    'city': ['NYC', 'NYC', 'LA', 'LA', 'Chicago', 'Chicago'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing', 'Electronics', 'Clothing'],
    'sales': [5000, 800, 3000, 600, 2000, 400]
})
result = df.groupby(['city', 'category'])['sales'].sum()
print(result)
# city     category
# Chicago  Clothing       400
#          Electronics   2000
# LA       Clothing       600
#          Electronics   3000
# NYC      Clothing       800
#          Electronics   5000
# Como selecionar apenas NYC?
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.

(2) Solução: Seleção com MultiIndex

▶ Exemplo

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

: Seleção com MultiIndex (Dificuldade ⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'city': ['NYC', 'NYC', 'LA', 'LA', 'Chicago', 'Chicago'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing', 'Electronics', 'Clothing'],
    'sales': [5000, 800, 3000, 600, 2000, 400]
})
result = df.groupby(['city', 'category'])['sales'].sum()

# Selecionar pelo rótulo MultiIndex
print(result.loc['NYC'])
# category
# Clothing       800
# Electronics   5000

# Selecionar específica (cidade, categoria)
print(result.loc[('NYC', 'Electronics')])  # 5000

# xs: seleção de seção transversal
print(result.xs('Electronics', level='category'))
# city
# Chicago    2000
# LA         3000
# NYC        5000
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.

3. Criando um MultiIndex

(1) Três Métodos de Criação

▶ Exemplo

TEXT 📖 Somente leitura
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on your pandas version.

: Métodos de Criação de MultiIndex (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

# 1. from_tuples — explicit pairs
index = pd.MultiIndex.from_tuples([
    ('NYC', 'Electronics'), ('NYC', 'Clothing'),
    ('LA', 'Electronics'), ('LA', 'Clothing')
], names=['city', 'category'])
df1 = pd.DataFrame({'sales': [5000, 800, 3000, 600]}, index=index)
print("from_tuples:")
print(df1)

# 2. from_product — cartesian product (most common)
index2 = pd.MultiIndex.from_product(
    [['NYC', 'LA', 'Chicago'], ['Electronics', 'Clothing']],
    names=['city', 'category']
)
df2 = pd.DataFrame({
    'sales': [5000, 800, 3000, 600, 2000, 400]
}, index=index2)
print("\nfrom_product:")
print(df2)

# 3. from_frame — from DataFrame
df_index = pd.DataFrame({
    'city': ['NYC', 'NYC', 'LA', 'LA'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing']
})
index3 = pd.MultiIndex.from_frame(df_index)
df3 = pd.DataFrame({'sales': [5000, 800, 3000, 600]}, index=index3)
TEXT 📖 Somente leitura
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on your pandas version.

4. Seleção Hierárquica

(1) loc vs xs

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute isso 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 sua versão do pandas.

: Métodos de Seleção Hierárquica (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

index = pd.MultiIndex.from_product(
    [['NYC', 'LA'], ['Electronics', 'Clothing', 'Home']],
    names=['city', 'category']
)
df = pd.DataFrame({
    'sales': [5000, 800, 300, 3000, 600, 200],
    'profit': [1500, 200, 50, 800, 100, 30]
}, index=index)

# loc: seleciona o primeiro nível
print(df.loc['NYC'])

# loc: seleciona ambos os níveis
print(df.loc[('NYC', 'Electronics')])

# xs: seção transversal (seleciona em QUALQUER nível)
print(df.xs('Electronics', level='category'))
# Retorna os dados de Eletrônica de todas as cidades

# xs com drop_level=False
print(df.xs('NYC', level='city', drop_level=False))

# Seleção parcial com slice
print(df.loc[('NYC', slice(None)), :])  # todas as categorias em NYC
TEXT 📖 Somente leitura
> **Saída:** Execute isso 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 sua versão do pandas.

(2) Comparação loc vs xs

Característica loc xs
Selecionar um nível loc['NYC'] xs('NYC', level=0)
Selecionar segundo nível Complexo loc[(slice(None),'Elec')] Simples xs('Elec', level=1)
Vários níveis de uma vez loc[('NYC','Elec')] ❌ Apenas um nível por vez
Preservar nível Preservado por padrão Controlado por drop_level

5. swaplevel / sort_index

(1) Trocando Níveis

▶ Exemplo

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

: swaplevel para Reordenar Níveis (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

index = pd.MultiIndex.from_product(
    [['NYC', 'LA'], ['Q1', 'Q2', 'Q3', 'Q4']],
    names=['city', 'quarter']
)
df = pd.DataFrame({
    'sales': [1200, 1300, 1100, 1400, 800, 900, 700, 1000]
}, index=index)

# Troca os níveis
df_swapped = df.swaplevel()
print(df_swapped.head(4))
# city    quarter
# Q1      NYC        1200
# Q2      NYC        1300
# Q3      NYC        1100
# Q4      NYC        1400

# sort_index após a troca (importante!)
df_sorted = df_swapped.sort_index()
print(df_sorted.head(4))

# reorder_levels: reordenação arbitrária
df_reordered = df.reorder_levels(['quarter', 'city'])
TEXT 📖 Somente leitura
> **Saída:** Execute isto em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
⚠️ Nota: Após swaplevel ou reorder_levels, você deve chamar sort_index() — caso contrário, operações de seleção subsequentes podem gerar erros ou ser executadas lentamente.


6. MultiIndex com stack/unstack

▶ Exemplo

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

: stack/unstack com MultiIndex (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'city': ['NYC', 'NYC', 'LA', 'LA'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing'],
    'Q1': [1200, 400, 800, 200],
    'Q2': [1300, 500, 900, 300]
})

# set_index → DataFrame MultiIndex
multi_df = df.set_index(['city', 'category'])
print(multi_df)

# unstack: nível category → colunas
wide = multi_df.unstack(level='category')
print(wide)
#          Q1                 Q2
# category Clothing Electronics  Clothing Electronics
# city
# LA            200         800       300         900
# NYC           400        1200       500        1300

# stack: colunas → nível do índice (inverso)
back = wide.stack(level='category')
print(back)
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

7. Achatamento com reset_index

▶ Exemplo

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

: Achatamento de um MultiIndex (Dificuldade ⭐)

PYTHON
import pandas as pd

index = pd.MultiIndex.from_product(
    [['NYC', 'LA'], ['Q1', 'Q2']],
    names=['city', 'quarter']
)
df = pd.DataFrame({'sales': [1200, 1300, 800, 900]}, index=index)

# reset_index: MultiIndex → colunas regulares
flat = df.reset_index()
print(flat)
#    city quarter  sales
# 0   NYC      Q1   1200
# 1   NYC      Q2   1300
# 2    LA      Q1    800
# 3    LA      Q2    900

# Achatamento do MultiIndex das colunas
wide = df.unstack()
flat_cols = wide.copy()
flat_cols.columns = [f'{a}_{b}' for a, b in flat_cols.columns]
print(flat_cols)
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instale — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

8. Exemplo Completo: Análise de Vendas Multi-Cidade, Multi-Categoria

(6) ▶ Estrutura Hierárquica MultiIndex

100%
graph TB
    A[DataFrame] --> B[Outer index: city]
    B --> C[NYC]
    B --> D[LA]
    B --> E[Chicago]
    C --> F[Inner index: category]
    F --> G[Electronics]
    F --> H[Clothing]
    F --> I[Home]
    D --> J[Electronics]
    D --> K[Clothing]
    E --> L[Electronics]
    E --> M[Clothing]
TEXT 📖 Somente leitura
> **Saída:** Execute isso 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 sua versão do pandas.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute isso 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 sua versão do pandas.

: Análise de Fluxo de Trabalho MultiIndex Completo (Dificuldade ⭐⭐⭐)

PYTHON
import pandas as pd
import numpy as np

# ============================================
# Exemplo abrangente: análise de vendas
# multi-cidade multi-categoria com MultiIndex
# ============================================

# 1. Criar dados hierárquicos
np.random.seed(42)
index = pd.MultiIndex.from_product(
    [['NYC', 'LA', 'Chicago', 'Houston'],
     ['Electronics', 'Clothing', 'Home'],
     ['Q1', 'Q2', 'Q3', 'Q4']],
    names=['city', 'category', 'quarter']
)
df = pd.DataFrame({
    'sales': np.random.randint(100, 5000, 48),
    'profit': np.random.randint(10, 1500, 48)
}, index=index)

# 2. Visualizar estrutura
print(f"Níveis: {df.index.names}")
print(f"Formato: {df.shape}")

# 3. Selecionar por cidade
print("\n=== Vendas de NYC ===")
print(df.loc['NYC', 'sales'].unstack(level='quarter'))

# 4. xs: todos os Electronics nas cidades
print("\n=== Electronics por Cidade ===")
elec = df.xs('Electronics', level='category')[['sales']]
print(elec.unstack(level='quarter'))

# 5. swaplevel → sort → select
df2 = df.swaplevel('city', 'quarter').sort_index()
print("\n=== Q1 em todas as cidades ===")
print(df2.loc['Q1'])

# 6. Unstack para relatório amplo
report = df['sales'].unstack(level=['category', 'quarter'])
print("\n=== Relatório Amplo (primeiras 2 cidades) ===")
print(report.head(2))

# 7. Reset para exportação
flat = df.reset_index()
print(f"\nFormato achatado: {flat.shape}")
TEXT 📖 Somente leitura
> **Saída:** Execute isso 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 sua versão do pandas.

❓ Perguntas Frequentes

Q: Quando devo usar um MultiIndex? R: Quando seus dados têm uma estrutura hierárquica natural — cidade + categoria, ano + trimestre, departamento + equipe. Agrupar por múltiplas colunas automaticamente produz um MultiIndex, e o set_index com múltiplas colunas também faz isso. Para dados simples, um índice de nível único é mais conveniente — não force um MultiIndex onde ele não é necessário.

Q: Qual é a diferença entre xs e loc? R: O xs pode selecionar em qualquer nível (ex: selecionar diretamente category='Electronics' sem selecionar a cidade primeiro). O loc só pode selecionar do nível mais externo para o interno (cidade primeiro, depois categoria). O xs é mais flexível, mas não pode selecionar múltiplos níveis simultaneamente; o loc suporta loc[('NYC','Electronics')], mas a sintaxe de seleção do segundo nível é mais complexa.

Q: O swaplevel altera os dados? R: Não — o swaplevel apenas troca a ordem dos níveis do índice; os dados em si permanecem inalterados. No entanto, você deve chamar sort_index() após a troca, caso contrário seleções subsequentes podem produzir erros ou desempenho ruim. Fluxo de trabalho recomendado: swaplevel → sort_index → selecionar.

Q: Como achatar um MultiIndex? R: Para MultiIndex no nível das linhas → use df.reset_index() para converter os níveis em colunas regulares. Para MultiIndex no nível das colunas → renomeie as colunas unindo os valores dos níveis: ['_'.join(col) for col in df.columns]. Após o groupby, use as_index=False para evitar criar um MultiIndex (mas você perde a capacidade de seleção hierárquica).

Q: Como é o desempenho do MultiIndex? R: As consultas ao MultiIndex são O(1) (baseado em hash subjacente), então o desempenho é excelente. No entanto, a eficiência só é garantida após o sort_index() — uma seleção em um MultiIndex não ordenado pode degradar para O(n). Para grandes conjuntos de dados: chame sort_index() imediatamente após a criação, e use is_unique para verificar a unicidade.

Q: Para que serve get_level_values? R: df.index.get_level_values('city') retorna todos os valores em um determinado nível (ex: ['NYC','NYC','LA','LA',...]). Útil para seleção condicional: df[df.index.get_level_values('city') == 'NYC']. Também funciona com groupby: df.groupby(df.index.get_level_values(0)).sum().

Q: Como escolher entre from_product e from_tuples? R: O from_product gera o produto cartesiano (todas as combinações) — ideal para dados de grade completa (3 cidades × 4 trimestres = 12 linhas). O from_tuples especifica combinações exatas — ideal para dados incompletos (algumas cidades faltando certas categorias). O from_product é mais conciso; o from_tuples é mais preciso.


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Use from_product para criar um DataFrame MultiIndex com 3 cidades × 2 categorias, em seguida use loc e xs para selecionar uma cidade específica e uma categoria específica, respectivamente.
  2. Intermediário (Dificuldade ⭐⭐): Crie um DataFrame MultiIndex cidade × trimestre, use swaplevel para trocar os níveis → sort_index → unstack para uma tabela ampla → stack de volta e verifique a conversão completa.
  3. Desafio (Dificuldade ⭐⭐⭐): Simule 48 linhas de dados com 4 regiões × 3 categorias × 4 trimestres, em seguida complete: seleção cruzada de nível com xs → reordenação com swaplevel → unstack multinível para formato amplo → reset_index para exportação → groupby para reagregar.

← Previous: Advanced Time Series · Next: Window Functions →

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%