Resolver duplicatas e nulos

Concluído(a)

Problemas de qualidade de dados, como registros duplicados e valores nulos, podem comprometer seus processos de análise e downstream. Se as duplicatas surgem de cargas de dados simultâneas ou nulos aparecem devido a dados de origem incompletos, resolver esses problemas é uma responsabilidade principal para os engenheiros de dados que trabalham no Azure Databricks.

Nesta unidade, você aprenderá a identificar e resolver valores duplicados, ausentes e nulos usando abordagens SQL e PySpark.

Identificar registros duplicados

Antes de remover duplicatas, você precisa encontrá-las. Normalmente, as duplicatas ocorrem quando o mesmo registro aparece várias vezes em uma tabela, geralmente devido a problemas de integração de dados, ingestão repetida ou operações de gravação simultâneas.

Diagrama explicando como identificar registros duplicados.

Usar GROUP BY e HAVING para localizar duplicatas

A maneira mais simples de identificar duplicatas é agrupando registros e contando ocorrências. A HAVING cláusula filtra os resultados agrupados para mostrar apenas valores que aparecem mais de uma vez.

SELECT 
    customer_id, 
    email, 
    COUNT(*) AS occurrence_count
FROM sales.customers
GROUP BY customer_id, email
HAVING COUNT(*) > 1
ORDER BY occurrence_count DESC;

Essa consulta retorna todas as combinações de customer_id e email que aparecem várias vezes na tabela, ajudando você a entender o escopo da duplicação.

Usar QUALIFY com funções de janela

A QUALIFY cláusula fornece uma abordagem mais simples filtrando os resultados das funções de janela diretamente, sem exigir subconsultas. Essa abordagem é especialmente útil quando você precisa exibir as linhas duplicadas reais, não apenas contagens.

SELECT *
FROM sales.customers
QUALIFY COUNT(*) OVER (PARTITION BY customer_id, email) > 1;

Essa consulta pode retornar resultados como:

customer_id email nome criado_em status
1001 jane@contoso.com Jane Doe 2024-01-15 Active
1001 jane@contoso.com Jane D. 2024-03-20 Active
1002 bob@fabrikam.com Bob Smith 2024-02-10 Pendente
1002 bob@fabrikam.com Robert Smith 11/02/2024 Active

Com esse padrão, você obtém todas as colunas das linhas duplicadas, facilitando a investigação da origem da duplicação.

Localizar duplicatas usando o PySpark

No PySpark, você pode usar funções de janela combinadas com filtragem para identificar registros duplicados:

from pyspark.sql.functions import count
from pyspark.sql.window import Window

window_spec = Window.partitionBy("customer_id", "email")

duplicates_df = (
    df.withColumn("row_count", count("*").over(window_spec))
    .filter("row_count > 1")
    .drop("row_count")
)

display(duplicates_df)

Como alternativa, use o exceptAll() método para comparar o DataFrame original com uma versão com eliminação de duplicação:

df_duplicates = df.exceptAll(df.dropDuplicates(["customer_id", "email"]))
display(df_duplicates)

O exceptAll() método executa uma diferença de conjunto que preserva duplicatas. Ele retorna todas as linhas do primeiro DataFrame que não estão no segundo DataFrame, mantendo ocorrências duplicadas. Veja como funciona:

  1. df.dropDuplicates(["customer_id", "email"]) cria um DataFrame com uma linha por combinação exclusiva
  2. exceptAll() compara o DataFrame original com essa versão deduplicada
  3. Para cada combinação exclusiva, uma ocorrência é "encontrada" e removida, restando apenas as duplicatas.

Por exemplo, se o cliente 1001 aparecer três vezes no DataFrame original e uma vez na versão com eliminação de duplicação, exceptAll() retornará duas linhas (as ocorrências extras).

Observação

Ao contrário except()de , que remove todas as linhas correspondentes e retorna resultados distintos, exceptAll() preserva a estrutura duplicada. Se você tiver três linhas idênticas no conjunto original e uma no conjunto deduplicado, exceptAll() retornará exatamente duas linhas.

Remover registros duplicados

Depois de identificar duplicatas, você pode escolher uma estratégia de resolução com base em seus requisitos de dados.

Diagrama explicando como remover registros duplicados.

Remover duplicatas no PySpark

O dropDuplicates() método remove linhas duplicadas com base em colunas especificadas e mantém uma linha para cada combinação. Quando as linhas diferem em outras colunas, não é possível garantir qual linha permanece:

df_clean = df.dropDuplicates(["customer_id", "email"])

Para uma completa eliminação de duplicação de linha em todas as colunas, use distinct():

df_unique = df.distinct()

Manter linhas específicas usando ROW_NUMBER

Quando precisar de controle sobre a duplicata a ser mantida, use ROW_NUMBER() com QUALIFY para selecionar registros com base em critérios como a atualização mais recente:

SELECT *
FROM sales.customers
QUALIFY ROW_NUMBER() OVER (
    PARTITION BY customer_id 
    ORDER BY updated_at DESC
) = 1;

Essa consulta particiona registros por customer_id, ordena-os em updated_at ordem decrescente e mantém apenas o registro atualizado mais recentemente para cada cliente.

Tratar valores nulos e ausentes

Valores nulos representam dados ausentes ou desconhecidos. Dependendo dos requisitos de análise, talvez seja necessário remover linhas com nulos, substituí-las por valores padrão ou usar a imputação estatística.

Diagrama explicando como lidar com valores nulos e ausentes.

Identificar valores nulos

Use a função isnull() ou o operador IS NULL para localizar registros com valores ausentes.

SELECT *
FROM sales.transactions
WHERE amount IS NULL 
   OR customer_id IS NULL;

Para contar ocorrências nulas por coluna:

SELECT 
    COUNT(*) AS total_rows,
    COUNT(*) - COUNT(amount) AS null_amount_count,
    COUNT(*) - COUNT(customer_id) AS null_customer_count
FROM sales.transactions;

Remover linhas com valores nulos

No PySpark, o dropna() método remove linhas que contêm valores nulos:

# Drop rows where any column is null
df_clean = df.dropna()

# Drop rows where all columns are null
df_clean = df.dropna(how="all")

# Drop rows where specific columns are null
df_clean = df.dropna(subset=["customer_id", "amount"])

O how parâmetro controla o comportamento: "any" descarta linhas com pelo menos um nulo (padrão), enquanto "all" descarta linhas somente quando todas as colunas especificadas são nulas.

Preencher valores nulos com valores padrão

O fillna() método substitui valores nulos por padrões especificados:

# Fill null values with a single value (applies only to columns whose data type matches)
df_filled = df.fillna(0)

# Fill specific columns with different values
df_filled = df.fillna({
    "amount": 0,
    "status": "Unknown",
    "quantity": 1
})

No SQL, use a COALESCE função para fornecer valores padrão:

SELECT 
    customer_id,
    COALESCE(amount, 0) AS amount,
    COALESCE(status, 'Unknown') AS status
FROM sales.transactions;

Escolha a estratégia certa

A estratégia de tratamento nulo apropriada depende do contexto de dados:

Scenario Abordagem recomendada
Nulos em campos necessários, como identificadores Remover as linhas
Nulos em campos numéricos para agregação Preencher com zero ou média
Nulos em campos categóricos opcionais Preencher com placeholder como "Desconhecido"
Nulos capazes de distorcer a análise Remover ou preencher com base no conhecimento de domínio

Dica

Documente suas decisões de manuseio de nulos. Os futuros analistas precisam entender por que determinados valores foram substituídos ou removidos para interpretar corretamente os resultados da consulta.

Entender como identificar e resolver esses problemas de qualidade de dados prepara você para criar pipelines de dados mais confiáveis. Com dados limpos, suas transformações e análises downstream produzem resultados confiáveis.