Pular para o conteúdo principal

Visualize dados ausentes com o pacote VIM

Aprenda a usar as ferramentas de visualização do pacote VIM para obter insights rápidos sobre padrões de dados ausentes.
Atualizado 17 de set. de 2026  · 13 min lido

Explorar com IA

ChatGPTClaudePerplexity

Dados ausentes são um problema no dia a dia de todo cientista de dados. Devemos imputá-los? Se sim, qual método é adequado? Ou dá para simplesmente excluir observações com pontos ausentes? Para responder, é preciso entender o mecanismo por trás dos dados ausentes. Detectá-lo com testes estatísticos é complexo e, às vezes, só leva a conclusões vagas. Já as ferramentas de visualização são fáceis de usar e ajudam não só a identificar mecanismos de ausência, como também a revelar outros aspectos da qualidade dos dados. Neste tutorial, apresentamos um conjunto de métodos de plotagem disponíveis no pacote VIM para mostrar como eles podem ajudar você a entender, de forma sólida, quais são os padrões de ausência nos dados.

Mecanismos de dados ausentes

Há vários motivos para um dataset estar incompleto. É essencial investigar as possíveis causas de ausência, pois isso impacta a forma como vamos tratar o problema. Por exemplo, em pesquisas sobre trabalho, é razoável esperar que os respondentes mais ricos e os mais pobres não informem seus rendimentos no questionário, o que significa que os pontos ausentes não estão distribuídos de maneira uniforme no conjunto de dados. Se for esse o caso, simplesmente remover observações incompletas antes da análise pode gerar vieses. Por outro lado, se os dados faltam por falha do dispositivo de coleta, pode ser que os locais dos pontos ausentes no dataset sejam puramente aleatórios.

Existem três padrões distintos segundo os quais os dados podem estar ausentes. Eles são chamados, em geral, de mecanismos de dados ausentes.

  • Missing completely at random (MCAR)
    Sob MCAR, não há padrão sistemático na localização dos pontos ausentes no dataset: eles ocorrem totalmente ao acaso. Formalmente, isso significa que a probabilidade de uma observação estar ausente não depende dos valores de outras variáveis nem de seus próprios valores. Nesse caso, excluir observações incompletas não introduziria viés nos resultados da análise.
    Exemplo: A temperatura é medida continuamente por um sensor que coleta os dados e os envia via Internet para um banco de dados. Por motivos desconhecidos, a conexão cai às vezes.

  • Missing at random (MAR)
    Sob MAR, a probabilidade de uma observação específica estar ausente ainda é independente de seus próprios valores, mas depende dos valores de outras variáveis. Nesse cenário, remover observações incompletas torna a amostra menos representativa.
    Exemplo: Parte dos dados do período noturno faltam devido a manutenções do sensor, que sempre ocorrem à noite.

  • Missing not at random (MNAR)
    Sob MNAR, a probabilidade de uma observação estar ausente depende de seus próprios valores não observados. Novamente, excluir dados incompletos leva a análises enviesadas.
    Exemplo: O sensor congela a -20 graus Celsius e não mede temperaturas abaixo desse valor.

Na prática, é difícil dizer qual dos três mecanismos se aplica a um caso específico. Para ver isso, vamos plotar alguns dados MNAR. Usaremos os pacotes ggplot2 e gridExtra, que precisamos carregar antes. Também carregaremos outros dois para uso posterior: VIM para análise visual de dados ausentes e dplyr para pré-processamento. Lembre-se de rodar install.packages() se eles ainda não estiverem no seu ambiente.

library(\"VIM\")
library(\"dplyr\")
library(\"ggplot2\")
library(\"gridExtra\")

Vamos criar um dataset com duas variáveis não correlacionadas e normalmente distribuídas, x e y, com alguns valores ausentes em y na cauda direita da distribuição, ou seja, entre seus valores mais altos. Note que também guardamos os valores reais e os marcamos como ausentes em uma variável separada.

set.seed(2)
mnar_data <- data.frame(x = rnorm(100), y = rnorm(100)) %>%
    mutate(y_miss = ifelse(y > 1, y, NA),
           y = ifelse(is.na(y_miss), y, NA),
           x_miss = ifelse(is.na(y), x, NA))

Agora vamos desenhar dois gráficos de dispersão de x contra y: um incluindo os pontos cujos valores de y estamos simulando como ausentes e outro apenas com os dados observados.

grid.arrange(
  # Gráfico destacando pontos ausentes
  ggplot(mnar_data, aes(x, y)) +
    geom_point(size = 4, alpha = 0.6) +
    geom_point(aes(x, y_miss), col = \"red\", size = 4, alpha = 0.6) +
    geom_hline(aes(yintercept = y_miss), col = \"red\", alpha = 0.6,
               linetype = \"dashed\") +
    ylim(NA, max(mnar_data$y_miss, na.rm = TRUE)) +
    ggtitle(\"Where the data points are missing\"),
  # O que o cientista de dados consegue ver
  ggplot(mnar_data, aes(x, y)) +
    geom_point(size = 4, alpha = 0.6) +
    geom_vline(aes(xintercept = x_miss), col = \"red\", alpha = 0.6,
               linetype = \"dashed\") +
    ylim(NA, max(mnar_data$y_miss, na.rm = TRUE)) +
    ggtitle(\"What the data scientist can see\"),
  # Dispor os dois gráficos lado a lado
  ncol = 2
)
\"scatter

Embora no primeiro gráfico fique claro que os dados são de fato MNAR, o que o cientista de dados consegue ver são apenas as coordenadas x dos pontos ausentes. Que conclusão tiramos do segundo gráfico? Os dados são MCAR? Possivelmente sim, as localizações dos valores ausentes parecem bem espalhadas ao longo do eixo x. Ou seriam MAR? Olhando com mais cuidado, parece haver mais ausências em y para valores negativos de x do que para os positivos, então essa também é uma hipótese. Por fim, MNAR nunca pode ser descartado: para saber se os dados são MNAR, precisaríamos, por definição, observar os valores não observados.

Felizmente, não ficamos totalmente no escuro. Ferramentas de visualização podem orientar sobre que padrões existem nas ausências. Agora vamos analisar alguns gráficos úteis para detectar esses padrões usando o dataset biopics do pacote fivethirtyeight, que reúne informações sobre filmes biográficos.

Limpeza de dados

Antes de partir para os gráficos, precisamos fazer um pré-processamento. O bloco de código abaixo resolve. A chamada a select no início do pipeline do dplyr extrai as variáveis de interesse, e o mutate seguinte agrupa raças relacionadas para termos observações suficientes em cada grupo. Em seguida, ajustamos a classe de algumas variáveis: precisamos de factors para variáveis de texto e de inteiros para a variável lógica. Por fim, renomeamos as variáveis para nomes mais curtos, facilitando a leitura dos gráficos.

data(biopics, package = \"fivethirtyeight\")

biopics <- biopics %>%
  select(country, year_release, box_office, number_of_subjects,
         type_of_subject, subject_race, person_of_color, subject_sex) %>%
  mutate(subject_race = ifelse(grepl(\"^Hispanic\", subject_race), \"Hispanic\",
                               subject_race),
         subject_race = ifelse(grepl(\"^African\", subject_race), \"African\",
                               subject_race),
         subject_race = ifelse(grepl(\"^Middle\", subject_race), \"Mid Eastern\",
                               subject_race),
         subject_race = ifelse(subject_race %in% c(\"White\", \"Asian\", \"African\",
                                                   \"Hispanic\", \"Mid Eastern\",
                                                   \"Multi racial\", NA),
                               subject_race, \"other\")) %>%
  mutate(country = as.factor(country),
         type_of_subject = as.factor(type_of_subject),
         subject_race = as.factor(subject_race),
         subject_sex = as.factor(subject_sex),
         person_of_color = as.integer(person_of_color)) %>%
      as.data.frame()

colnames(biopics) <- c(\"country\", \"year\", \"earnings\", \"sub_num\",
                       \"sub_type\", \"sub_race\", \"non_white\", \"sub_sex\")

Ficamos com um dataset composto por oito variáveis:

  • country - país ou países de origem do filme,
  • year - ano de lançamento,
  • earnings - bilheteria bruta nos EUA,
  • sub_num - quantidade de personagens retratados no filme,
  • sub_type - ocupação do personagem ou motivo do reconhecimento,
  • sub_race - raça do personagem,
  • non_white - variável indicadora para pessoa não branca,
  • sub_sex - sexo do personagem.

Gráficos de agregação

A primeira pergunta, fundamental, é: em quais variáveis há ausências e quantas são? Os gráficos de agregação ajudam a responder. A linha abaixo é tudo o que você precisa.

aggr(biopics, numbers = TRUE, prop = c(TRUE, FALSE))
\"aggregation

Especificamos numbers = TRUE para exibir os números no topo das barras. O argumento prop indica se devemos usar a proporção de valores ausentes e combinações em vez do total. Definimos TRUE para o primeiro gráfico e FALSE para o segundo.

Fica claro que há ausências apenas em duas variáveis: mais de 40% em earnings e cerca de 25% em sub_race. No gráfico de combinações à direita, a grade apresenta todas as combinações de valores ausentes (vermelho) e observados (azul) presentes nos dados. Há 317 observações completas e, em 77 linhas, ambas as variáveis estão ausentes.

Olhar para dois gráficos ao mesmo tempo pode confundir, então vamos condensar as mesmas informações em uma única visualização com a linha a seguir.

aggr(biopics, combined = TRUE, numbers = TRUE)

O argumento combined permite juntar os dois gráficos em um só. À direita da grade, as barras horizontais mostram as frequências das combinações correspondentes, enquanto as barras verticais na parte superior apresentam as proporções de ausências em cada variável. Somando os valores de todas as combinações para earnings (0,32 e 0,10), vemos que a proporção total de ausências nessa variável, estimada antes como acima de 40%, é na verdade 42%.

Spinogram e spineplot

Até aqui tivemos uma visão geral dos dados ausentes. É hora de olhar mais de perto as interações entre variáveis específicas. Spinogram e spineplot permitem estudar a porcentagem de ausências em uma variável para diferentes valores de outra. Se a variável de divisão for numérica, temos um spinogram; quando é categórica, a visualização é chamada de spineplot.

Ambos podem ser gerados com a função spineMiss(), que recebe um data frame com duas colunas. A primeira variável especificada é aquela segundo a qual os dados serão divididos e é mapeada para o eixo horizontal. A segunda é a que queremos investigar quanto ao padrão de ausências. Para ver na prática, vamos criar um spineplot. Indicamos primeiro a variável categórica sub_race, seguida de earnings, que você pode ler assim: qual é a porcentagem de ausências em earnings para cada categoria de sub_race?

spineMiss(biopics[, c(\"sub_race\", \"earnings\")])
\"Spinogram

A largura relativa das barras para as categorias de sub_race reflete a frequência dessa categoria no dataset: por exemplo, na grande maioria dos filmes o personagem principal é branco. Dentro de cada barra, vemos a proporção de ausências em earnings, enquanto a barra sombreada à direita mostra essa proporção no conjunto inteiro. Parece que, quando o personagem principal é africano, é mais provável termos a informação completa de bilheteria.

Invertendo a ordem das variáveis como abaixo, produzimos um spinogram respondendo à pergunta inversa: qual é a porcentagem de ausências em sub_race para diferentes valores de earnings?

spineMiss(biopics[, c(\"earnings\", \"sub_race\")])
\"Spinogram

Como earnings é numérica, seus valores são divididos em bins, cujas larguras correspondem à distribuição da própria variável. O spinogram mostra que earnings é fortemente assimétrica à direita: apenas alguns filmes tiveram a maior arrecadação. Curiosamente, para esses blockbusters, é mais provável faltar a raça do personagem, como indica a barra vermelha mais alta nos maiores valores de earnings.

Gráfico mosaico

O spinogram e o spineplot permitem estudar interações entre duas variáveis. Essa ideia se generaliza para mais variáveis por meio do gráfico mosaico. Esse gráfico é um conjunto de ladrilhos, em que cada ladrilho corresponde a uma combinação específica de categorias (para variáveis categóricas) ou bins (para variáveis numéricas) de duas ou mais variáveis. Dentro de cada ladrilho, mostramos a porcentagem de ausências em outra variável. Em princípio, é possível criar gráficos mosaico para qualquer quantidade de variáveis, mas eles podem ficar poluídos com muitas divisões. Também são mais legíveis quando as variáveis de divisão são factors com poucos níveis.

Vamos analisar a proporção de ausências em earnings dividida por sub_sex e US_movie. Esta última, criada no bloco abaixo, é uma variável lógica que indica se os Estados Unidos participaram da produção do filme. Fornecemos o data frame com três variáveis como primeiro argumento para mosaicMiss(). O argumento plotvars, definido como o vetor 1 e 2, indica que queremos dividir os dados pelas duas primeiras colunas. Definir highlight como 3 quer dizer que desejamos exibir, dentro dos ladrilhos, a proporção de ausências da variável da terceira coluna.

biopics <- biopics %>%
    mutate(US_movie = ifelse(grepl(\"US\", country), TRUE, FALSE))
mosaicMiss(biopics[, c(\"sub_sex\", \"US_movie\", \"earnings\")], highlight = 3,
           plotvars = 1:2, miss.labels = FALSE)
\"Mosaic

Novamente, os tamanhos dos ladrilhos correspondem às frequências das combinações no dataset. Por exemplo, o maior ladrilho inferior direito indica que a maioria dos filmes tem personagem masculino e foi produzida, ao menos em parte, nos EUA.

Para filmes com personagem principal masculino, a informação de bilheteria tende a faltar mais quando não são americanos. Já quando a personagem principal é feminina, os filmes dos EUA têm ligeiramente mais ausências em bilheteria. As diferenças, no entanto, parecem pequenas demais para serem significativas.

Boxplot paralelo

Outro tipo de visualização é o boxplot paralelo. A ideia é dividir o dataset em dois subconjuntos: um apenas com valores observados de uma variável incompleta e outro apenas com seus valores ausentes. Para ambos, construímos um boxplot de uma variável numérica escolhida. Isso permite verificar se a distribuição da variável escolhida é afetada pelas ausências da variável de divisão.

Para produzir um boxplot paralelo, usamos a função pbox(). Passamos um único argumento: um data frame com duas colunas. Os boxplots serão desenhados para a variável na primeira coluna, enquanto a segunda será usada para a divisão. No exemplo abaixo, aplicamos log em earnings, pois a distribuição é altamente assimétrica e, sem essa transformação, o boxplot ficaria como uma linha só.

biopics <- biopics %>%
  mutate(log_earnings = log(earnings))
pbox(biopics[, c(\"log_earnings\", \"sub_race\")])
\"Parallel

A caixa branca à esquerda mostra a distribuição geral de log_earnings, enquanto as caixas azul e vermelha mostram a distribuição para os subconjuntos com valores observados e ausentes em sub_race, respectivamente. A largura relativa das caixas reflete o tamanho dos subconjuntos: a caixa azul mais larga indica que há mais valores observados do que ausentes em sub_race. Fora isso, as duas caixas são parecidas entre si e com a caixa branca geral. Isso sugere que a ausência de informação sobre raça não impacta a distribuição de bilheteria.

Gráfico de coordenadas paralelas

Já vimos variáveis isoladas e suas interações. Agora vamos analisar todas as variáveis do dataset de uma vez. A visualização adequada é o gráfico de coordenadas paralelas. Nele, cada variável é transformada para a mesma escala e representada por um eixo paralelo. No caso de variáveis categóricas, a escala do eixo é dividida em pontos equidistantes, um para cada categoria. Valores ausentes ficam acima dos eixos verticais, fora da área do gráfico. Cada linha representa uma observação, e a cor da linha indica ausências na variável selecionada.

Podemos gerar o gráfico com a função parcoordMiss(). Por padrão, ela usa todas as variáveis do data frame fornecido como primeiro argumento. Definir highlight como earnings pinta de outra cor as linhas das observações com valor ausente em earnings. Definir alpha-blending em 0,6 deixa as linhas levemente transparentes, melhorando a leitura.

# Remover variáveis criadas para os gráficos anteriores
biopics <- biopics %>%
  select(- US_movie, - log_earnings)

parcoordMiss(biopics, highlight = 'earnings', alpha = 0.6)
\"Parallel

No gráfico acima, as linhas vermelho-escuro indicam observações com valor ausente em earnings. Essas observações destacadas parecem se comportar de forma diferente do restante. Em particular, poucas delas pertencem ao segundo nível mais alto de country, que, de outra forma, concentra muitas observações! Descobrimos que se trata de filmes US/UK (para ver, rode levels(biopics$country) e procure o penúltimo valor!).

Além disso, uma olhada rápida no eixo year revela uma faixa, em torno de dois terços de sua altura, com menos linhas vermelho-escuro cruzando. Parece ter havido um período, não muito distante, com dados de bilheteria mais completos. Isso sugere que country e year podem ajudar a explicar a distribuição de ausências em earnings!

Gráfico de matriz

A última ferramenta de visualização que veremos é o gráfico de matriz. Ele visualiza todas as células da matriz de dados como retângulos. Os dados observados aparecem em uma escala contínua de cinza a preto (quanto mais escuro, maior o valor), enquanto os ausentes são destacados em vermelho. É uma boa prática ordenar os dados por uma das variáveis incompletas — isso facilita a interpretação. O bloco abaixo faz isso, ordenando por earnings.

matrixplot(biopics, sortby = c('earnings'))
\"Matrix

O gráfico confirma alguns achados anteriores: observações com valores ausentes em earnings tendem a ser de muito tempo atrás (valores baixos em year) e também têm valores baixos em country — indicado pela cor mais clara dessas duas variáveis nas linhas em que earnings está em vermelho. Além disso, parece haver menos filmes com personagem não branco quando earnings está ausente.

Conclusões

Resumindo, parece que os dados ausentes no dataset biopics não são MCAR. As localizações de ausências em earnings e sub_race ajudam a explicar uma à outra, como mostrado pelo spineplot e pelo spinogram. Além disso, o gráfico de matriz e o de coordenadas paralelas sugerem que country, year e non_white também podem ajudar a explicar a distribuição de ausências em earnings. Portanto, não é uma boa ideia excluir as observações incompletas, pois isso muito provavelmente introduziria viés na nossa inferência.

Considerações finais

Você chegou até aqui! Agora você sabe o que são mecanismos de dados ausentes, como eles diferem e, mais importante, como investigá-los com várias ferramentas de visualização. Mandou bem! Você está pronto para analisar seus próprios datasets incompletos!

Se quiser aprender mais sobre R, faça o curso Data Visualization with ggplot2 (Part 1) da DataCamp e confira nosso R Formula Tutorial.

Tópicos
Visualização de dados
Ciência de dados

Aprenda mais sobre R e visualização de dados

Curso

Introdução à Visualização de Dados com ggplot2

4 h
188.2K
Aprenda a produzir visualizações de dados impactantes e atraentes com o ggplot2, compreendendo a gramática dos gráficos.
Ver detalhesRight Arrow
Iniciar Curso
Ver maisRight Arrow
Relacionado

blog

11 técnicas de visualização de dados para cada caso de uso com exemplos

Descubra as análises, técnicas e ferramentas mais populares para dominar a arte do assistente de visualização de dados
Javier Canales Luna's photo

Javier Canales Luna

12 min

blog

Explorando 12 das melhores ferramentas de visualização de dados em 2023 com exemplos

Há muitas ferramentas de visualização de dados disponíveis. Neste artigo, preparamos uma lista abrangente de algumas das ferramentas de visualização de dados mais úteis na ciência de dados.
Javier Canales Luna's photo

Javier Canales Luna

12 min

blog

As 10 melhores ferramentas de ciência de dados para usar em 2026

As ferramentas essenciais de ciência de dados para iniciantes e profissionais da área para coletar, processar, analisar, visualizar e modelar os dados de forma eficiente.
Abid Ali Awan's photo

Abid Ali Awan

9 min

Tutorial

Principais técnicas para lidar com valores ausentes que todo cientista de dados deve conhecer

Explore várias técnicas para lidar eficientemente com valores ausentes e suas implementações em Python.
Zoumana Keita 's photo

Zoumana Keita

15 min

Tutorial

Histogramas no Matplotlib

Aprenda sobre histogramas e como você pode usá-los para obter insights dos dados com a ajuda do matplotlib.
Aditya Sharma's photo

Aditya Sharma

8 min

Tutorial

Tutorial do Power BI para iniciantes

Aprenda os conceitos básicos do Power BI e como criar um relatório básico com este tutorial passo a passo.
DataCamp Team's photo

DataCamp Team

13 min

Ver MaisVer Mais