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.

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

1. O Que Você Aprenderá



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:

PYTHON
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
TEXT 📖 Somente leitura
> **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

TEXT 📖 Somente leitura
> **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 ⭐)

PYTHON
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
TEXT 📖 Somente leitura
> **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

TEXT 📖 Somente leitura
> **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 ⭐)

PYTHON
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
TEXT 📖 Somente leitura
> **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

TEXT 📖 Somente leitura
> **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 ⭐⭐)

PYTHON
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]
TEXT 📖 Somente leitura
> **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

TEXT 📖 Somente leitura
> **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 ⭐)

PYTHON
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)
TEXT 📖 Somente leitura
> **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

TEXT 📖 Somente leitura
> **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 ⭐)

PYTHON
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)
TEXT 📖 Somente leitura
> **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

TEXT 📖 Somente leitura
> **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 ⭐⭐)

PYTHON
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
TEXT 📖 Somente leitura
> **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

TEXT 📖 Somente leitura
> **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 ⭐⭐)

PYTHON
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
TEXT 📖 Somente leitura
> **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

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.

: Agregando em vez de deletando (Dificuldade ⭐⭐⭐)

PYTHON
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
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.

(2) Fluxograma de Decisão para Desduplicação

100%
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"]
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. Exemplo Completo: Fluxo de Trabalho de Desduplicação de Clientes

▶ 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-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 ⭐⭐⭐)

PYTHON
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()}")
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-o localmente (`pip install pandas`) e siga adiante. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.

❓ Perguntas Frequentes

P Qual é a diferença entre duplicated e drop_duplicates?
R 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.
P Como escolher entre keep='first'/'last'/False?
R 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.
P Qual é a diferença entre um subconjunto de uma única coluna e múltiplas colunas?
R 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.
P E se o índice ficar bagunçado após a deduplicação?
R Após o 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).
P Dados duplicados devem ser excluídos ou agregados?
R Depende do significado de negócio. Se as duplicatas forem erros (falha do sistema → exclua). Se as duplicatas forem medições repetidas → agregue (média/máx/último). Se não tiver certeza → marque e revise primeiro, não exclua diretamente. Princípio: a exclusão é irreversível, enquanto a agregação preserva a informação.
P O drop_duplicates modifica o DataFrame original?
R Não. O 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.
P Como encontrar linhas "quase-duplicadas"?
R Use 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


📝 Exercícios

  1. Básico (Dificuldade ⭐): Crie um DataFrame com 3 linhas totalmente duplicadas (8 linhas no total), conte-as com duplicated().sum(), limpe-as com drop_duplicates(), e compare as contagens de linhas antes e depois.
  2. 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 use keep='last' para manter a nota mais recente.
  3. 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 →

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%