Tutorial completo com o pacote janitor, abre o R e vem praticar
Esta aula foi construída para que você resolva em minutos o que antes tomava horas. Os dados usados são simulados para fins didáticos. Todo o código está funcional e pronto para reproduzir.
Inscreva-se já no canal Link.
janitorjanitor foi criado por Sam Firke com o objetivo de simplificar tarefas de limpeza que aparecem em praticamente todo projeto de análise de dados.
|>Este dataset simula uma planilha de recursos humanos exportada de um sistema legado.
Problemas clássicos: nomes de colunas com espaço e acento, linhas duplicadas, valores inconsistentes, coluna vazia e linha totalizadora no final.
dados_sujos <- tibble(
`Nome Completo` = c("Ana Silva", "ana silva", "Carlos Mendes",
"CARLOS MENDES", "Beatriz Santos",
"Fernanda Lima", "Fernanda Lima",
"Rodrigo Costa", NA, "TOTAL"),
`Departamento ` = c("RH", "rh", "TI", "ti", "Financeiro",
"Marketing", "Marketing", "TI", "RH", NA),
`Salário (R$)` = c(4500, 4500, 7200, 7200, 5800,
6100, 6100, 8300, NA, 49900),
`Data de Admissão` = c("2020-03-15", "2020-03-15", "2019-07-22",
"2019-07-22", "2021-11-01",
"2022-05-10", "2022-05-10", "2018-01-30",
"2023-08-14", NA),
`% Avaliação` = c(87, 87, 92, 92, 78, 95, 95, 88, NA, NA),
`Coluna Vazia` = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA),
`status` = c("Ativo", "ativo", "Ativo", "ATIVO",
"Inativo", "Ativo", "ativo", "Ativo",
"Ativo", NA))# A tibble: 10 × 7
`Nome Completo` `Departamento ` `Salário (R$)` `Data de Admissão`
<chr> <chr> <dbl> <chr>
1 Ana Silva RH 4500 2020-03-15
2 ana silva rh 4500 2020-03-15
3 Carlos Mendes TI 7200 2019-07-22
4 CARLOS MENDES ti 7200 2019-07-22
5 Beatriz Santos Financeiro 5800 2021-11-01
6 Fernanda Lima Marketing 6100 2022-05-10
7 Fernanda Lima Marketing 6100 2022-05-10
8 Rodrigo Costa TI 8300 2018-01-30
9 <NA> RH NA 2023-08-14
10 TOTAL <NA> 49900 <NA>
# ℹ 3 more variables: `% Avaliação` <dbl>, `Coluna Vazia` <lgl>, status <chr>
%Coluna Vazia)Departamento e status (variações de maiúsculas)Nome CompletoEsses são exatamente os problemas que o janitor resolve.
% quebram pipelines e exigem aspas em todo acesso.[1] "nome_completo" "departamento" "salario_r"
[4] "data_de_admissao" "percent_avaliacao" "coluna_vazia"
[7] "status"
Antes: Nome Completo, Salário (R$), % Avaliação
Depois: nome_completo, salario_r, percent_avaliacao
Todos os nomes são agora válidos como variáveis R sem necessidade de aspas ou backticks.
[1] "nome_completo" "departamento" "salario_r"
[4] "data_de_admissao" "percent_avaliacao" "status"
A coluna coluna_vazia foi removida.
O dataset passou de 7 para 6 colunas.
Uma linha foi removida. O dataset passou de 10 para 9 linhas.
Problema: planilhas exportadas de sistemas frequentemente incluem uma linha de totais no final.
Essa linha não é uma observação e distorce cálculos.
# A tibble: 8 × 2
nome_completo salario_r
<chr> <dbl>
1 Ana Silva 4500
2 ana silva 4500
3 Carlos Mendes 7200
4 CARLOS MENDES 7200
5 Beatriz Santos 5800
6 Fernanda Lima 6100
7 Fernanda Lima 6100
8 Rodrigo Costa 8300
A linha “TOTAL” foi removida.
O salário de R$ 49.900 que distorceria qualquer média não está mais no dataset.
Problema: linhas duplicadas inflam contagens, distorcem médias e podem gerar erros em joins.
O janitor oferece get_dupes() para investigar as duplicatas antes de removê-las.
# get_dupes() identifica e exibe as linhas duplicadas com contagem
dados_p4 |>
get_dupes(nome_completo)# A tibble: 2 × 7
nome_completo dupe_count departamento salario_r data_de_admissao
<chr> <int> <chr> <dbl> <chr>
1 Fernanda Lima 2 Marketing 6100 2022-05-10
2 Fernanda Lima 2 Marketing 6100 2022-05-10
# ℹ 2 more variables: percent_avaliacao <dbl>, status <chr>
O dataset passou de 8 para 6 linhas.
Ana Silva e Carlos Mendes agora aparecem uma única vez.
RH, rh, Ativo, ATIVO, ativo) impede agrupamentos, joins e filtros corretos.# str_to_title() capitaliza a primeira letra de cada palavra
# str_squish() remove espaços extras no início, fim e entre palavras
dados_p6 <- dados_p5 |>
mutate(
nome_completo = str_to_title(str_squish(nome_completo)),
departamento = str_to_title(str_squish(departamento)),
status = str_to_title(str_squish(status)))# A tibble: 7 × 3
nome_completo departamento status
<chr> <chr> <chr>
1 Ana Silva Rh Ativo
2 Ana Silva Rh Ativo
3 Carlos Mendes Ti Ativo
4 Carlos Mendes Ti Ativo
5 Beatriz Santos Financeiro Inativo
6 Fernanda Lima Marketing Ativo
7 Rodrigo Costa Ti Ativo
rh e RH agora são Rh. ativo e ATIVO agora são Ativo.
Os valores estão padronizados para permitir agrupamentos corretos.
Problema: colunas importadas de CSV ou planilhas frequentemente chegam como character mesmo quando deveriam ser numéricas ou de data.
Isso impede cálculos e ordenações.
Rows: 7
Columns: 6
$ nome_completo <chr> "Ana Silva", "Ana Silva", "Carlos Mendes", "Carlos M…
$ departamento <chr> "Rh", "Rh", "Ti", "Ti", "Financeiro", "Marketing", "…
$ salario_r <dbl> 4500, 4500, 7200, 7200, 5800, 6100, 8300
$ data_de_admissao <chr> "2020-03-15", "2020-03-15", "2019-07-22", "2019-07-2…
$ percent_avaliacao <dbl> 87, 87, 92, 92, 78, 95, 88
$ status <chr> "Ativo", "Ativo", "Ativo", "Ativo", "Inativo", "Ativ…
Rows: 7
Columns: 6
$ nome_completo <chr> "Ana Silva", "Ana Silva", "Carlos Mendes", "Carlos M…
$ departamento <chr> "Rh", "Rh", "Ti", "Ti", "Financeiro", "Marketing", "…
$ salario_r <dbl> 4500, 4500, 7200, 7200, 5800, 6100, 8300
$ data_de_admissao <date> 2020-03-15, 2020-03-15, 2019-07-22, 2019-07-22, 2021…
$ percent_avaliacao <dbl> 87, 87, 92, 92, 78, 95, 88
$ status <fct> Ativo, Ativo, Ativo, Ativo, Inativo, Ativo, Ativo
Problema: valores ausentes em variáveis-chave comprometem análises.
Antes de remover ou imputar, é preciso entender onde estão os NA e em qual proporção.
Problema: após a limpeza, é necessário validar que a distribuição dos dados faz sentido.
O tabyl() faz isso em uma linha e já retorna percentuais.
# tabyl() + adorn_ para formatação profissional da tabela
dados_p7 |>
tabyl(departamento, status) |>
adorn_totals(where = c("row", "col")) |>
adorn_percentages("row") |>
adorn_pct_formatting(digits = 1) |>
adorn_ns() departamento Inativo Ativo Total
Financeiro 100.0% (1) 0.0% (0) 100.0% (1)
Marketing 0.0% (0) 100.0% (1) 100.0% (1)
Rh 0.0% (0) 100.0% (2) 100.0% (2)
Ti 0.0% (0) 100.0% (3) 100.0% (3)
Total 14.3% (1) 85.7% (6) 100.0% (7)
| Nome Completo | Departamento | Salário (R$) | Data de Admissão | % Avaliação | Coluna Vazia | status |
|---|---|---|---|---|---|---|
| Ana Silva | RH | 4500 | 2020-03-15 | 87 | NA | Ativo |
| ana silva | rh | 4500 | 2020-03-15 | 87 | NA | ativo |
| Carlos Mendes | TI | 7200 | 2019-07-22 | 92 | NA | Ativo |
| CARLOS MENDES | ti | 7200 | 2019-07-22 | 92 | NA | ATIVO |
| Beatriz Santos | Financeiro | 5800 | 2021-11-01 | 78 | NA | Inativo |
| Fernanda Lima | Marketing | 6100 | 2022-05-10 | 95 | NA | Ativo |
| Fernanda Lima | Marketing | 6100 | 2022-05-10 | 95 | NA | ativo |
| Rodrigo Costa | TI | 8300 | 2018-01-30 | 88 | NA | Ativo |
| NA | RH | NA | 2023-08-14 | NA | NA | Ativo |
| TOTAL | NA | 49900 | NA | NA | NA | NA |
| nome_completo | departamento | salario_r | data_de_admissao | percent_avaliacao | status |
|---|---|---|---|---|---|
| Ana Silva | Rh | 4500 | 2020-03-15 | 87 | Ativo |
| Ana Silva | Rh | 4500 | 2020-03-15 | 87 | Ativo |
| Carlos Mendes | Ti | 7200 | 2019-07-22 | 92 | Ativo |
| Carlos Mendes | Ti | 7200 | 2019-07-22 | 92 | Ativo |
| Beatriz Santos | Financeiro | 5800 | 2021-11-01 | 78 | Inativo |
| Fernanda Lima | Marketing | 6100 | 2022-05-10 | 95 | Ativo |
| Rodrigo Costa | Ti | 8300 | 2018-01-30 | 88 | Ativo |
dados_limpos <- dados_sujos |>
# Passo 1: padronizar nomes de colunas
clean_names() |>
# Passos 2 e 3: remover colunas e linhas completamente vazias
remove_empty(which = c("cols", "rows")) |>
# Passo 4: remover linha totalizadora
filter(!str_to_upper(nome_completo) == "TOTAL") |>
# Passo 5: remover linhas duplicadas
distinct(nome_completo, .keep_all = TRUE) |>
# Passo 6: padronizar texto
mutate(
nome_completo = str_to_title(str_squish(nome_completo)),
departamento = str_to_title(str_squish(departamento)),
status = str_to_title(str_squish(status))) |>
# Passo 7: converter tipos
mutate(
data_de_admissao = as.Date(data_de_admissao),
salario_r = as.numeric(salario_r),
status = factor(status, levels = c("Inativo", "Ativo")))| Passo | Função | O que resolve |
|---|---|---|
| 1 | clean_names() |
Nomes de colunas inválidos |
| 2 | remove_empty("cols") |
Colunas 100% NA |
| 3 | remove_empty("rows") |
Linhas 100% NA |
| 4 | filter() |
Linha totalizadora |
| 5 | get_dupes() + distinct() |
Linhas duplicadas |
| 6 | str_to_title() + str_squish() |
Texto inconsistente |
| 7 | as.Date() + as.numeric() |
Tipos incorretos |
| 8 | tabyl() |
Diagnóstico de NA |
| 9 | tabyl() + adorn_*() |
Validação da limpeza |
get_dupes() antes de distinct() para entender o que está sendo removido, não apenas remover às cegastabyl() no início e no final de qualquer limpeza: antes para diagnosticar, depois para validar| Situação | Problema | Solução |
|---|---|---|
clean_names() gerou nomes iguais |
Colunas tinham nomes distintos mas que resultaram no mesmo snake_case | Renomear manualmente após clean_names() |
remove_empty() removeu coluna com dados |
Coluna tinha quase todos NA mas não todos | Usar remove_constant() ou filtrar manualmente |
distinct() removeu linha errada |
Duplicatas com valores diferentes | Especificar todas as colunas-chave em distinct() |
Limpeza de dados consome entre 60% e 80% do tempo de um projeto de análise segundo pesquisas da área.
O janitor não elimina esse tempo, mas reduz o esforço de tarefas repetitivas e torna o processo rastreável e reproduzível.
Continue praticando e explorando!
Esta aula é parte do projeto Café com R. É open source. Use, compartilhe e adapte.
Que cada gole desperte uma nova ideia.
Que cada script abra uma nova conversa.
Que o Café com R se torne um ponto de encontro nosso.

Jennifer Lopes | Café com R