Pandas: Mesclar e Juntar

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

Dados do mundo real nunca vivem em uma única tabela — informações de usuários em uma tabela, registros de pedidos em outra, detalhes de produtos em mais outra. A análise exige uni-los, e é exatamente isso que o mesclagem faz. O mesclagem do Pandas implementa todos os tipos de JOIN do SQL. Nesta seção, usamos diagramas Mermaid para ilustrar o efeito de todos os 4 tipos de junção, para que você possa entender claramente "o que é mantido da tabela da esquerda e o que é mantido da tabela da direita."

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

1. What You Will Learn


2. Associação Usuário-Pedido do Bob

(1) O Problema: Duas Tabelas Separadas, Sem Forma de Analisar

O Bob tem uma tabela de usuários e uma tabela de pedidos. Ele quer ver "o que cada usuário comprou":

PYTHON
import pandas as pd

users = pd.DataFrame({
    'user_id': [1, 2, 3, 4],
    'name': ['Alice', 'Bob', 'Charlie', 'Carol']
})

orders = pd.DataFrame({
    'order_id': ['O001', 'O002', 'O003'],
    'user_id': [1, 2, 2],
    'amount': [120, 85, 200]
})

# Como combinar? Precisamos vincular por user_id
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 o exemplo. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

(2) A Solução: mesclagem em Uma Única Linha

▶ 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 o exemplo. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: Merge básico (Dificuldade ⭐)

PYTHON
import pandas as pd

users = pd.DataFrame({
    'user_id': [1, 2, 3, 4],
    'name': ['Alice', 'Bob', 'Charlie', 'Carol']
})

orders = pd.DataFrame({
    'order_id': ['O001', 'O002', 'O003'],
    'user_id': [1, 2, 2],
    'amount': [120, 85, 200]
})

# Inner join (padrão) — apenas user_ids que correspondem
result = pd.merge(users, orders, on='user_id')
print(result)
#    user_id     name order_id  amount
# 0        1    Alice     O001     120
# 1        2      Bob     O002      85
# 2        2      Bob     O003     200
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 o exemplo. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

3. Os 4 Tipos de Junção

(1) Diagrama Mermaid

100%
graph TB
    subgraph Inner["inner — manter apenas correspondências"]
        I1["user_id 1: Alice+O001"]
        I2["user_id 2: Bob+O002"]
        I3["user_id 2: Bob+O003"]
    end
    subgraph Left["left — manter todas as linhas da esquerda"]
        L1["user_id 1: Alice+O001"]
        L2["user_id 2: Bob+O002"]
        L3["user_id 2: Bob+O003"]
        L4["user_id 3: Charlie+NaN"]
        L5["user_id 4: Carol+NaN"]
    end
    subgraph Right["right — manter todas as linhas da direita"]
        R1["user_id 1: Alice+O001"]
        R2["user_id 2: Bob+O002"]
        R3["user_id 2: Bob+O003"]
    end
    subgraph Outer["outer — manter todas as linhas de ambos os lados"]
        O1["user_id 1: Alice+O001"]
        O2["user_id 2: Bob+O002"]
        O3["user_id 2: Bob+O003"]
        O4["user_id 3: Charlie+NaN"]
        O5["user_id 4: Carol+NaN"]
    end
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 ligeiramente dependendo da versão do pandas.

(2) Comparação dos 4 Tipos de Junção

Tipo como Tabela esquerda sem correspondência Tabela direita sem correspondência Contagem de linhas
inner 'inner' Descartadas Descartadas ≤mínimo(esquerda, direita)
left 'left' Mantidas (preenchidas com NaN) Descartadas = linhas da esquerda × correspondências
right 'right' Descartadas Mantidas (preenchidas com NaN) = linhas da direita × correspondências
outer 'outer' Mantidas (preenchidas com NaN) Mantidas (preenchidas com NaN) ≥máximo(esquerda, direita)

▶ 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 acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: Comparação dos 4 tipos de junção (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

left = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Charlie']
})

right = pd.DataFrame({
    'id': [2, 3, 4],
    'score': [85, 92, 78]
})

# Inner — somente id 2, 3 (ambas as tabelas os têm)
print("INNER:")
print(pd.merge(left, right, on='id', how='inner'))
#    id    name  score
# 0   2     Bob     85
# 1   3 Charlie     92

# Left — todas as linhas da esquerda, direita preenche com NaN onde não há correspondência
print("\nLEFT:")
print(pd.merge(left, right, on='id', how='left'))
#    id     name  score
# 0   1    Alice    NaN  ← sem correspondência na direita
# 1   2      Bob   85.0
# 2   3  Charlie   92.0

# Right — todas as linhas da direita
print("\nRIGHT:")
print(pd.merge(left, right, on='id', how='right'))
#    id    name  score
# 0   2     Bob     85
# 1   3 Charlie     92
# 2   4    NaN     78  ← sem correspondência na esquerda

# Outer — todas as linhas de ambos os lados
print("\nOUTER:")
print(pd.merge(left, right, on='id', how='outer'))
#    id     name  score
# 0   1    Alice    NaN
# 1   2      Bob   85.0
# 2   3  Charlie   92.0
# 3   4     NaN    78.0
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 ligeiramente dependendo da versão do pandas.

4. Merges com Múltiplas Chaves e Nomes de Colunas Diferentes

(1) Merge com Múltiplas Chaves

▶ 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 acompanhe. Os valores reais podem variar ligeramente dependendo da versão do pandas.

: Merge com múltiplas chaves (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

sales = pd.DataFrame({
    'region': ['North', 'North', 'South', 'South'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing'],
    'revenue': [5000, 800, 2000, 600]
})

targets = pd.DataFrame({
    'region': ['North', 'North', 'South', 'South'],
    'category': ['Electronics', 'Clothing', 'Electronics', 'Clothing'],
    'target': [4500, 1000, 2500, 500]
})

# Merge em múltiplas chaves
result = pd.merge(sales, targets, on=['region', 'category'])
print(result)
#   region    category  revenue  target
# 0  North  Electronics     5000    4500
# 1  North     Clothing      800    1000
# 2  South  Electronics     2000    2500
# 3  South     Clothing      600     500

# Calcular taxa de cumprimento
result['achievement'] = (result['revenue'] / result['target'] * 100).round(1)
print(result[['region', 'category', 'achievement']])
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 acompanhe. Os valores reais podem variar ligeramente dependendo da versão do pandas.

(2) Merge com Nomes de Colunas Diferentes

▶ 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 acompanhe. Os valores reais podem variar ligeramente dependendo da versão do pandas.

: left_on/right_on (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

employees = pd.DataFrame({
    'emp_id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Charlie']
})

salaries = pd.DataFrame({
    'employee_id': [1, 2, 3],
    'salary': [75000, 92000, 68000]
})

# Nomes de colunas diferem: emp_id vs employee_id
result = pd.merge(
    employees, salaries,
    left_on='emp_id', right_on='employee_id',
    how='inner'
)
print(result)
#    emp_id     name  employee_id  salary
# 0       1    Alice            1   75000
# 1       2      Bob            2   92000
# 2       3  Charlie            3   68000

# Remover coluna redundante
result = result.drop(columns='employee_id')
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 acompanhe. Os valores reais podem variar ligeramente dependendo da versão do pandas.

5. sufixos e indicador

(1) Lidando com Conflitos de Nomes de Colunas

▶ 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 acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: sufixos para nomes de colunas duplicados (Dificuldade ⭐)

PYTHON
import pandas as pd

df1 = pd.DataFrame({
    'id': [1, 2],
    'value': [100, 200]
})

df2 = pd.DataFrame({
    'id': [1, 2],
    'value': [300, 400]
})

# Sufixos padrão: _x e _y
result = pd.merge(df1, df2, on='id')
print(result)
#    id  value_x  value_y
# 0   1      100      300
# 1   2      200      400

# Sufixos personalizados
result2 = pd.merge(df1, df2, on='id', suffixes=('_esquerdo', '_direito'))
print(result2)
#    id  value_esquerdo  value_direito
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 ligeiramente dependendo da versão do pandas.

(2) indicador para Diagnosticar Fontes da Junçã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 acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

: indicador para rastrear origens das linhas (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

left = pd.DataFrame({'id': [1, 2, 3], 'name': ['Alice', 'Bob', 'Charlie']})
right = pd.DataFrame({'id': [2, 3, 4], 'score': [85, 92, 78]})

# Adiciona a coluna _merge para ver de onde veio cada linha
result = pd.merge(left, right, on='id', how='outer', indicator=True)
print(result)
#    id     name  score      _merge
# 0   1    Alice    NaN   left_only
# 1   2      Bob   85.0        both
# 2   3  Charlie   92.0        both
# 3   4     NaN    78.0  right_only

# Filtrar pela fonte da junção
only_left = result[result['_merge'] == 'left_only']
print(f"Somente na tabela esquerda: {len(only_left)} linhas")  # 1 (Alice)

# Validar a integridade dos dados — encontrar registros não combinados
unmatched = result[result['_merge'] != 'both']
print(f"Registros não combinados: {len(unmatched)}")  # 2
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 ligeiramente dependendo da versão do pandas.

6. Validar e Cross Join

(1) Validar para Verificar Relações de Merge

▶ 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 acompanhe. Os valores reais podem variar ligeramente dependendo da versão do pandas.

: validação (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

users = pd.DataFrame({'user_id': [1, 2, 3], 'name': ['Alice', 'Bob', 'Charlie']})
orders = pd.DataFrame({'order_id': ['O1', 'O2', 'O3'], 'user_id': [1, 2, 2]})

# Validar: cada usuário deve ter no máximo um pedido (1:1)
# Isso FALHARÁ porque o usuário 2 tem 2 pedidos
try:
    result = pd.merge(users, orders, on='user_id', validate='1:1')
except Exception as e:
    print(f"Falha na validação: {e}")

# Validar: cada usuário pode ter muitos pedidos (1:m) — passa
result = pd.merge(users, orders, on='user_id', validate='1:m')
print(result)  # OK

# Tipos de validação: '1:1', '1:m', 'm:1', 'm:m'
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) Cross Join

▶ 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 acompanhe. Os valores reais podem variar ligeramente dependendo da versão do pandas.

: cross join (Dificuldade ⭐)

PYTHON
import pandas as pd

colors = pd.DataFrame({'color': ['Red', 'Blue']})
sizes = pd.DataFrame({'size': ['S', 'M', 'L']})

# Toda combinação (produto cartesiano)
result = pd.merge(colors, sizes, how='cross')
print(result)
#   color size
# 0   Red    S
# 1   Red    M
# 2   Red    L
# 3  Blue    S
# 4  Blue    M
# 5  Blue    L
# 6 linhas = 2 cores × 3 tamanhos
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.

7. mesclagem vs join

Recurso mesclagem join
Estilo de chamada pd.merge(df1, df2) df1.join(df2)
Chave de junção padrão Coluna especificada por on Índice
Junção de múltiplas colunas ✅ on=['a','b'] ❌ Apenas índice
Tipos de junção inner/left/right/outer left (padrão)
Flexibilidade Alta Baixa
Melhor para Junções de uso geral Alinhamento de índices

▶ Exemplo

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

: atalho de join (Dificuldade ⭐)

PYTHON
import pandas as pd

df1 = pd.DataFrame({'A': [1, 2, 3]}, index=['x', 'y', 'z'])
df2 = pd.DataFrame({'B': [4, 5]}, index=['x', 'y'])

# join usa o Índice por padrão
result = df1.join(df2)  # how='left' por padrão
print(result)
#    A    B
# x  1  4.0
# y  2  5.0
# z  3  NaN  ← a junção left mantém todas as linhas da esquerda

# join com parâmetro how
result2 = df1.join(df2, how='inner')
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não possui pandas pré-instalado. Instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da versão do pandas.

8. Exemplo Completo: Análise de Junção de Três Tabelas

▶ Exemplo

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

: Fluxo de trabalho de mesclagem de três tabelas (Dificuldade ⭐⭐⭐)

PYTHON
import pandas as pd

# ============================================
# Exemplo abrangente: mesclagem de 3 tabelas
# usuários + pedidos + produtos → análise completa
# ============================================

# 1. Tabela de usuários
users = pd.DataFrame({
    'user_id': [1, 2, 3, 4, 5],
    'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
    'region': ['Norte', 'Sul', 'Leste', 'Norte', 'Oeste']
})

# 2. Tabela de pedidos
orders = pd.DataFrame({
    'order_id': ['O001', 'O002', 'O003', 'O004', 'O005', 'O006'],
    'user_id': [1, 2, 2, 3, 1, 5],
    'product_id': ['P01', 'P02', 'P03', 'P01', 'P04', 'P02'],
    'quantity': [2, 1, 3, 1, 5, 2]
})

# 3. Tabela de produtos
products = pd.DataFrame({
    'product_id': ['P01', 'P02', 'P03', 'P04', 'P05'],
    'product_name': ['Laptop', 'Phone', 'Tablet', 'Mouse', 'Keyboard'],
    'price': [999, 699, 349, 29, 79]
})

# Passo 1: pedidos + produtos → detalhes do pedido com preço
order_details = pd.merge(orders, products, on='product_id', how='left')
order_details['total'] = order_details['quantity'] * order_details['price']

# Passo 2: order_details + usuários → visão completa
full = pd.merge(order_details, users, on='user_id', how='left')

# Passo 3: Análise por região
region_sales = full.groupby('region')['total'].sum().sort_values(ascending=False)
print("=== Vendas por Região ===")
print(region_sales)

# Passo 4: Melhores clientes
top_customers = full.groupby('name')['total'].sum().sort_values(ascending=False)
print("\n=== Melhores Clientes ===")
print(top_customers)

# Passo 5: Produtos sem correspondência (nos produtos, mas nunca pedidos)
unmatched = pd.merge(
    products, orders[['product_id']].drop_duplicates(),
    on='product_id', how='left', indicator=True
)
never_ordered = unmatched[unmatched['_merge'] == 'left_only']
print(f"\n=== Produtos Nunca Pedidos ===")
print(never_ordered[['product_id', 'product_name']])
TEXT 📖 Somente leitura
> **Saída:** Execute em um ambiente local do Python (pandas 2.x). O servidor Piston não tem o pandas pré-instalado. Por favor, instale localmente (`pip install pandas`) e siga along. Os valores reais podem variar ligeramente dependendo da versão do pandas.

❓ Perguntas Frequentes

P Devo usar inner ou left?
R Como padrão, use inner (mantém apenas as linhas correspondentes, resultando em dados limpos). Use left quando precisar de todas as linhas da tabela da esquerda (por exemplo, "todos os usuários, independentemente de terem pedidos"). right é raramente usada (basta trocar as tabelas e usar left). Use outer para encontrar diferenças ("quais usuários não têm pedidos + quais pedidos não têm usuário"). Em 80% dos cenários do dia a dia, inner é a escolha correta.
P E se os nomes das colunas-chave forem diferentes entre as tabelas?
R Use left_on e right_on para especificar a coluna-chave em cada tabela separadamente. Por exemplo, pd.merge(a, b, left_on='emp_id', right_on='employee_id'). Após a junção, ambas as colunas são mantidas — use drop para remover a redundante. Se uma chave for um Índice, use left_index=True / right_index=True.
P Como lidar com conflitos de sufixos?
R Quando ambas as tabelas têm uma coluna com o mesmo nome (além da chave), mesclagem automaticamente anexa os sufixos _x e _y. Use suffixes=('_left','_right') para personalizá-los. Uma boa prática é renomear as colunas antes da junção para evitar ambiguidade: df.rename(columns={'value': 'value_a'}).
P Qual é a diferença entre mesclagem e join?
R mesclagem é mais versátil — ela suporta junções baseadas em colunas, junções por múltiplas chaves e todos os 4 tipos de junção. join é mais concisa — ela faz junção no Índice por padrão e assume uma junção à esquerda. Use mesclagem quando precisar de junções por múltiplas colunas; use join para simples alinhamento de Índice. Em geral, prefira mesclagem por sua completude e trate join como um atalho.
P Como verificar se o resultado da junção está correto?
R Uma verificação em três etapas: ① Compare as contagens de linhas antes e depois da junção (inner deve ser ≤ min, left deve ser igual às linhas da esquerda × correspondências); ② Use indicator=True para inspecionar a origem de cada linha (both/left_only/right_only); ③ Use validate='1:1' ou '1:m' para verificar a relação esperada — ela gera um erro se for violada.
P E se mesclagem causar uma explosão no número de linhas?
R Uma explosão de linhas indica uma junção m:m (muitos-para-muitos) — quando cada chave na tabela da direita corresponde a N linhas, o resultado é igual às linhas da esquerda × N. Solução: desduplicar ou agregar (groupby + agg) a tabela da direita antes da junção para reduzir as linhas correspondentes. Use validate='m:1' para detectar isso antecipadamente.
P Quando devo usar cross join?
R cross join produz um produto cartesiano (cada linha × cada linha), com contagem de linhas = linhas da esquerda × linhas da direita. Use-a apenas para gerar combinações (por exemplo, cores × tamanhos = todas as variantes de SKU). Nunca use cross join em tabelas grandes — 1000 × 1000 = 1 milhão de linhas!

📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Crie uma tabela de alunos e uma tabela de notas (compartilhando student_id). Realize inner/left/outer joins e observe como a contagem de linhas muda.
  2. Intermediário (Dificuldade ⭐⭐): Crie uma tabela de departamentos (dept_id/dept_name) e uma tabela de funcionários (emp_id/dept_id/salary). Mescle-as, calcule o salário médio por departamento e use o indicador para encontrar departamentos sem funcionários.
  3. Desafio (Dificuldade ⭐⭐⭐): Simule três tabelas (usuários/pedidos/produtos) e complete o seguinte: inner join para uní-las → calcular o gasto total por usuário → left join para encontrar usuários com gasto zero → validar para verificar relacionamentos → indicador para diagnosticar origens.

← Previous: GroupBy and Aggregation · Next: Concat and Append →

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%