Em qualquer projeto de análise de dados, a etapa de limpeza e preparação consome, em média, mais tempo do que a análise em si. Dados do mundo real chegam com inconsistências de tipos, valores ausentes, duplicatas, categorias grafadas de formas diferentes e erros de digitação.
Iniciar uma análise estatística sem verificar a qualidade dos dados produz resultados incorretos - e o pior: resultados que parecem plausíveis.
4.2 Mercado e pesquisa
Analistas experientes dedicam de 50% a 80% do tempo de um projeto à preparação dos dados. Habilidade em limpeza de dados não é detalhe: é o que separa uma análise confiável de uma análise perigosa.
4.3 Verificação inicial do dataset
O fluxo de verificação inicial deve ser sempre o mesmo, independentemente da origem dos dados:
# 4. Verificar valores ausentes por colunacolSums(is.na(CO2))
Plant Type Treatment conc uptake
0 0 0 0 0
# 5. Resumo geralsummary(CO2)
Plant Type Treatment conc uptake
Qn1 : 7 Quebec :42 nonchilled:42 Min. : 95 Min. : 7.70
Qn2 : 7 Mississippi:42 chilled :42 1st Qu.: 175 1st Qu.:17.90
Qn3 : 7 Median : 350 Median :28.30
Qc1 : 7 Mean : 435 Mean :27.21
Qc3 : 7 3rd Qu.: 675 3rd Qu.:37.12
Qc2 : 7 Max. :1000 Max. :45.50
(Other):42
4.4 Valores ausentes
4.4.1 O que são e por que ocorrem
Valores ausentes (NA no R) são observações para as quais não existe registro. Podem ocorrer por falha na coleta, erro de digitação, dados não aplicáveis ou perda durante o processamento.
4.4.2 Tipos de ausência
Tipo
Descrição
Implicação
MCAR (Missing Completely at Random)
Ausência não relacionada a nenhuma variável
Remoção simples possível
MAR (Missing at Random)
Ausência relacionada a outras variáveis observadas
Imputação adequada
MNAR (Missing Not at Random)
Ausência relacionada ao próprio valor faltante
Problema sério, exige cuidado
4.4.3 Identificação e tratamento
# Função para resumo completo de ausentesresumo_ausentes <-function(df) { ausentes <-colSums(is.na(df)) perc <-round(ausentes /nrow(df) *100, 2)data.frame(Variavel =names(ausentes),N_ausente = ausentes,Perc_ausente = perc) |>filter(N_ausente >0) |>arrange(desc(Perc_ausente))}# Aplicando ao CO2 (sem ausentes, mas a função serve para qualquer dataset)resultado <-resumo_ausentes(CO2)if (nrow(resultado) ==0) {cat("Nenhum valor ausente encontrado.\n")} else {kable(resultado, caption ="Valores ausentes por variável")}
# Estratégia 1: remover linhas com NA (só justificada com poucos casos e MCAR)CO2_sem_na <- CO2_sujo |>drop_na(uptake)cat("Linhas após remoção:", nrow(CO2_sem_na), "\n")
Linhas após remoção: 76
# Estratégia 2: imputar pela mediana do grupo (mais conservadora)CO2_imputado <- CO2_sujo |>group_by(Type, Treatment) |>mutate(uptake =ifelse(is.na(uptake), median(uptake, na.rm =TRUE), uptake)) |>ungroup()cat("Valores ausentes após imputação:", sum(is.na(CO2_imputado$uptake)), "\n")
Valores ausentes após imputação: 0
Atenção
Nunca remova valores ausentes automaticamente sem investigar o padrão. Remoção inadequada pode introduzir viés nos resultados. Sempre documente a decisão tomada e o critério utilizado.
4.5 Verificação e correção de tipos
Variáveis com o tipo errado causam erros silenciosos - operações que parecem funcionar mas produzem resultados incorretos.
# No CO2, Plant e Type e Treatment já são fatores# Demonstração de conversão de tiposCO2_tipado <- CO2 |>mutate(# Garantir que variáveis categóricas são fatores com labels clarosType =factor(Type,levels =c("Quebec", "Mississippi"),labels =c("Quebec", "Mississippi")),Treatment =factor(Treatment,levels =c("nonchilled", "chilled"),labels =c("Nao_resfriada", "Resfriada")),# Concentração como numérica (já está, mas explicitando)conc =as.numeric(conc),uptake =as.numeric(uptake))# Verificando resultadostr(CO2_tipado)
Transformações de dados não são manipulação dos resultados - são ajustes legítimos que permitem atender pressupostos de testes estatísticos. A transformação logarítmica é a mais comum em dados biológicos, pois estabiliza variâncias e reduz assimetria positiva. Sempre reporte que a variável foi transformada e interprete os resultados na escala original quando possível.
4.9 Checklist de limpeza
Antes de prosseguir para qualquer análise, percorra este checklist:
Boas práticas
Nunca modifique o arquivo de dados brutos. Mantenha o dataset original intacto e aplique todas as transformações em um novo objeto. Isso garante rastreabilidade e facilita a revisão da análise.
---title: "Limpeza e preparação de dados"---```{r setup, include=FALSE}knitr::opts_chunk$set(echo=TRUE, warning=FALSE, message=FALSE, fig.align="center", fig.width=9, fig.height=5.5)library(tidyverse)library(knitr)library(kableExtra)cores_cafe <-c("#224573", "#6B4F4F", "#4A6FA5", "#E5D3B3")data("CO2")```## Por que a limpeza de dados importaEm qualquer projeto de análise de dados, a etapa de limpeza e preparação consome, em média, mais tempo do que a análise em si. Dados do mundo real chegam com inconsistências de tipos, valores ausentes, duplicatas, categorias grafadas de formas diferentes e erros de digitação.Iniciar uma análise estatística sem verificar a qualidade dos dados produz resultados incorretos - e o pior: resultados que parecem plausíveis.## Mercado e pesquisaAnalistas experientes dedicam de 50% a 80% do tempo de um projeto à preparação dos dados. Habilidade em limpeza de dados não é detalhe: é o que separa uma análise confiável de uma análise perigosa.## Verificação inicial do datasetO fluxo de verificação inicial deve ser sempre o mesmo, independentemente da origem dos dados:```{r verificacao_inicial}data("CO2")# 1. Dimensõescat("Linhas:", nrow(CO2), "| Colunas:", ncol(CO2), "\n")# 2. Tipos de variáveisglimpse(CO2)``````{r nomes_colunas}# 3. Nomes das colunasnames(CO2)``````{r valores_ausentes}# 4. Verificar valores ausentes por colunacolSums(is.na(CO2))``````{r resumo}# 5. Resumo geralsummary(CO2)```## Valores ausentes### O que são e por que ocorrem**Valores ausentes** (`NA` no R) são observações para as quais não existe registro. Podem ocorrer por falha na coleta, erro de digitação, dados não aplicáveis ou perda durante o processamento.### Tipos de ausência| Tipo | Descrição | Implicação ||------------------------|------------------------|------------------------|| **MCAR (Missing Completely at Random)** | Ausência não relacionada a nenhuma variável | Remoção simples possível || **MAR (Missing at Random)** | Ausência relacionada a outras variáveis observadas | Imputação adequada || **MNAR (Missing Not at Random)** | Ausência relacionada ao próprio valor faltante | Problema sério, exige cuidado |### Identificação e tratamento```{r missing_detalhado}# Função para resumo completo de ausentesresumo_ausentes <-function(df) { ausentes <-colSums(is.na(df)) perc <-round(ausentes /nrow(df) *100, 2)data.frame(Variavel =names(ausentes),N_ausente = ausentes,Perc_ausente = perc) |>filter(N_ausente >0) |>arrange(desc(Perc_ausente))}# Aplicando ao CO2 (sem ausentes, mas a função serve para qualquer dataset)resultado <-resumo_ausentes(CO2)if (nrow(resultado) ==0) {cat("Nenhum valor ausente encontrado.\n")} else {kable(resultado, caption ="Valores ausentes por variável")}``````{r simulando_ausentes}# Simulando ausentes para demonstração didáticaset.seed(42)CO2_sujo <- CO2indices_na <-sample(nrow(CO2_sujo), size =8)CO2_sujo$uptake[indices_na] <-NAcat("Valores ausentes inseridos:", sum(is.na(CO2_sujo$uptake)), "\n")# Estratégia 1: remover linhas com NA (só justificada com poucos casos e MCAR)CO2_sem_na <- CO2_sujo |>drop_na(uptake)cat("Linhas após remoção:", nrow(CO2_sem_na), "\n")# Estratégia 2: imputar pela mediana do grupo (mais conservadora)CO2_imputado <- CO2_sujo |>group_by(Type, Treatment) |>mutate(uptake =ifelse(is.na(uptake), median(uptake, na.rm =TRUE), uptake)) |>ungroup()cat("Valores ausentes após imputação:", sum(is.na(CO2_imputado$uptake)), "\n")```::: callout-warning## AtençãoNunca remova valores ausentes automaticamente sem investigar o padrão. Remoção inadequada pode introduzir viés nos resultados. Sempre documente a decisão tomada e o critério utilizado.:::## Verificação e correção de tiposVariáveis com o tipo errado causam erros silenciosos - operações que parecem funcionar mas produzem resultados incorretos.```{r tipos}# Verificar tipos atuaissapply(CO2, class)``````{r correcao_tipos}# No CO2, Plant e Type e Treatment já são fatores# Demonstração de conversão de tiposCO2_tipado <- CO2 |>mutate(# Garantir que variáveis categóricas são fatores com labels clarosType =factor(Type,levels =c("Quebec", "Mississippi"),labels =c("Quebec", "Mississippi")),Treatment =factor(Treatment,levels =c("nonchilled", "chilled"),labels =c("Nao_resfriada", "Resfriada")),# Concentração como numérica (já está, mas explicitando)conc =as.numeric(conc),uptake =as.numeric(uptake))# Verificando resultadostr(CO2_tipado)```## Verificação de duplicatas```{r duplicatas}# Verificar linhas duplicadasn_duplicatas <-sum(duplicated(CO2))cat("Linhas duplicadas:", n_duplicatas, "\n")# Remover duplicatas se existiremCO2_limpo <- CO2 |>distinct()cat("Linhas após remoção de duplicatas:", nrow(CO2_limpo), "\n")```## Verificação de valores inconsistentesValores fora dos limites esperados podem indicar erros de medição ou digitação.```{r valores_inconsistentes}# Verificar valores de uptake: biologicamente, deve ser positivocat("Mínimo de uptake:", min(CO2$uptake), "\n")cat("Máximo de uptake:", max(CO2$uptake), "\n")# Verificar se há valores negativos (biologicamente impossíveis aqui)negativos <- CO2 |>filter(uptake <0)cat("Valores negativos:", nrow(negativos), "\n")# Verificar concentrações únicas (devem ser os 7 níveis esperados)sort(unique(CO2$conc))``````{r resumo_qualidade}# Resumo completo de qualidade dos dadoscat("=== Relatório de qualidade dos dados ===\n")cat("Dimensões: ", nrow(CO2), "x", ncol(CO2), "\n")cat("Valores ausentes: ", sum(is.na(CO2)), "\n")cat("Linhas duplicadas: ", sum(duplicated(CO2)), "\n")cat("Variáveis categóricas: ", sum(sapply(CO2, is.factor)), "\n")cat("Variáveis numéricas: ", sum(sapply(CO2, is.numeric)), "\n")```## Transformação de variáveisTransformações podem ser necessárias quando os dados violam pressupostos de normalidade ou quando a relação entre variáveis não é linear.```{r transformacoes}# Transformação logarítmica - reduz assimetria positivaCO2 <- CO2 |>mutate(log_uptake =log(uptake),sqrt_uptake =sqrt(uptake) )# Comparando distribuições: original - log - raiz quadradapar(mfrow =c(1, 3))hist(CO2$uptake,main ="Original",xlab ="uptake",col ="#4A6FA5",border ="white")hist(CO2$log_uptake,main ="Log(uptake)",xlab ="log(uptake)",col ="#6B4F4F",border ="white")hist(CO2$sqrt_uptake,main ="Sqrt(uptake)",xlab ="sqrt(uptake)",col ="#224573",border ="white")```::: callout-note## ConceitoTransformações de dados não são manipulação dos resultados - são ajustes legítimos que permitem atender pressupostos de testes estatísticos. A transformação logarítmica é a mais comum em dados biológicos, pois estabiliza variâncias e reduz assimetria positiva. Sempre reporte que a variável foi transformada e interprete os resultados na escala original quando possível.:::## Checklist de limpezaAntes de prosseguir para qualquer análise, percorra este checklist:- [ ] Dimensões do dataset verificadas- [ ] Tipos de variáveis conferidos e corrigidos se necessário- [ ] Valores ausentes identificados, quantificados e tratados com critério documentado- [ ] Duplicatas verificadas e removidas se aplicável- [ ] Valores inconsistentes ou fora do domínio esperado investigados- [ ] Nomes de colunas padronizados (sem espaços, acentos ou caracteres especiais)- [ ] Dataset final salvo como objeto limpo, separado do original::: callout-tip## Boas práticas> **Nunca modifique o arquivo de dados brutos.** Mantenha o dataset original intacto e aplique todas as transformações em um novo objeto. Isso garante rastreabilidade e facilita a revisão da análise.:::