Combinar dados de múltiplas fontes é uma das operações mais comuns em análise. pd.merge() é o equivalente do JOIN do SQL no Pandas — e funciona com a mesma lógica de chaves e tipos de junção.

merge(): combinando por chave

import pandas as pd

pedidos = pd.DataFrame({
    "id_pedido": [1, 2, 3, 4],
    "id_cliente": [10, 20, 10, 30],
    "valor": [1500, 800, 2200, 500]
})

clientes = pd.DataFrame({
    "id_cliente": [10, 20, 40],
    "nome": ["Ana", "Bruno", "Carlos"],
    "cidade": ["SP", "RJ", "BH"]
})

# Inner join (padrão): apenas registros com correspondência em ambos
resultado = pd.merge(pedidos, clientes, on="id_cliente")

# Left join: todos de pedidos + correspondentes de clientes
resultado = pd.merge(pedidos, clientes, on="id_cliente", how="left")

# Right join: todos de clientes + correspondentes de pedidos
resultado = pd.merge(pedidos, clientes, on="id_cliente", how="right")

# Outer join: todos de ambos, nulos onde não há correspondência
resultado = pd.merge(pedidos, clientes, on="id_cliente", how="outer")

Merge com chaves de nomes diferentes

# Se as colunas chave têm nomes diferentes nas duas tabelas:
resultado = pd.merge(
    pedidos, clientes,
    left_on="id_cliente",
    right_on="codigo_cliente"
)

Merge por múltiplas chaves

# Junção por mais de uma coluna:
resultado = pd.merge(
    df1, df2,
    on=["ano", "mes", "produto"]
)

Sufixos para colunas duplicadas

# Quando as duas tabelas têm colunas com o mesmo nome (além da chave):
resultado = pd.merge(
    pedidos, clientes,
    on="id_cliente",
    suffixes=("_pedido", "_cliente")
)
# Colunas como "valor_pedido" e "valor_cliente" em vez de "valor_x" e "valor_y"

concat(): empilhando tabelas verticalmente

jan = pd.read_excel("vendas_jan.xlsx")
fev = pd.read_excel("vendas_fev.xlsx")
mar = pd.read_excel("vendas_mar.xlsx")

# Empilhar os três DataFrames:
total = pd.concat([jan, fev, mar], ignore_index=True)

# ignore_index=True cria um índice novo sequencial (evita índices duplicados)

Consolidando múltiplos arquivos de uma pasta

import glob

arquivos = glob.glob("vendas_*.xlsx")
dfs = [pd.read_excel(arq) for arq in arquivos]
total = pd.concat(dfs, ignore_index=True)
print(f"Total de linhas: {len(total)}")

Verificando o resultado do merge

# Quantas linhas antes e depois:
print(f"Pedidos: {len(pedidos)}")
print(f"Após merge: {len(resultado)}")

# Linhas que não tiveram correspondência (left join com nulos):
sem_cliente = resultado[resultado["nome"].isnull()]
print(f"Pedidos sem cliente: {len(sem_cliente)}")

Perguntas frequentes

Por que o merge duplicou as linhas?

Se a coluna chave na tabela da direita não for única (tem duplicatas), cada linha da esquerda se combina com todas as correspondências da direita — causando multiplicação. Verifique com df["chave"].duplicated().sum() antes do merge.

merge() vs join()?

df.join() é um atalho para merge que une pelo índice por padrão. Para a maioria dos casos práticos, pd.merge() é mais explícito e flexível.