Skip to Content

Como lidar com valores faltantes (missing)?

Missings Dados faltantes Métodos de imputação

Introdução

Se você usar o código ou as informações deste guia em um trabalho publicado, solicito que cite-o como uma fonte nas referências bibliográficas.

DUTT-ROSS,Steven Como lidar com valores faltantes (missing)? Introdução aos métodos de imputação múltipla de dados faltantes. Rio de Janeiro. 2020. mimeo. Disponível em: https://blog.metodosquantitativos.com/missing/


Você não precisa usar o R, mas é uma boa ideia.


O objetivo desse texto é mostrar como usar as técnicas de imputação múltipla de dados ausentes. O procedimento padrão para lidar com dados faltanes é a exclusão de toda a linha do banco (listwise deletion). Vamos estudar outros métodos para além do procedimento básico. Antes vamos ver os tipos de dados faltantes.

Os dados ausentes podem ser definidos pelo mecanismo que leva à falta deles. Três principais tipos de dados ausentes (“Statistical analysis with missing data”, D. Rubin, R. Little):
• Falta completamente ao acaso (Missing completely at random - MCAR) - como “jogar uma moeda” para responder a uma questão; dados ausentes não dependem dos dados observados ou ausentes.
• Faltando aleatoriamente (Missing at random - MAR) - algo conhecido (dos dados ou de outra fonte) faz com que uma pessoa com menor probabilidade de responder a uma pergunta; dados ausentes depende dos dados observados e não não depende de dados não observados.
• Falta não-aleatória (Missing not at random - MNAR) (falta não ignorável) - algo (não conhecido/medido) diminui a probabilidade de uma pessoa responder a uma pergunta; os dados ausentes depende de algo não observado.

Banco de dados com valores ausentes

Para obter um banco de dados com valores ausentes, vamos pegar a base de dados CARROS e criar alguns valores ausentes.

source('https://raw.githubusercontent.com/DATAUNIRIO/Miscellaneous_Functions_Rstats/master/CARROS.R',encoding = "UTF-8")
set.seed(12345)
# Carregando a base de dados
CARROS<-as.matrix(CARROS[,c(1,3:7)])
CARROS_imp<-CARROS
missing_level<-0.3
# Retirando aleatoriamente uma amostra para gerar os missings
x1<-sample(1:length(CARROS[,1]),round(length(CARROS[,1])*missing_level),replace=F)
x2<-sample(1:length(CARROS[,1]),round(length(CARROS[,1])*missing_level),replace=F)
CARROS_imp[x1,2]<-NA
CARROS_imp[x2,5]<-NA
CARROS_imp2<-data.frame(CARROS_imp)
library(DT)
CARROS_imp %>% datatable(options = list(pageLength = 5, dom = 'tip'),fillContainer = FALSE,
caption = 'Tabela 1: Base de dados CARROS com dados faltantes.')

Alguns valores sumiram nessa base de dados.Podemos ver que o preço do Mazda RX4 Wag não foi observado. Também vemos que o peso do Mazda RX4 está faltando.

Como lidar com esses dados faltantes?

Acredito que o primeiro procedimento é contar o número de dados ausentes.

# contar o número de valores ausentes
paste0("Número de dados faltantes (Missing Values): ", sum(is.na(CARROS_imp)))
[1] "Número de dados faltantes (Missing Values): 20"

Mapa de dados faltantes (missing map)

library(visdat)
vis_dat(CARROS_imp2)
vis_miss(CARROS_imp2)

funções do Tidyr

A seguir, são apresentadas as três funções do tidyr para o processamento de valores ausentes (Missing Values).
1. drop_na() 2. fill() 3. replace_na()

drop_na() drop_na() remove as linhas com valores ausentes.

Como excluir observações ausentes

Muitos pesquisadores afirmam que a imputação múltipla de dados faltantes pode levar a viés no conjunto de dados. Além disso, pode resultar em modelos estatísticos ruins. Muitas vezes o melhor procedimento é deletar essas observações.

# drop_na
CARROS_drop_na <- CARROS_imp2 %>%
  drop_na()
# manter casos completos (complete.cases)
CARROS_drop_na  <- CARROS_imp[complete.cases(CARROS_imp), ]
# uso da função na.omit()
CARROS_drop_na  <- na.omit(CARROS_drop_na)
# remover colunas com mais de 30% de dados faltantes
CARROS_imp[, -which(colMeans(is.na(CARROS_imp)) > 0.3)]

Como substituir as observações ausentes

replace_na() deve ser usado quando você sabe o valor de substituição com o qual os valores ausentes (NAs) devem ser preenchidos.

Abaixo está um exemplo de como substituímos todas as NAs por apenas zero (0).

library(dplyr)
library(tidyr)

# replace_na
CARROS_na_replaced <- CARROS_imp %>%
  replace_na(0)

CARROS_na_replaced %>% datatable(options = list(pageLength = 5, dom = 'tip'),fillContainer = FALSE,
caption = 'Tabela 2: Base de dados CARROS com substituição por zero.')

Estratégias de imputação

Estrategia 1 - Expectation-Maximization (Algoritmo EM) e Expectation-Maximization com Bootstraping (Algoritmo EMB)

O algoritmo EM alterna entre a uma Experança matemática (Etapa E) e maximização (etapa M) até a convergência. A convergência é alcançada quando os valores atuais e anteriores estão próximos o suficiente um do outro (geralmente definido pelo analista). A ideia básica é que o dado ausente é correlacionado com outros dados presentes. Desse modo, usamos as variáveis existentes para preencher os “buracos” do banco de dados.

Para este método, vamos utilizar o procedimento “Amelia”. O Amelia faz o procedimento EM com Bootstrap. O Amelia utiliza os dados existentes para estimar os dados que não estão no banco de dados.

#-------------------------------------------
#  Estrategia 1 - Amelia
#-------------------------------------------

library(Amelia)
am<-amelia(CARROS_imp,  k=5)  
-- Imputation 1 --

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 

-- Imputation 2 --

 1  2  3  4  5  6  7  8  9 10 

-- Imputation 3 --

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 
21 22 23 24 25 26 27 28 

-- Imputation 4 --

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 
221 222 223 224 

-- Imputation 5 --

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 
61 62 63 64 65 66 67 68 69 
# Media dos cinco tipos de imputação
amelia_imp<-(am$imputations$imp1+am$imputations$imp2+am$imputations$imp3+am$imputations$imp4+am$imputations$imp5)/5

O AMELIA fornece todos os valores imputados, mas sua precisão é determinada pela sua proximidade com os valores originais.

Na base original, podemos ver que o preço do Mazda RX4 Wag era de R$ 160.000,00 e o peso do Mazda RX4 era 2.620 toneladas. Vamos usar essas informações para a comparação com o valor imputado.

O procedimento AMELIA estimou um preço de R$ 174.202,32 (errou em 14 mil). A estimativa para o peso foi peso de 2.618510 (erro pequeno). Vamos calcular todas essas diferenças, elevar ao quadrado e somá-las em um procedimento parecido com a variância.

Em resumo, como temos os dados originais, podemos avaliar a precisão do método.

# precisão
precisao_amelia_preco<-sqrt(sum((CARROS[,2]-amelia_imp[,2])^2))/sum(length(x1))
precisao_amelia_peso <-sqrt(sum((CARROS[,5]-amelia_imp[,5])^2))/sum(length(x2))
# precisão ???
#precisão_amelia<-sqrt(sum((CARROS[,2]-amelia_imp[,2])^2,  (CARROS[,5]-amelia_imp[,5])^2))/sum(length(x1),length(x2))  

#precisao_amelia
paste0("O Erro médio quadrado da variável preço: ", precisao_amelia_preco)
[1] "O Erro médio quadrado da variável preço: 18.4717284577018"
paste0("O Erro médio quadrado da variável peso: ", precisao_amelia_peso)
[1] "O Erro médio quadrado da variável peso: 0.168897019244796"

Parece que o procedimento é melhor na variável peso do que na variável preço.

Estrategia 2 - K-Nearest Neighbor (Algoritmo KNN)

O algoritmo KNN, muito popular em machine learning, pode ser usado para problemas preditivos de classificação e regressão.No entanto, é mais amplamente utilizado em problemas de classificação. Neste método, o aprendizado é baseado “no quão similar” é um dado (um vetor) do outro.

De acordo com a documentação, KnnImputation - É uma função disponível no pacote DMwR destinada à imputação e trabalha com o princípio do vizinho mais próximo, de modo que imputa um valor específico calculando a média dos membros mais próximos e é usado principalmente para variáveis numéricas.

Para essa estratégia de imputação,vamos utilizar o pacote DMwR. Esse é um acrônimo para Data Mining with R - DMwR.

#-------------------------------------------
# Estrategia 2 - KNN
#-------------------------------------------
library(DMwR)
CARROS_KNN <- knnImputation(CARROS_imp)

Vamos agora avaliar a precisão do método.

precisao_KNN_preco<-sqrt(sum((CARROS[,2]-CARROS_KNN[,2])^2))/sum(length(x1))
precisao_KNN_peso <-sqrt(sum((CARROS[,5]-CARROS_KNN[,5])^2))/sum(length(x2))

#precisao
paste0("O Erro médio quadrado da variável preço: ", precisao_KNN_preco)
[1] "O Erro médio quadrado da variável preço: 13.9448922478246"
paste0("O Erro médio quadrado da variável peso: ", precisao_KNN_peso)
[1] "O Erro médio quadrado da variável peso: 0.187529529743591"

Parece que o procedimento é melhor na variável preço do que na variável peso.

Estrategia 3 - Imputação via modelos de regressão bayesiana

Uma outra abordagem de imputação muito utilizada é via modelos de regressão bayesiana. Para isso, vamos utilizar o pacote mi.

#-------------------------------------------
#  Estrategia 3 - MI
#-------------------------------------------
library(mi)
# Imputacao via mi
mult_imp<-mi(missing_data.frame(CARROS_imp),  n.chains=5)  #Multiple  Imputation
mi_imp<-(complete(mult_imp)[[1]][,1:6]+complete(mult_imp)[[2]][,1:6]+complete(mult_imp)[[3]][,1:6]+complete(mult_imp)[[4]][,1:6]+complete(mult_imp)[[5]][,1:6])/5

Vamos agora avaliar a precisão do método 3.

precisao_MI_preco<-sqrt(sum((CARROS[,2]-mi_imp[,2])^2))/sum(length(x1))
precisao_MI_peso<-sqrt(sum((CARROS[,5]-mi_imp[,5])^2))/sum(length(x2))

#precisao
paste0("O Erro médio quadrado da variável preço: ", precisao_MI_preco)
[1] "O Erro médio quadrado da variável preço: 19.2726249324717"
paste0("O Erro médio quadrado da variável peso: ", precisao_MI_peso)
[1] "O Erro médio quadrado da variável peso: 0.150190606298451"

Estrategia 4 - Imputação via modelos de regressão

#-------------------------------------------
#  Estrategia 4 MI
#-------------------------------------------
library(VIM)
imp1<-regressionImp(Preco~Kmporlitro+HP+Amperagem_circ_eletrico+RPM,  data=CARROS_imp)  #Regression
imp2<-regressionImp(Peso~Kmporlitro+HP+Amperagem_circ_eletrico+RPM,  data=CARROS_imp)
regressao_imp<-cbind(CARROS_imp[,1],imp1$Preco,  CARROS_imp[,3:4],imp2$Peso,CARROS_imp[,6])

Vamos agora avaliar a precisão do método 4.

precisao_REG_preco<-sqrt(sum((CARROS[,2]-regressao_imp[,2])^2))/sum(length(x1))
precisao_REG_peso<-sqrt(sum((CARROS[,5]-regressao_imp[,5])^2))/sum(length(x2))

#precisao
paste0("O Erro médio quadrado da variável preço: ", precisao_REG_preco)
[1] "O Erro médio quadrado da variável preço: 24.2499381503542"
paste0("O Erro médio quadrado da variável peso: ", precisao_REG_peso)
[1] "O Erro médio quadrado da variável peso: 0.157187146842914"

Estrategia 5 e 6 - MissForest e Multivariate Imputation via Chained Equations - MICE

Temos duas ostras estratégicas interessantes chamadas de MissForest e MICE. Vou deixar ao leitor encontrar as funções de imputação desses pacotes e construir a métrica de precisão.

#-------------------------------------------#  Estrategia 5 - missForest
#-------------------------------------------
library(missForest)

#-------------------------------------------#  Estrategia 6 - MICE
#-------------------------------------------
library(mice)
md.pattern(CARROS_imp)

Qual é o melhor mecanismo de imputação?

A melhora abordagem será aquela que tiver o menor erro médio.

Para saber sobre outras funções no R e no Python, você pode acessar o meu blog https://blog.metodosquantitativos.com/ ou o meu site pessoal https://steven.metodosquantitativos.com/