Neste relatório vamos abordar algumas técnicas em R de pré-processamento de dados. Criaremos uma base de dados genérica afim de aplicar algumas funções e métodos de organização e limpeza de dados em um data frame. Utilizaremos a biblioteca dplyr com alguns recursos de seleção derivados da função select(). Para determinados procedimentos de seleção, organização ou limpeza dos dados podem haver diversas maneiras de se obter o mesmo resultado, cabe ao estatístico utilizar as funções e métodos de sua preferência. A intenção é otimizar as técnicas de programação para poupar tempo e esforço e gerar bons resultados.
Temas de estudo: Pré-processamento, funções aninhadas, função startsWith()/endsWith(), função ifelse(), função for(), operador pipe (%>%), R Markdown.
Criaremos um Data Frame genérico relacionado à pescaria, onde a variável IdPeixe é apenas o número de identificação de determinada espécie de peixe, Quantidade é a quantidade de peixes pescados, Média representa o tamanho médio em centímetros dos peixes pescados e Local é o local geográfico em que o peixe foi capturado. Colocaremos valores NA propositalmente no Data Frame para podermos tratá-los posteriormente. Toda vez que a base de dados é gerada novas informações são armazenadas, pois não nos interessa a interpretação analítica da base de dados e sim os procedimentos de pré-processamento.
IdPeixe = seq(1,20,1)
Quantidade = rbinom(20, 100, 0.20)
x = seq(1,10.5,0.5); nx = length(x); Média = sample(x, nx, replace = F)
y = c("Lago", "Rio", "Mar", "Lagoa"); Local = sample(y, nx, replace = T)
df = data.frame(IdPeixe, Quantidade, Média, Local)
df$Média= ifelse(df$Média<= 3, is.na(df$Média), df$Média)
df$Média[df$Média== 0] = NA
df$IdPeixe = as.character(df$IdPeixe); class(df$IdPeixe)## [1] "character"
glimpse(df)## Rows: 20
## Columns: 4
## $ IdPeixe <chr> "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "1~
## $ Quantidade <int> 24, 17, 19, 18, 22, 13, 23, 23, 23, 21, 24, 27, 20, 20, 14,~
## $ Média <dbl> 8.5, NA, 5.5, 6.0, 9.0, 8.0, 7.5, 4.5, NA, NA, 6.5, 10.5, 5~
## $ Local <chr> "Lago", "Mar", "Rio", "Lago", "Mar", "Lago", "Lagoa", "Rio"~
| IdPeixe | Quantidade | Média | Local |
|---|---|---|---|
| 1 | 24 | 8.5 | Lago |
| 2 | 17 | NA | Mar |
| 3 | 19 | 5.5 | Rio |
| 4 | 18 | 6.0 | Lago |
| 5 | 22 | 9.0 | Mar |
| 6 | 13 | 8.0 | Lago |
| 7 | 23 | 7.5 | Lagoa |
| 8 | 23 | 4.5 | Rio |
| 9 | 23 | NA | Lago |
| 10 | 21 | NA | Mar |
| 11 | 24 | 6.5 | Rio |
| 12 | 27 | 10.5 | Lago |
| 13 | 20 | 5.0 | Lagoa |
| 14 | 20 | 4.0 | Lagoa |
| 15 | 14 | 3.5 | Lago |
| 16 | 18 | 9.5 | Mar |
| 17 | 20 | NA | Rio |
| 18 | 23 | 10.0 | Rio |
| 19 | 21 | 7.0 | Rio |
| 20 | 21 | NA | Mar |
Remover a coluna IdPeixe e remover todas as linhas com valores NA. Note que este procedimento remove informações de outras variáveis e consequentemente diminui nosso tamanho amostral. Procedimento recomendado principalmente se houver poucos valores NA na sua base de dados.
df = df[!is.na(df$Média),]
df$IdPeixe = NULL
nrow(df)## [1] 15
| Quantidade | Média | Local | |
|---|---|---|---|
| 1 | 24 | 8.5 | Lago |
| 3 | 19 | 5.5 | Rio |
| 4 | 18 | 6.0 | Lago |
| 5 | 22 | 9.0 | Mar |
| 6 | 13 | 8.0 | Lago |
| 7 | 23 | 7.5 | Lagoa |
| 8 | 23 | 4.5 | Rio |
| 11 | 24 | 6.5 | Rio |
| 12 | 27 | 10.5 | Lago |
| 13 | 20 | 5.0 | Lagoa |
| 14 | 20 | 4.0 | Lagoa |
| 15 | 14 | 3.5 | Lago |
| 16 | 18 | 9.5 | Mar |
| 18 | 23 | 10.0 | Rio |
| 19 | 21 | 7.0 | Rio |
Substituir todos os valores NA pela média de todos os elementos restantes da variável Média. A média é uma estatística, portanto, uma função da amostra. Em inferência (ou estatística indutiva) consideramos a média amostral um estimador pontual para o parâmetro de interesse chamado de média populacional. A média é uma medida resumo de tendência central de uma amostra, observe que se a média for uma medida representativa dos dados não há problema substituir valores faltantes pela média dos demais valores. Esse método mantém as informações das outras variavéis e sua base de dados permanece com o mesmo tamanho amostral.
média = mean(df$Média[!is.na(df$Média)]);média## [1] 7
df$Média = df$Média %>% is.na() %>% ifelse(média, df$Média)
df$IdPeixe = NULL
nrow(df)## [1] 20
| Quantidade | Média | Local |
|---|---|---|
| 15 | 4.0 | Mar |
| 22 | 3.5 | Lago |
| 22 | 7.5 | Lagoa |
| 21 | 9.0 | Lagoa |
| 23 | 8.0 | Mar |
| 17 | 7.0 | Lago |
| 17 | 4.5 | Lagoa |
| 19 | 5.5 | Lago |
| 17 | 10.0 | Lagoa |
| 19 | 8.5 | Lagoa |
| 24 | 9.5 | Mar |
| 20 | 7.0 | Lagoa |
| 21 | 10.5 | Rio |
| 22 | 6.0 | Rio |
| 24 | 7.0 | Mar |
| 22 | 7.0 | Rio |
| 15 | 7.0 | Lago |
| 12 | 5.0 | Lago |
| 22 | 7.0 | Lago |
| 21 | 6.5 | Lagoa |
Algumas bases de dados que geram informações em tempo real podem armazenar elementos com nomes diferentes, porém com o mesmo significado para a análise. Imagine que uma empresa reporta alertas de erros do servidor em tempo real e o que difere alguns elementos são geralmente datas e horários distintos gerados na mesma coluna. Com o auxílio das funções startsWith() e endsWith() conseguimos selecionar um grupo de caracteres para alterarmos ou padronizarmos nossa base de dados. Neste caso, utilizamos apenas a última letra do nome das classes da variável Local para realizarmos as alterações.
rm(list = ls())
IdPeixe = seq(1,20,1)
Quantidade = rbinom(20, 100, 0.20)
x = seq(1,10.5,0.5); nx = length(x); Média = sample(x, nx, replace = F)
y = c("Lago", "Rio", "Mar", "Lagoa"); Local = sample(y, nx, replace = T)
df = data.frame(IdPeixe, Quantidade, Média, Local)
df$IdPeixe = NULL
for (i in 1:3) {
u = c("o", "a", "r")
w = c("Água Doce", "Água Doce", "Água Salgada")
df$Local = df$Local %>% endsWith(u[i]) %>% ifelse(w[i], df$Local)
}| Quantidade | Média | Local |
|---|---|---|
| 13 | 4.5 | Água Salgada |
| 25 | 2.5 | Água Doce |
| 18 | 1.5 | Água Salgada |
| 26 | 1.0 | Água Doce |
| 17 | 5.5 | Água Doce |
| 20 | 7.5 | Água Doce |
| 19 | 8.0 | Água Doce |
| 23 | 6.0 | Água Doce |
| 22 | 9.5 | Água Doce |
| 18 | 10.5 | Água Doce |
| 21 | 6.5 | Água Doce |
| 22 | 10.0 | Água Doce |
| 26 | 2.0 | Água Doce |
| 15 | 3.0 | Água Doce |
| 22 | 8.5 | Água Doce |
| 14 | 3.5 | Água Doce |
| 15 | 5.0 | Água Salgada |
| 27 | 9.0 | Água Salgada |
| 22 | 4.0 | Água Salgada |
| 17 | 7.0 | Água Doce |
Muitas vezes não queremos alterar uma coluna já existente e sim criar uma nova coluna contendo novas informações para a base de dados. Colunas criadas pelo pesquisador geralmente são formadas por classificações ou estatísticas, podem ser tanto variáveis aleatórias quantitativas quanto qualitativas.
rm(list = ls())
IdPeixe = seq(1,20,1)
Quantidade = rbinom(20, 100, 0.20)
x = seq(1,10.5,0.5); nx = length(x); Média = sample(x, nx, replace = F)
y = c("Lago", "Rio", "Mar", "Lagoa"); Local = sample(y, nx, replace = T)
Tipo = Local
df = data.frame(IdPeixe, Quantidade, Média, Local)
for (i in 1:3) {
u = c("o", "a", "r")
w = c("Água Doce", "Água Doce", "Água Salgada")
Tipo = Tipo %>% endsWith(u[i]) %>% ifelse(w[i], Tipo)
}; df = cbind(df, Tipo)| IdPeixe | Quantidade | Média | Local | Tipo |
|---|---|---|---|---|
| 1 | 20 | 10.5 | Lago | Água Doce |
| 2 | 20 | 7.5 | Lago | Água Doce |
| 3 | 16 | 4.5 | Lago | Água Doce |
| 4 | 21 | 6.0 | Lagoa | Água Doce |
| 5 | 18 | 2.0 | Mar | Água Salgada |
| 6 | 15 | 1.5 | Lago | Água Doce |
| 7 | 18 | 8.0 | Lago | Água Doce |
| 8 | 17 | 5.5 | Mar | Água Salgada |
| 9 | 20 | 3.5 | Rio | Água Doce |
| 10 | 23 | 1.0 | Lago | Água Doce |
| 11 | 21 | 4.0 | Mar | Água Salgada |
| 12 | 23 | 9.0 | Lago | Água Doce |
| 13 | 14 | 3.0 | Mar | Água Salgada |
| 14 | 21 | 7.0 | Mar | Água Salgada |
| 15 | 24 | 2.5 | Rio | Água Doce |
| 16 | 26 | 10.0 | Mar | Água Salgada |
| 17 | 18 | 6.5 | Rio | Água Doce |
| 18 | 23 | 5.0 | Mar | Água Salgada |
| 19 | 25 | 8.5 | Lagoa | Água Doce |
| 20 | 19 | 9.5 | Rio | Água Doce |
Separando a base de dados em dois grupos referentes ao tipo de água do peixe. Os peixes de água salgada pertencem ao Grupo 1 e os de água doce ao Grupo 2. Para esse procedimento vamos utilizar a função filter().
grupo1 = filter(df, df$Tipo == "Água Salgada")
grupo2 = filter(df, df$Tipo == "Água Doce")| IdPeixe | Quantidade | Média | Local | Tipo |
|---|---|---|---|---|
| 5 | 18 | 2.0 | Mar | Água Salgada |
| 8 | 17 | 5.5 | Mar | Água Salgada |
| 11 | 21 | 4.0 | Mar | Água Salgada |
| 13 | 14 | 3.0 | Mar | Água Salgada |
| 14 | 21 | 7.0 | Mar | Água Salgada |
| 16 | 26 | 10.0 | Mar | Água Salgada |
| 18 | 23 | 5.0 | Mar | Água Salgada |
| IdPeixe | Quantidade | Média | Local | Tipo |
|---|---|---|---|---|
| 1 | 20 | 10.5 | Lago | Água Doce |
| 2 | 20 | 7.5 | Lago | Água Doce |
| 3 | 16 | 4.5 | Lago | Água Doce |
| 4 | 21 | 6.0 | Lagoa | Água Doce |
| 6 | 15 | 1.5 | Lago | Água Doce |
| 7 | 18 | 8.0 | Lago | Água Doce |
| 9 | 20 | 3.5 | Rio | Água Doce |
| 10 | 23 | 1.0 | Lago | Água Doce |
| 12 | 23 | 9.0 | Lago | Água Doce |
| 15 | 24 | 2.5 | Rio | Água Doce |
| 17 | 18 | 6.5 | Rio | Água Doce |
| 19 | 25 | 8.5 | Lagoa | Água Doce |
| 20 | 19 | 9.5 | Rio | Água Doce |
Podemos também utilizar a filtragem nativa do R. Neste caso, quantidades maiores ou iguais a 20 peixes pertencem ao Grupo 1 e quantidades menores que 20 peixes pertecem ao Grupo 2.
grupo1 = df[df$Quantidade >= 20,]
grupo2 = df[df$Quantidade < 20,]| IdPeixe | Quantidade | Média | Local | Tipo | |
|---|---|---|---|---|---|
| 1 | 1 | 20 | 10.5 | Lago | Água Doce |
| 2 | 2 | 20 | 7.5 | Lago | Água Doce |
| 4 | 4 | 21 | 6.0 | Lagoa | Água Doce |
| 9 | 9 | 20 | 3.5 | Rio | Água Doce |
| 10 | 10 | 23 | 1.0 | Lago | Água Doce |
| 11 | 11 | 21 | 4.0 | Mar | Água Salgada |
| 12 | 12 | 23 | 9.0 | Lago | Água Doce |
| 14 | 14 | 21 | 7.0 | Mar | Água Salgada |
| 15 | 15 | 24 | 2.5 | Rio | Água Doce |
| 16 | 16 | 26 | 10.0 | Mar | Água Salgada |
| 18 | 18 | 23 | 5.0 | Mar | Água Salgada |
| 19 | 19 | 25 | 8.5 | Lagoa | Água Doce |
| IdPeixe | Quantidade | Média | Local | Tipo | |
|---|---|---|---|---|---|
| 3 | 3 | 16 | 4.5 | Lago | Água Doce |
| 5 | 5 | 18 | 2.0 | Mar | Água Salgada |
| 6 | 6 | 15 | 1.5 | Lago | Água Doce |
| 7 | 7 | 18 | 8.0 | Lago | Água Doce |
| 8 | 8 | 17 | 5.5 | Mar | Água Salgada |
| 13 | 13 | 14 | 3.0 | Mar | Água Salgada |
| 17 | 17 | 18 | 6.5 | Rio | Água Doce |
| 20 | 20 | 19 | 9.5 | Rio | Água Doce |
Podemos, se necessário, transformar variáveis categóricas em numéricas ou vice e versa com o uso da função factor(). O nome desse procedimento chama-se encode, onde mudamos o tipo da variável. Este método pode ser utilizado para transformações de variáveis dicotômicas (Dummy; 1 ou 0; Sim ou Não), para correções necessárias ou procedimentos correlatos. Vamos considerar um experimento em que nosso sucesso (valor 1) seja capturar um peixe de água doce e nosso fracasso (valor 0) seja capturar um peixe de água salgada.
| IdPeixe | Quantidade | Média | Local | Tipo |
|---|---|---|---|---|
| 1 | 25 | 3.5 | Mar | Água Salgada |
| 2 | 20 | 1.0 | Lago | Água Doce |
| 3 | 26 | 10.0 | Rio | Água Doce |
| 4 | 24 | 8.5 | Rio | Água Doce |
| 5 | 19 | 9.0 | Lago | Água Doce |
| 6 | 22 | 9.5 | Mar | Água Salgada |
| 7 | 16 | 5.0 | Mar | Água Salgada |
| 8 | 19 | 6.5 | Rio | Água Doce |
| 9 | 28 | 6.0 | Mar | Água Salgada |
| 10 | 15 | 7.5 | Mar | Água Salgada |
| 11 | 20 | 10.5 | Lago | Água Doce |
| 12 | 21 | 7.0 | Mar | Água Salgada |
| 13 | 15 | 4.0 | Lago | Água Doce |
| 14 | 24 | 5.5 | Lago | Água Doce |
| 15 | 26 | 4.5 | Mar | Água Salgada |
| 16 | 26 | 8.0 | Mar | Água Salgada |
| 17 | 18 | 3.0 | Rio | Água Doce |
| 18 | 24 | 2.5 | Rio | Água Doce |
| 19 | 18 | 1.5 | Lago | Água Doce |
| 20 | 22 | 2.0 | Lago | Água Doce |
df$Tipo = factor(df$Tipo, levels = c("Água Doce", "Água Salgada"), labels = c( 1, 0))| IdPeixe | Quantidade | Média | Local | Tipo |
|---|---|---|---|---|
| 1 | 25 | 3.5 | Mar | 0 |
| 2 | 20 | 1.0 | Lago | 1 |
| 3 | 26 | 10.0 | Rio | 1 |
| 4 | 24 | 8.5 | Rio | 1 |
| 5 | 19 | 9.0 | Lago | 1 |
| 6 | 22 | 9.5 | Mar | 0 |
| 7 | 16 | 5.0 | Mar | 0 |
| 8 | 19 | 6.5 | Rio | 1 |
| 9 | 28 | 6.0 | Mar | 0 |
| 10 | 15 | 7.5 | Mar | 0 |
| 11 | 20 | 10.5 | Lago | 1 |
| 12 | 21 | 7.0 | Mar | 0 |
| 13 | 15 | 4.0 | Lago | 1 |
| 14 | 24 | 5.5 | Lago | 1 |
| 15 | 26 | 4.5 | Mar | 0 |
| 16 | 26 | 8.0 | Mar | 0 |
| 17 | 18 | 3.0 | Rio | 1 |
| 18 | 24 | 2.5 | Rio | 1 |
| 19 | 18 | 1.5 | Lago | 1 |
| 20 | 22 | 2.0 | Lago | 1 |
Este relatório teve como intuito apenas documentar meus progressos nos estudos de estatística e programação em R. Dominar a etapa de pré-processamento dos dados é fundamental para realizar bons modelos.
Contato: bruno.br.7@hotmail.com
Linkedin: https://www.linkedin.com/in/bruno-de-lima-teles-57a246247/