Concatenação e junções
Juntar linhas com concat e relacionar tabelas com merge e join, verificando cardinalidade.
Há dois pedidos diferentes. Podemos juntar vendas de janeiro às vendas de fevereiro, conservando as mesmas colunas. Ou podemos acrescentar o preço a cada venda através do código do produto. O primeiro usa concatenação; o segundo usa uma junção.
Concatenar linhas ou colunas
vendas = pd.concat([janeiro, fevereiro], ignore_index=True)
Com axis=0, pandas acrescenta linhas e alinha as colunas pelo nome. ignore_index=True cria um índice consecutivo. Se uma coluna só existe num dos lados, as linhas do outro ficam com valores em falta nessa coluna. join="inner" conserva apenas as colunas comuns.
Com axis=1, acrescenta colunas e alinha as linhas pelo índice. Não associa automaticamente a primeira linha de uma tabela à primeira da outra. Para uma relação por código de produto, usa merge.
Slides antigos podem usar DataFrame.append. Esse método foi removido no pandas 2.0. O equivalente para juntar tabelas é pd.concat. Para muitas linhas, recolhe-as primeiro e concatena uma vez, em vez de reconstruir a tabela a cada iteração.
Conservar a origem e verificar o índice
keys acrescenta um nível ao índice, útil para conservar a origem de cada bloco. names dá nomes a esses níveis. Continua a existir um índice por linha dentro de cada origem.
janeiro = pd.DataFrame({"unidades": [2, 3]})
fevereiro = pd.DataFrame({"unidades": [4]})
por_mes = pd.concat([janeiro, fevereiro], keys=["jan", "fev"], names=["mes", "linha"])
print(por_mes.loc["jan", "unidades"].to_list()) # [2, 3]
verify_integrity=True rejeita rótulos repetidos no eixo concatenado. Sem keys, os índices 0 dos dois blocos colidem. Com keys, os pares ("jan", 0) e ("fev", 0) são distintos. Esta verificação é sobre o índice, não sobre valores duplicados numa coluna de identificadores. Com ignore_index=True, o novo índice consecutivo não conserva a colisão original.
Relacionar por uma chave
import pandas as pd
vendas = pd.DataFrame({"codigo": ["A", "B", "A", "C"], "quantidade": [2, 3, 5, 4]})
produtos = pd.DataFrame({"codigo": ["A", "B"], "preco": [1.5, 1.2]})
resultado = vendas.merge(produtos, on="codigo", how="left", validate="many_to_one", indicator=True)
print(resultado.to_string(index=False))
print("linhas sem preço:", resultado["preco"].isna().sum())Dados de entrada
As duas vendas de A recebem 1,50, a venda de B recebe 1,20 e C fica sem preço. A junção à esquerda conserva as quatro vendas. indicator=True identifica as linhas com correspondência como both e C como left_only.
validate="many_to_one" exige que o código seja único em produtos; pode repetir-se em vendas. Esta verificação protege o significado de uma linha por venda.
O tipo de junção
how | Chaves conservadas |
|---|---|
inner | Presentes nos dois lados |
left | Todas as do lado esquerdo |
right | Todas as do lado direito |
outer | Presentes em pelo menos um lado |
cross | Todos os pares, sem chave |
Uma junção interna excluiria a venda de C. Isso pode diminuir a faturação ou a contagem sem qualquer erro de execução. Uma junção externa incluiria também produtos sem vendas.
Se os nomes das chaves diferem, usa left_on="produto" e right_on="codigo". Para colunas com o mesmo nome que não sejam chaves, suffixes=("_venda", "_catalogo") distingue as origens.
Repetições multiplicam linhas
Se A aparece duas vezes à esquerda e três vezes à direita, a junção cria seis pares para A. Não escolhe um dos preços. Uma relação muitos-para-muitos pode ser válida, mas exige que esse produto de correspondências seja o resultado pretendido.
validate aceita one_to_one, one_to_many e many_to_one. Confere também o número de linhas, chaves sem correspondência e totais antes e depois. pandas pode relacionar chaves nulas entre si, o que difere do comportamento habitual de NULL em SQL.
join usa o índice
vendas.join(produtos.set_index("codigo"), on="codigo") procura o código da venda no índice de produtos. join é útil quando o índice representa a chave. Define essa relação explicitamente; um índice de posições não é um código de produto.
Exercícios
Contar correspondências
Uma chave A aparece duas vezes à esquerda e três à direita. Quantas linhas de A cria uma junção pela chave?
Primeira pista
Cada linha da esquerda combina com todas as correspondências da direita.
Mais uma pista
Ver solução
Há 2 × 3 = 6 linhas. Uma relação muitos-para-muitos pode alterar contagens e somas.
Erros frequentes
Somar 2 + 3 ou escolher apenas uma das linhas da direita.
Conservar vendas sem preço
Queres conservar todas as vendas e detetar produtos sem preço num catálogo. Que junção escolhes?
Primeira pista
Mais uma pista
As linhas sem correspondência precisam de ficar visíveis.
Ver solução
Usa left e valida a relação many_to_one se o catálogo deve ter uma linha por produto. Confere nulos e contagem depois.
- left, com vendas à esquerda. Conserva todas as vendas e mostra preço ausente quando não há correspondência.
- inner. Elimina vendas sem produto correspondente no catálogo.
- cross. Cria todos os pares de venda e produto, ignorando a chave.
Erros frequentes
Eliminar as vendas desconhecidas e apresentar o total restante como total completo.