Pandas: Lidando com Dados Duplicados
Última atualização: 2026-08-26
Fusões de dados, execuções repetidas de coleta, falhas de sistema — dados duplicados estão em todo lugar. Um único registro de cliente aparecendo 3 vezes infla suas estatísticas em 3x. As funções duplicated / drop_duplicates do Pandas permitem detectar e limpar duplicatas com precisão, enquanto os parâmetros subset + keep oferecem controle flexível sobre a granularidade. Esta seção aborda o fluxo de trabalho completo, desde a detecção até a remoção.
1. O Que Você Aprenderá
- ❶ Detectando duplicatas com
duplicated - ❷ Removendo duplicatas com
drop_duplicates - ❸ Deduplicação baseada em colunas com
subset - ❹ Estratégias de retenção com
keep - ❺ Deduplicação em múltiplas colunas e estratégias do mundo real
2. Pedidos Duplicados da Alice
(1) O Problema: Falha no Sistema Causa Pedidos Duplicados
O sistema da cafeteria da Alice apresentou uma falha durante um horário de pico, e 3 pedidos foram enviados duas vezes:
import pandas as pd
orders = pd.DataFrame({
'order_id': ['O001', 'O001', 'O002', 'O003', 'O003', 'O003', 'O004'],
'customer': ['Alice', 'Alice', 'Bob', 'Charlie', 'Charlie', 'Charlie', 'Carol'],
'drink': ['Latte', 'Latte', 'Americano', 'Mocha', 'Mocha', 'Mocha', 'Espresso'],
'price': [4.50, 4.50, 3.00, 5.50, 5.50, 5.50, 2.50]
})
print(f"Total rows: {len(orders)}")
print(f"Duplicates: {orders.duplicated().sum()}")
# Total rows: 7, Duplicates: 3
> **Saída:** Execute isto em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
(2) A Solução: Limpeza em Uma Única Linha com drop_duplicates
▶ Exemplo
> **Saída:** Execute isto em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Desduplicação básica (Dificuldade ⭐)
import pandas as pd
orders = pd.DataFrame({
'order_id': ['O001', 'O001', 'O002', 'O003', 'O003', 'O003', 'O004'],
'customer': ['Alice', 'Alice', 'Bob', 'Charlie', 'Charlie', 'Charlie', 'Carol'],
'drink': ['Latte', 'Latte', 'Americano', 'Mocha', 'Mocha', 'Mocha', 'Espresso'],
'price': [4.50, 4.50, 3.00, 5.50, 5.50, 5.50, 2.50]
})
# Remove linhas duplicadas exatas
clean = orders.drop_duplicates()
print(clean)
# order_id customer drink price
# 0 O001 Alice Latte 4.5
# 2 O002 Bob Americano 3.0
# 3 O003 Charlie Mocha 5.5
# 6 O004 Carol Espresso 2.5
print(f"Before: {len(orders)} → After: {len(clean)}")
# Before: 7 → After: 4
> **Saída:** Execute isto em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
3. Detectando Duplicatas com duplicated
(1) Detecção Básica
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instale — instale-o localmente (`pip install pandas`) e siga os passos. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Detectando duplicatas com duplicated (Dificuldade ⭐)
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
'age': [28, 34, 28, 25, 35]
})
# Marca as duplicatas (primeira ocorrência = False, subsequentes = True)
print(df.duplicated())
# 0 False ← primeira Alice (mantém)
# 1 False ← primeiro Bob (mantém)
# 2 True ← segunda Alice (duplicata!)
# 3 False ← primeira Charlie (mantém)
# 4 True ← Bob, mas idade=35 (NÃO é duplicata — a linha é diferente)
# Filtra para ver apenas as linhas duplicadas
print(df[df.duplicated()])
# name age
# 2 Alice 28
# Conta as duplicatas
print(f"Linhas duplicadas: {df.duplicated().sum()}") # 1
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instale — instale-o localmente (`pip install pandas`) e siga os passos. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
(2) O Parâmetro keep Controla a Lógica de Marcação
| Valor do keep | Comportamento | Primeira Duplicata | Última Duplicata |
|---|---|---|---|
| 'first' | Mantém a primeira ocorrência | Marcado False | Marcado True |
| 'last' | Mantém a última ocorrência | Marcado True | Marcado False |
| False | Marca todas as duplicatas | Marcado True | Marcado True |
▶ Exemplo
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instale — instale-o localmente (`pip install pandas`) e siga os passos. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Comparando o parâmetro keep (Dificuldade ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Alice', 'Alice', 'Bob'],
'score': [85, 92, 85, 85, 92]
})
# keep='first' (padrão) — a primeira ocorrência NÃO é duplicata
print("keep='first':", df.duplicated(keep='first').tolist())
# [False, False, True, True, True]
# keep='last' — a última ocorrência NÃO é duplicata
print("keep='last':", df.duplicated(keep='last').tolist())
# [True, True, True, False, False]
# keep=False — TODAS as duplicatas são marcadas como True
print("keep=False:", df.duplicated(keep=False).tolist())
# [True, True, True, True, True]
> **Saída:** Execute em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instale — instale-o localmente (`pip install pandas`) e siga os passos. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
4. Removendo Duplicatas com drop_duplicates
(1) Remoção Básica
▶ Exemplo
> **Saída:** Execute isto em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instale — instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: Removendo duplicatas com drop_duplicates (Dificuldade ⭐)
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice'],
'age': [28, 34, 28, 25, 28],
'city': ['NYC', 'LA', 'NYC', 'Chicago', 'Boston'] # cidade diferente para a última Alice
})
# Remove linhas completamente duplicadas
print(df.drop_duplicates())
# name age city
# 0 Alice 28 NYC
# 1 Bob 34 LA
# 3 Charlie 25 Chicago
# 4 Alice 28 Boston ← mantida (city é diferente da linha 0)
# Com o parâmetro keep
print(df.drop_duplicates(keep='last'))
# name age city
# 1 Bob 34 LA
# 3 Charlie 25 Chicago
# 4 Alice 28 Boston ← última Alice mantida
# Remove TODAS as duplicatas (mantém apenas linhas únicas)
print(df.drop_duplicates(keep=False))
# name age city
# 1 Bob 34 LA
# 3 Charlie 25 Chicago
# Todas as linhas de Alice removidas (porque existem múltiplas)
> **Saída:** Execute isto em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instale — instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
(2) inplace e Resetando o Índice
▶ Exemplo
> **Saída:** Execute isto em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instale — instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
: inplace e reset_index (Dificuldade ⭐)
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Alice', 'Charlie'],
'score': [85, 92, 85, 78]
})
# Método 1: atribuir de volta (recomendado)
df = df.drop_duplicates().reset_index(drop=True)
print(df)
# name score
# 0 Alice 85
# 1 Bob 92
# 2 Charlie 78
# Método 2: inplace
# df.drop_duplicates(inplace=True)
# df.reset_index(inplace=True, drop=True)
> **Saída:** Execute isto em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instale — instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.
5. Deduplicação Baseada em Colunas com Subconjunto
(1) Olhando Apenas para Colunas-Chave
▶ Exemplo
> **Saída:** Execute 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.
: Deduplicação baseada em colunas com subconjunto (Dificuldade ⭐⭐)
import pandas as pd
df = pd.DataFrame({
'student_id': ['S001', 'S001', 'S002', 'S003', 'S002'],
'name': ['Alice', 'Alice Smith', 'Bob', 'Charlie', 'Robert Bob'],
'math_score': [85, 85, 92, 78, 92],
'attempt': [1, 2, 1, 1, 2]
})
# Linha completa duplicada: nenhuma (coluna 'name' difere)
print(f"Duplicatas de linha completa: {df.duplicated().sum()}") # 0
# Mas student_id deveria ser único!
print(f"Duplicatas em student_id: {df.duplicated(subset='student_id').sum()}") # 2
# Remover duplicatas baseado apenas em student_id
clean = df.drop_duplicates(subset='student_id', keep='first')
print(clean)
# student_id name math_score attempt
# 0 S001 Alice 85 1
# 2 S002 Bob 92 1
# 3 S003 Charlie 78 1
> **Saída:** Execute 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) Deduplicação por Combinação de Múltiplas Colunas
▶ Exemplo
> **Saída:** Execute 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.
: Deduplicação por combinação de múltiplas colunas (Dificuldade ⭐⭐)
import pandas as pd
# O mesmo aluno pode ter múltiplas tentativas de teste
# Mas o mesmo aluno + mesma disciplina deve ser único
df = pd.DataFrame({
'student_id': ['S001', 'S001', 'S001', 'S002', 'S002'],
'subject': ['Math', 'English', 'Math', 'Math', 'English'],
'score': [85, 90, 88, 92, 87],
'attempt_date': ['2024-01-10', '2024-01-10', '2024-02-15', '2024-01-12', '2024-01-12']
})
# Duplicata: combinação student_id + subject
dupes = df.duplicated(subset=['student_id', 'subject'], keep=False)
print("Todas as linhas envolvidas em duplicatas:")
print(df[dupes])
# S001 + Math aparece duas vezes (linhas 0 e 2)
# Manter a tentativa mais recente por aluno + disciplina
clean = df.drop_duplicates(subset=['student_id', 'subject'], keep='last')
print("\nApós deduplicação (manter última tentativa):")
print(clean)
# student_id subject score attempt_date
# 0 S001 English 90 2024-01-10
# 2 S001 Math 88 2024-02-15 ← mais recente
# 3 S002 Math 92 2024-01-12
# 4 S002 English 87 2024-01-12
> **Saída:** Execute 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.
6. Estratégias para Lidar com Dados Duplicados
(1) Tabela de Decisão por Cenário
| Cenário | Estratégia | Código |
|---|---|---|
| Linhas totalmente duplicadas | drop_duplicates() | df.drop_duplicates() |
| Colunas-chave duplicadas | Desduplicar com subset | df.drop_duplicates(subset=['id']) |
| Manter o mais recente | keep='last' | df.drop_duplicates(subset=['id'], keep='last') |
| Necessita revisão manual | Marcar sem deletar | df[df.duplicated(keep=False)] |
| Agregar em vez de deletar | groupby + agg | df.groupby('id').agg({'val': 'mean'}) |
▶ Exemplo
> **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.
: Agregando em vez de deletando (Dificuldade ⭐⭐⭐)
import pandas as pd
# Múltiplas leituras para o mesmo sensor — média em vez de exclusão
df = pd.DataFrame({
'sensor_id': ['T01', 'T01', 'T01', 'T02', 'T02'],
'location': ['Lab A', 'Lab A', 'Lab A', 'Lab B', 'Lab B'],
'temperature': [22.5, 22.7, 22.3, 18.1, 18.3],
'humidity': [45, 47, 43, 55, 57]
})
# Em vez de deletar, agregar: manter a média
agg = df.groupby('sensor_id').agg({
'location': 'first',
'temperature': 'mean',
'humidity': 'mean'
}).reset_index()
print(agg)
# sensor_id location temperature humidity
# 0 T01 Lab A 22.500 45.0
# 1 T02 Lab B 18.200 56.0
> **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.
(2) Fluxograma de Decisão para Desduplicação
graph TB
Q["Encontrou duplicatas?"] -->|Não| DONE["✅ Dados limpos"]
Q -->|Sim| TYPE{"Linha inteira ou coluna-chave?"}
TYPE -->|Linha inteira| SIMPLE["drop_duplicates()"]
TYPE -->|Coluna-chave| SUBSET["drop_duplicates(subset=['id'])"]
SIMPLE --> WHICH["keep='first'/'last'/False?"]
SUBSET --> WHICH
WHICH -->|Manter primeiro| FIRST["keep='first'"]
WHICH -->|Manter último| LAST["keep='last'"]
WHICH -->|Necessário todos para revisão| REVIEW["duplicated(keep=False) → manual"]
WHICH -->|Valores diferentes| AGG["groupby().agg() → merge"]
> **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. Exemplo Completo: Fluxo de Trabalho de Desduplicação de Clientes
▶ Exemplo
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale-o localmente (`pip install pandas`) e siga adiante. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.
: Fluxo de trabalho completo de desduplicação de clientes (Dificuldade ⭐⭐⭐)
import pandas as pd
# ============================================
# Exemplo abrangente: Desduplicação de clientes
# com múltiplas estratégias
# ============================================
# 1. Dados brutos com vários padrões de duplicação
df = pd.DataFrame({
'email': ['alice@example.com', 'alice@example.com', 'bob@example.com',
'charlie@example.com', 'bob@example.com', 'alice@example.com',
'david@example.com'],
'nome': ['Alice', 'Alice Smith', 'Bob', 'Charlie', 'Bob Jones',
'Alice', 'David'],
'telefone': ['555-0100', '555-0100', '555-0200', '555-0300',
'555-0201', '555-0100', '555-0400'],
'data_cadastro': ['2024-01-15', '2024-02-01', '2024-01-20',
'2024-03-01', '2024-03-15', '2024-01-15',
'2024-04-01']
})
print("=== Passo 1: Detectar Duplicatas ===")
print(f"Duplicatas de linha inteira: {df.duplicated().sum()}")
print(f"Duplicatas de Email: {df.duplicated(subset='email').sum()}")
print(f"Duplicatas de Email+Telefone: {df.duplicated(subset=['email','telefone']).sum()}")
# 2. Revisar todas as linhas envolvidas em duplicatas de email
print("\n=== Passo 2: Revisar Duplicatas de Email ===")
email_dupes = df[df.duplicated(subset='email', keep=False)]
print(email_dupes.sort_values('email'))
# 3. Estratégia: manter o cadastro mais recente por email
df['data_cadastro'] = pd.to_datetime(df['data_cadastro'])
clean = df.sort_values('data_cadastro').drop_duplicates(subset='email', keep='last')
print("\n=== Passo 3: Após Desduplicação (manter o mais recente) ===")
print(clean[['email', 'nome', 'data_cadastro']])
# 4. Verificar
print(f"\nAntes: {len(df)} linhas → Depois: {len(clean)} linhas")
print(f"Emails únicos: {clean['email'].nunique()}")
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale-o localmente (`pip install pandas`) e siga adiante. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.
❓ Perguntas Frequentes
duplicated e drop_duplicates?duplicated() retorna uma Série booleana que marca as linhas duplicadas (sem excluí-las) — use-a para detecção e revisão. drop_duplicates() retorna diretamente um DataFrame deduplicado (sem modificar os dados originais). Use duplicated quando quiser inspecionar as duplicatas e drop_duplicates quando quiser limpá-las.keep='first'/'last'/False?keep='first' mantém a primeira ocorrência (o padrão — bom para dados no estilo de log). keep='last' mantém a última ocorrência (bom para cenários de atualização/sobrescrita). keep=False marca cada linha duplicada (usado para revisão, mantendo nenhuma das duplicatas). drop_duplicates(keep=False) mantém apenas as linhas que nunca foram duplicadas.subset=['email'] verifica apenas se a coluna de e-mail está duplicada, ignorando diferenças em outras colunas. subset=['email','phone'] requer que ambas as colunas correspondam simultaneamente para contar como uma duplicata. A deduplicação em coluna única pode excluir incorretamente dados legítimos (mesmo e-mail, mas informações de contato diferentes), enquanto combinações de múltiplas colunas são mais precisas, mas podem perder duplicatas variantes.drop_duplicates remover as linhas, ele mantém o índice original, deixando lacunas. Use reset_index(drop=True) para redefinir para um índice contínuo. drop=True descarta o índice antigo; caso contrário, o índice antigo se torna uma nova coluna chamada 'index'. A forma encadeada recomendada é: df.drop_duplicates().reset_index(drop=True).drop_duplicates modifica o DataFrame original?drop_duplicates retorna um novo DataFrame e deixa os dados originais inalterados. O parâmetro inplace=True pode modificá-lo no local, mas sob o modo Copy-on-Write do Pandas 3.x, a forma com atribuição é recomendada: df = df.drop_duplicates(), que possui semântica mais clara.duplicated para duplicatas exatas, mas "Alice" e "Alice Smith" não são duplicatas exatas. Estratégia: normalize primeiro, depois compare — strip() para remover espaços em branco, lower() para unificar maiúsculas/minúsculas, ou combine no prefixo do e-mail como substring. Para necessidades de correspondência difusa, use a biblioteca recordlinkage ou dedupe para deduplicação probabilística.📖 Resumo
- duplicated() marca linhas duplicadas e retorna uma Série booleana; drop_duplicates() remove duplicatas diretamente
- O parâmetro keep controla a estratégia de retenção: first (padrão) / last / False (marcar todas)
- O parâmetro subset especifica por quais colunas julgar duplicatas, suportando tanto colunas únicas quanto combinações de múltiplas colunas
- Após a remoção de duplicatas, use reset_index(drop=True) para redefinir para um índice contínuo
- Linhas totalmente duplicadas → excluir diretamente; colunas-chave duplicadas → remover duplicatas com subset; valores diferentes → agregar em vez de excluir
- Detectar e revisar primeiro (duplicated), depois decidir uma estratégia (excluir / agregar / revisão manual)
📝 Exercícios
- Básico (Dificuldade ⭐): Crie um DataFrame com 3 linhas totalmente duplicadas (8 linhas no total), conte-as com
duplicated().sum(), limpe-as comdrop_duplicates(), e compare as contagens de linhas antes e depois. - Intermediário (Dificuldade ⭐⭐): Crie um DataFrame de notas de estudantes (o mesmo estudante aparece várias vezes para a mesma disciplina), faça a deduplicação com
subset=['student_id','subject']e usekeep='last'para manter a nota mais recente. - Desafio (Dificuldade ⭐⭐⭐): Simule dados de cadastro de clientes (e-mail/nome/telefone/data_cadastro), incluindo casos onde o e-mail está duplicado mas o nome/telefone diferem. Complete o seguinte: detecte duplicatas de e-mail → revise as linhas duplicadas → ordene por data_cadastro e então faça a deduplicação com
keep='last'→ verifique a contagem de e-mails únicos.
← Previous Lesson: Handling Missing Values · Next Lesson: Data Transformation →