Resolver duplicados e nulos
Problemas de qualidade dos dados, como registos duplicados e valores nulos, podem comprometer as suas análises e processos a jusante. Quer os duplicados surjam de cargas de dados concorrentes ou apareçam nulos devido a dados fonte incompletos, abordar estas questões é uma responsabilidade central dos engenheiros de dados que trabalham em Azure Databricks.
Nesta unidade, aprende a identificar e resolver valores duplicados, em falta e nulos usando abordagens SQL e PySpark.
Identificar registos duplicados
Antes de poderes remover duplicados, tens de os encontrar. Os duplicados ocorrem tipicamente quando o mesmo registo aparece várias vezes numa tabela, frequentemente devido a problemas de integração de dados, ingestão repetida ou operações de escrita concorrentes.
Utilize GROUP BY e HAVING para encontrar duplicados
A forma mais simples de identificar duplicados é agrupando registos e contando ocorrências. A HAVING cláusula filtra os resultados agrupados para mostrar apenas valores que aparecem mais do que 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;
Esta consulta devolve todas as combinações de customer_id e email que aparecem várias vezes na tabela, ajudando-o a compreender o âmbito da duplicação.
Use o QUALIFY com funções janela
A QUALIFY cláusula oferece uma abordagem mais simples filtrando diretamente os resultados das funções janela, sem necessidade de subconsultas. Esta abordagem é particularmente útil quando precisar de ver as verdadeiras linhas duplicadas, não apenas as contagens.
SELECT *
FROM sales.customers
QUALIFY COUNT(*) OVER (PARTITION BY customer_id, email) > 1;
Esta consulta pode devolver resultados como:
| customer_id | nome | criado_em | estado | |
|---|---|---|---|---|
| 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 | 2024-02-11 | Active |
Com este padrão, obtém-se todas as colunas das linhas duplicadas, facilitando a investigação da origem da duplicação.
Encontre duplicados usando o PySpark
No PySpark, pode usar funções de janela combinadas com filtragem para identificar registos 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)
Alternativamente, use o exceptAll() método para comparar o DataFrame original com uma versão deduplicada:
df_duplicates = df.exceptAll(df.dropDuplicates(["customer_id", "email"]))
display(df_duplicates)
O exceptAll() método realiza uma diferença de conjuntos que preserva duplicados. Devolve todas as linhas do primeiro DataFrame que não estão no segundo DataFrame, mantendo ocorrências duplicadas. Eis como funciona:
-
df.dropDuplicates(["customer_id", "email"])cria um DataFrame com uma linha por combinação única -
exceptAll()compara o DataFrame original com esta versão desduplicada - Para cada combinação única, uma ocorrência é "combinada" e removida, restando apenas os duplicados extra
Por exemplo, se o cliente 1001 aparecer três vezes no DataFrame original e uma vez na versão desduplicada, exceptAll() devolve duas linhas (as ocorrências extra).
Observação
Ao contrário de except(), que remove todas as linhas correspondentes e retorna resultados distintos, exceptAll() preserva a estrutura duplicada. Se tiveres três linhas idênticas no original e uma no conjunto desduplicado, exceptAll() devolve exatamente duas linhas.
Remover registos duplicados
Depois de identificar duplicados, pode escolher uma estratégia de resolução com base nas suas necessidades de dados.
Remover duplicados no PySpark
O dropDuplicates() método remove linhas duplicadas com base nas colunas especificadas e mantém uma linha para cada combinação. Quando as linhas diferem noutras colunas, não é garantido qual linha permanece:
df_clean = df.dropDuplicates(["customer_id", "email"])
Para a deduplicação completa de linhas em todas as colunas, use distinct():
df_unique = df.distinct()
Mantém linhas específicas usando ROW_NUMBER
Quando precisar de controlo sobre qual duplicado manter, use ROW_NUMBER() com QUALIFY para selecionar registos 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;
Esta consulta divide os registos por customer_id, ordena-os updated_at por ordem decrescente e mantém apenas o registo mais recentemente atualizado para cada cliente.
Lidar com valores nulos e ausentes
Valores nulos representam dados em falta ou desconhecidos. Dependendo dos seus requisitos de análise, pode ser necessário remover linhas com nulos, substituí-las por valores padrão ou usar imputação estatística.
Identificar valores nulos
Use a isnull() função ou IS NULL operador para encontrar registos com valores em falta:
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;
Eliminar 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" elimina linhas com pelo menos uma nula (por defeito), enquanto "all" remove linhas apenas quando todas as colunas especificadas são nulas.
Preencher valores nulos com valores padrão
O fillna() método substitui valores nulos por valores definidos 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
})
**
Em SQL, use a função COALESCE para fornecer valores por defeito.
SELECT
customer_id,
COALESCE(amount, 0) AS amount,
COALESCE(status, 'Unknown') AS status
FROM sales.transactions;
Escolha a estratégia certa
A estratégia adequada de gestão de nulos depende do contexto dos seus dados:
| Scenario | Abordagem recomendada |
|---|---|
| Nulos em campos obrigatórios como identificadores | Elimina as linhas |
| Nulos em campos numéricos para agregação | Preencha com zero ou valor médio |
| Nulos em campos categóricos opcionais | Preencha com um marcador de posição como "Desconhecido" |
| Valores nulos que distorceriam a análise | Eliminar ou preencher com base no conhecimento do domínio |
Sugestão
Documente as suas decisões de gestão de valores nulos. Os analistas futuros precisam de compreender porque é que certos valores foram substituídos ou removidos para interpretar corretamente os resultados das consultas.
Compreender como identificar e resolver estas questões de qualidade de dados prepara-o para construir pipelines de dados mais fiáveis. Com dados limpos, as transformações e análises a jusante produzem resultados fiáveis.