Preparação de Dados para análise

Inovação Tecnológica e Processos de Desenvolvimento

Anderson Ribeiro Duarte

Introdução

Dados reais, problemas reais.

Autor desconhecido

Durante todo o curso de Estatística ou afins, como recurso didático, são apresentados diversos conjuntos de dados aos alunos. Esta apresentação tem como principal objetivo o aprendizado prático das técnicas aprendidas em sala de aula. De modo geral, esses conjuntos de dados apresentam uma estrutura ideal para a implementação de determinada técnica, para que o foco total do aluno esteja voltado para a utilização da técnica em si.

Introdução (continuação)

Entretanto, no momento em que o aluno se depara com um conjunto de dados reais, habitualmente ocorrem algumas dificuldades na utilização de dados reais. Quase sempre ocorrem erros na aplicação das técnicas, geralmente causados por alguma inconsistência nos dados. Isto ocorre devido ao fato de que, diferente das bases de dados fictícias, ou previamente organizadas, dados reais não são perfeitos, muito pelo contrário.

Introdução (continuação)

De modo geral, dados reais apresentam uma série de problemas estruturais, que podem ser causados por diversas fontes, desde erros de digitação, problemas na importação entre softwares, aparecimento de dados corrompidos, dentre outras diversas possibilidades.

Introdução (continuação)

É de extrema importância que tais inconsistências sejam solucionadas antes da realização de qualquer análise ou modelagem, pois a presença dessas inconsistências podem levar à geração de resultados enganosos, a modelos de pouca precisão e à conclusões equivocadas.

Este processo de pré-processamento dos dados tendem a ser bastante trabalhosos. Estima-se que em uma análise de dados, de 70 a 80% do tempo é gasto durante a etapa de pré-processamento, etapa esta que inclui a preparação, organização e estruturação dos dados.

Introdução (continuação)

Na próxima seção, trataremos dos principais problemas e apresentaremos algumas formas de solucionar aqueles mais frequentes. Porém, antes mesmo de iniciar a preparação dos dados para análise, por meio da correção dos possíveis problemas, é importante conhecer razoavelmente a estrutura dos dados. Nesse sentido, uma das ferramentas mais úteis é o Dicionário de Dados.

Dicionário de dados

O dicionário de dados é uma tabela na qual os dados em estudo são descritos. Sua construção auxilia o analista a compreender melhor a constituição do conjunto de dados. O dicionário de dados geralmente consiste em uma tabela na qual informações sobre o conjunto de dados são inseridas. Cada variável é inserida em uma linha e as características relacionadas à variável são incluídas nas colunas. As principais informações são as seguintes:

  • Nome da variável

  • Descrição da variável

  • Tipo de variável

  • Níveis da variável, caso seja uma variável qualitativa

Dicionário de dados

Outros campos podem ser adicionados, como contagem de valores faltantes, se a variável é a transformação de alguma outra, e assim sucessivamente.

No R, existem alguns pacotes para a construção de dicionários de dados com base em conjuntos de dados iniciais. Podemos por exemplo visualizar as variáveis, seu tipo e seus primeiros valores usando as funções str, nativa do R, ou a função glimpse do pacote dplyr. Porém queremos construir um dicionário com mais detalhes. Para isso, vamos trabalhar com o pacote labelled.

Dicionário de dados

O pacote labelled foi desenvolvido para trabalhar com dados do Stata e SPSS, que naturalmente apresentam rótulos. Entretanto ele possui duas funções que são excelentes para a construção de dicionários de dados em quaisquer data frames.

  • generate_dictionary: gera um dicionário de dados a partir de um data frame, incluindo seu tipo, nome e níveis no caso de fatores e a contagem de dados faltantes.

  • set_variable_labels: permite atribuir a descrição da variável com base em uma lista que relaciona o nome da variável à sua descrição.

Dicionário de dados

Vejamos um exemplo com o conjunto de dados iris:

#Estrutura do banco de dados
iris %>% 
  str
'data.frame':   150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

Dicionário de dados

Observe que o banco de dados possui 5 variáveis:

  • Sepal.Length: comprimento da sépala

  • Sepal.Width: largura da sépala

  • Petal.Length: comprimento da pétala

  • Petal.Width: largura da pétala

  • Species: Espécie da flor

Dicionário de dados

Vamos construir o dicionário de dados com o uso da função generate_dictionary:

pacman::p_load(labelled)

#Geração do dicionário de variáveis do banco de dados iris
iris %>% 
  generate_dictionary()
 pos variable     label col_type missing values    
 1   Sepal.Length —     dbl      0                 
 2   Sepal.Width  —     dbl      0                 
 3   Petal.Length —     dbl      0                 
 4   Petal.Width  —     dbl      0                 
 5   Species      —     fct      0       setosa    
                                         versicolor
                                         virginica 

Note que os níveis foram inseridos em linhas distintas para a variável Species.

Dicionário de dados

Podemos corrigir esse posicionamento com o uso da função convert_list_columns_to_character. Vamos aproveitar e incluir a descrição das variáveis usando a função var_label.

#Geração do dicionário de variáveis do banco de dados iris
dicionario <- iris %>% 
  set_variable_labels(Sepal.Length = "comprimento da sépala", #Adiciona a descrição
                 Sepal.Width = "largura da sépala",
                 Petal.Length = "comprimento da pétala",
                 Petal.Width = "largura da pétala",
                 Species = "Espécie da flor") %>% 
  generate_dictionary() %>% 
  convert_list_columns_to_character()

#Visualização do dicionário
dicionario
# A tibble: 5 × 7
    pos variable     label                 col_type missing levels  value_labels
  <int> <chr>        <chr>                 <chr>      <int> <chr>   <chr>       
1     1 Sepal.Length comprimento da sépala dbl            0 ""      ""          
2     2 Sepal.Width  largura da sépala     dbl            0 ""      ""          
3     3 Petal.Length comprimento da pétala dbl            0 ""      ""          
4     4 Petal.Width  largura da pétala     dbl            0 ""      ""          
5     5 Species      Espécie da flor       fct            0 "setos… ""          

Dicionário de dados

Sempre que ocorrerem alterações no banco de dados, é necessário atualizar o dicionário. Desse modo, o ideal é que um script à parte seja responsável por esse objeto.

Agora que já conhecemos uma forma de construir o dicionário de dados, vamos passar para os problemas mais comuns na preparação de dados para análise.

Problemas mais comuns na preparação de dados

Conforme mencionado, existem diversas possibilidades de problemas e inconsistências em bases de dados. Nesta seção, trabalharemos com as mais frequentes. Trataremos dos mais frequentes, na seguinte ordem:

  • Problemas nos nomes das variáveis;

  • Dados duplicados;

  • Dados com ruído;

  • Dados faltantes; ;

  • Outliers.

Problemas com nomes de variáveis

Muitas vezes, no momento da tabulação de dados, o usuário define os rótulos das variáveis de modo a facilitar seu preenchimento, seja por ele mesmo, seja por terceiros. Por este motivo, ao efetuar a leitura de conjuntos de dados, frequentemente nos deparamos com alguns problemas nos nomes das variáveis. Estes problemas podem gerar alguns contratempos na análise de dados.

Problemas com nomes de variáveis

Em arquivos do tipo .txt por exemplo, a presença de espaços nos títulos de variáveis impede a leitura do arquivo. Entretanto, uma vez realizada a leitura, muitas vezes o trabalho de análise de dados é dificultado por uma má definição dos nomes das variáveis.

Problemas com nomes de variáveis

Vamos utilizar a base de dados das músicas mais tocadas em 2024 no spotify. Vamos efetuar a importação e checar os nomes das variáveis.

#Como os dados são separados por vírgula, utilizaremos a função read.csv
dados_spotify <- read.csv("datasets/a6_pre_processamento/Spotify Songs 2024.csv")  

#Rótulos antes da correção 
glimpse(dados_spotify)
Rows: 4,600
Columns: 29
$ Track                      <chr> "MILLION DOLLAR BABY", "Not Like Us", "i li…
$ Album.Name                 <chr> "Million Dollar Baby - Single", "Not Like U…
$ Artist                     <chr> "Tommy Richman", "Kendrick Lamar", "Artemas…
$ Release.Date               <chr> "4/26/2024", "5/4/2024", "3/19/2024", "1/12…
$ ISRC                       <chr> "QM24S2402528", "USUG12400910", "QZJ8424003…
$ All.Time.Rank              <chr> "1", "2", "3", "4", "5", "6", "7", "8", "9"…
$ Track.Score                <dbl> 725.4, 545.9, 538.4, 444.9, 423.3, 410.1, 4…
$ Spotify.Streams            <chr> "390,470,936", "323,703,884", "601,309,283"…
$ Spotify.Playlist.Count     <chr> "30,716", "28,113", "54,331", "269,802", "7…
$ Spotify.Playlist.Reach     <chr> "196,631,588", "174,597,137", "211,607,669"…
$ Spotify.Popularity         <int> 92, 92, 92, 85, 88, 83, 86, 92, NA, 86, 91,…
$ YouTube.Views              <chr> "84,274,754", "116,347,040", "122,599,116",…
$ YouTube.Likes              <chr> "1,713,126", "3,486,739", "2,228,730", "10,…
$ TikTok.Posts               <chr> "5,767,700", "674,700", "3,025,400", "7,189…
$ TikTok.Likes               <chr> "651,565,900", "35,223,547", "275,154,237",…
$ TikTok.Views               <chr> "5,332,281,936", "208,339,025", "3,369,120,…
$ YouTube.Playlist.Reach     <chr> "150,597,040", "156,380,351", "373,784,955"…
$ Apple.Music.Playlist.Count <int> 210, 188, 190, 394, 182, 138, 280, 160, NA,…
$ AirPlay.Spins              <chr> "40,975", "40,778", "74,333", "1,474,799", …
$ SiriusXM.Spins             <chr> "684", "3", "536", "2,182", "1", "4,654", "…
$ Deezer.Playlist.Count      <int> 62, 67, 136, 264, 82, 86, 168, 87, NA, 78, …
$ Deezer.Playlist.Reach      <chr> "17,598,718", "10,422,430", "36,321,847", "…
$ Amazon.Playlist.Count      <int> 114, 111, 172, 210, 105, 152, 154, 53, NA, …
$ Pandora.Streams            <chr> "18,004,655", "7,780,028", "5,022,621", "19…
$ Pandora.Track.Stations     <chr> "22,931", "28,444", "5,639", "203,384", "7,…
$ Soundcloud.Streams         <chr> "4,818,457", "6,623,075", "7,208,651", "", …
$ Shazam.Counts              <chr> "2,669,262", "1,118,279", "5,285,340", "11,…
$ TIDAL.Popularity           <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ Explicit.Track             <int> 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0…

Problemas com nomes de variáveis

Note que os nomes encontram-se em caixa alta, o que torna a posterior modelagem dos dados um pouco mais complicada, dado que o R é case sensitive. Além disso, as variáveis apresentam pontos, que eram espaços originalmente e foram convertidos pelo R. Nestes casos, podemos utilizar o pacote janitor para corrigir os nomes das variáveis.

Problemas com nomes de variáveis

A função clean_names remove espaços em branco e caracteres especiais, torna únicos nomes duplicados, substitui padrões nos títulos, dentre outras possibilidades, tornando os títulos de colunas mais legíveis e com melhor visualização. Vejamos como ficariam os nomes das variáveis anteriores sem e com a correção:

#Rótulos originais e limpos
data.frame(nomes_antigos = dados_spotify %>% names,
           nomes_limpos = dados_spotify %>% clean_names %>% names)
                nomes_antigos               nomes_limpos
1                       Track                      track
2                  Album.Name                 album_name
3                      Artist                     artist
4                Release.Date               release_date
5                        ISRC                       isrc
6               All.Time.Rank              all_time_rank
7                 Track.Score                track_score
8             Spotify.Streams            spotify_streams
9      Spotify.Playlist.Count     spotify_playlist_count
10     Spotify.Playlist.Reach     spotify_playlist_reach
11         Spotify.Popularity         spotify_popularity
12              YouTube.Views             you_tube_views
13              YouTube.Likes             you_tube_likes
14               TikTok.Posts              tik_tok_posts
15               TikTok.Likes              tik_tok_likes
16               TikTok.Views              tik_tok_views
17     YouTube.Playlist.Reach    you_tube_playlist_reach
18 Apple.Music.Playlist.Count apple_music_playlist_count
19              AirPlay.Spins             air_play_spins
20             SiriusXM.Spins            sirius_xm_spins
21      Deezer.Playlist.Count      deezer_playlist_count
22      Deezer.Playlist.Reach      deezer_playlist_reach
23      Amazon.Playlist.Count      amazon_playlist_count
24            Pandora.Streams            pandora_streams
25     Pandora.Track.Stations     pandora_track_stations
26         Soundcloud.Streams         soundcloud_streams
27              Shazam.Counts              shazam_counts
28           TIDAL.Popularity           tidal_popularity
29             Explicit.Track             explicit_track

Problemas com nomes de variáveis

A função clean_names também é bastante útil para remoção de redundâncias em títulos. Considere o conjunto de dados fictício gerado abaixo. Vamos remover o texto “Pressão Arterial” dos títulos e fazer abreviações dos demais termos, além das demais correções.

#Geração do conjunto de dados fictício
dados_pressao <- data.frame(`Pressão Arterial Sistólica Repouso` = rnorm(100, 120, 20), 
                            `Pressão Arterial Diastólica Repouso` = rnorm(100, 80, 15),
                            `Pressão Arterial Sistólica Exercício` = rnorm(100, 150, 25), 
                            `Pressão Arterial Diastólica Exercício` = rnorm(100, 95, 20))

data.frame(antigo = names(dados_pressao),
           limpo = dados_pressao %>% clean_names(replace = c("Pressão.Arterial" = "pa", 
                                          "Sistólica" = "sis",
                                          "Diastólica" = "dis",
                                          "Repouso" = "rep",
                                          "Exercício" = "ex")) %>% names)
                                 antigo      limpo
1    Pressão.Arterial.Sistólica.Repouso pa_sis_rep
2   Pressão.Arterial.Diastólica.Repouso pa_dis_rep
3  Pressão.Arterial.Sistólica.Exercício  pa_sis_ex
4 Pressão.Arterial.Diastólica.Exercício  pa_dis_ex

Esta pequena alteração pode reduzir bastante a dificuldade na definição de modelos e na digitação de códigos para a análise de dados. Note que é sempre interessante possuir o conjunto de dados originais em mãos caso seja necessário rememorar o nome original das variáveis.

Dados Duplicados

Uma segunda fonte de erros em bancos de dados ocorre quando existem dados potencialmente duplicados. Este tipo de situação acontece devido a alguma falha no processo de coleta, importação ou mesmo digitação dos dados. Alguns exemplos de como dados duplicados podem ser incluídos na base de dados:

  • Um usuário ao submeter um formulário ou requisição, desconfia que seus dados não foram enviados corretamente, e submete novamente a informação.

  • Uma mesma unidade amostral é visitada por dois recenseadores, que repetem a pesquisa.

  • Atendentes de call center apresentam a mesma oferta para um único cliente.

  • Um usuário efetua uma compra recorrente em uma loja virtual, com os mesmos produtos.

  • Valores em um experimento são duplicados para que haja a presença de réplicas.

Dados Duplicados

Estes exemplos são algumas das situações em que dados potencialmente duplicados podem ser inseridos. Entretanto, note que, as três primeiras situações provavelmente gerarão dados de fato duplicado.

Entretanto, as duas últimas situações, geram dados que aparentemente são duplicados, mas que na realidade carregam informações relevantes em suas repetições.

No caso da compra recorrente, a duplicação é uma informação absolutamente relevante para a análise. O mesmo ocorre no experimento, uma vez que determinados erros amostrais só podem ser estimados no caso de presença de réplicas.

Dados Duplicados

Pelos motivos descritos, antes de eliminar dados potencialmente duplicados, é necessário conhecer a natureza do banco de dados e ter a certeza de que os dados de fato são redundantes e sua presença pode acarretar em erros de mensuração ou conferir alguma vantagem técnica à unidade amostral em estudo.

Existem dois tipos de duplicação de dados: duplicação exata e duplicação parcial. Na duplicação exata, conforme o próprio nome descreve, todos os atributos de dois ou mais registros são idênticos. Já na duplicação parcial, podem existir diferenças sutis entre os registros, porém, ao avaliar o quadro geral, percebe-se que se trata da mesma informação.

Dados Duplicados

A tabela a seguir apresenta exemplos de duplicatas exatas e parciais:

ID Modelo Ano/Modelo Avaliação
1 Volkswagen Gol 1.0 2012/2013 8
2 Volkswagen Polo 1.6 Turbo 2016/2017 8,5
3 Volkswagen Gol 1.0 2013/2013 8
4 Volkswagen Up 1.0 2017/2017 7.5
5 VolksWagen Polo 1.6 2016/2017 8,5
6 Volkswagen Polo 1.6 Turbo 2016/2017 8,5

Note que apenas as linhas 2 e 6 são duplicatas exatas. As linhas 1 e 3, bem como as linhas 2 e 5 podem ser consideradas duplicatas parciais, a depender do contexto dos dados.

Dados Duplicados

A remoção de duplicatas exatas é bastante simples. Vamos verificar um exemplo no R com uma base de dados de 20 anos de avaliações da IGN, por meio da função duplicated.

#Importação dos dados
jogos_ign <- read.csv("datasets/a6_pre_processamento/ign.csv", h = T)
glimpse(jogos_ign)
Rows: 18,625
Columns: 11
$ X              <int> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1…
$ score_phrase   <chr> "Amazing", "Amazing", "Great", "Great", "Great", "Good"…
$ title          <chr> "LittleBigPlanet PS Vita", "LittleBigPlanet PS Vita -- …
$ url            <chr> "/games/littlebigplanet-vita/vita-98907", "/games/littl…
$ platform       <chr> "PlayStation Vita", "PlayStation Vita", "iPad", "Xbox 3…
$ score          <dbl> 9.0, 9.0, 8.5, 8.5, 8.5, 7.0, 3.0, 9.0, 3.0, 7.0, 7.5, …
$ genre          <chr> "Platformer", "Platformer", "Puzzle", "Sports", "Sports…
$ editors_choice <chr> "Y", "Y", "N", "N", "N", "N", "N", "Y", "N", "N", "N", …
$ release_year   <int> 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2…
$ release_month  <int> 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9…
$ release_day    <int> 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 7, …

Dados Duplicados

#Vamos remover a coluna com os números de linhas
jogos_ign <- jogos_ign[,-1]

#Estrutura dos dados
glimpse(jogos_ign)
Rows: 18,625
Columns: 10
$ score_phrase   <chr> "Amazing", "Amazing", "Great", "Great", "Great", "Good"…
$ title          <chr> "LittleBigPlanet PS Vita", "LittleBigPlanet PS Vita -- …
$ url            <chr> "/games/littlebigplanet-vita/vita-98907", "/games/littl…
$ platform       <chr> "PlayStation Vita", "PlayStation Vita", "iPad", "Xbox 3…
$ score          <dbl> 9.0, 9.0, 8.5, 8.5, 8.5, 7.0, 3.0, 9.0, 3.0, 7.0, 7.5, …
$ genre          <chr> "Platformer", "Platformer", "Puzzle", "Sports", "Sports…
$ editors_choice <chr> "Y", "Y", "N", "N", "N", "N", "N", "Y", "N", "N", "N", …
$ release_year   <int> 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2…
$ release_month  <int> 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9…
$ release_day    <int> 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 7, …
#Vamos verificar quantas linhas duplicadas existem no conjunto de dados
duplicated(jogos_ign) %>% 
  sum()
[1] 48

Dados Duplicados

#Vamos agora verificar os 48 registros duplicados
jogos_ign %>% 
  subset(duplicated(jogos_ign)) %>% 
  arrange(title) %>% 
  formattable()
score_phrase title url platform score genre editors_choice release_year release_month release_day
Okay Aladdin /games/aladdin/gba-566703 Game Boy Advance 6.5 Platformer N 2004 10 5
Painful Big League Sports /games/big-league-sports/wii-14275098 Wii 2.3 Sports, Compilation N 2008 11 25
Good Blur /games/blur/xbox-360-14222096 Xbox 360 7.0 Racing N 2010 5 25
Amazing Call of Duty: Modern Warfare 2 (Hardened Edition) /games/call-of-duty-modern-warfare-2/ps3-2550 PlayStation 3 9.5 Shooter Y 2009 11 10
Good Crash Twinsanity /games/crash-twinsanity/ps2-667247 PlayStation 2 7.7 Platformer N 2004 10 5
Mediocre Defiance /games/defiance/pc-71832 PC 5.9 Action N 2013 4 17
Good Die Hard Trilogy /games/die-hard-trilogy/ps-447 PlayStation 7.5 Action N 1996 11 21
Good Discworld /games/discworld/ps-583 PlayStation 7.0 Adventure N 1996 11 21
Bad Disney Princess: Enchanted Journey /games/disney-princess-enchanted-journey/wii-943709 Wii 4.0 Adventure N 2008 1 22
Great Dr. Muto /games/dr-muto/xbox-16983 Xbox 8.5 Platformer Y 2002 11 11
Good Dracula the Undead /games/dracula-the-undead/lynx-5849 Lynx 7.0 Adventure N 1999 7 6
Great Final Fantasy I & II: Dawn of Souls /games/final-fantasy-i-and-ii-dawn-of-souls/gba-479100 Game Boy Advance 8.5 RPG, Compilation Y 2004 11 30
Good Galaga /games/galaga/nes-7024 NES 7.5 Shooter N 2007 4 18
Great Guitar Hero On Tour: Decades (Game Only Edition) /games/guitar-hero-on-tour-decades/nds-14253160 Nintendo DS 8.0 Music N 2008 11 17
Okay Hard Drivin’ /games/hard-drivin/lynx-4142 Lynx 6.0 Racing N 1999 7 6
Good Harvest Moon GBC 3 /games/harvest-moon-gbc-3/gbc-17428 Game Boy Color 7.0 Simulation N 2002 1 15
Mediocre John Daly’s ProStroke Golf /games/john-dalys-prostroke-golf/ps3-69069 PlayStation 3 5.5 Sports N 2010 10 15
Good LEGO Racers /games/lego-racers/n64-1997 Nintendo 64 7.5 Racing N 1999 10 26
Bad March of the Penguins /games/march-of-the-penguins/nds-855305 Nintendo DS 4.0 Adventure N 2007 1 18
Okay Motorhead [1998] /games/motorhead/pc-3566 PC 6.0 Racing N 1999 5 17
Great Namco Museum Vol. 1 /games/namco-museum-vol-1/ps-702 PlayStation 8.0 Action, Compilation N 1996 11 25
Great Need for Speed Underground /games/need-for-speed-underground/gcn-552526 GameCube 8.8 Racing Y 2003 11 14
Okay Olympic Summer Games: Atlanta ’96 /games/olympic-summer-games-atlanta-96-808731/ps-551 PlayStation 6.0 Sports N 1996 11 25
Good PGA Tour ’96 /games/pga-tour-96/ps-165 PlayStation 7.0 Sports N 1996 11 25
Okay Planet Minigolf /games/planet-minigolf/ps3-38306 PlayStation 3 6.5 Sports N 2010 6 1
Good Puzzle Chronicles /games/puzzle-chronicles/ps3-14310826 PlayStation 3 7.0 Puzzle N 2010 4 26
Okay Puzzle Guzzle /games/puzzle-guzzle/psp-966173 PlayStation Portable 6.7 Puzzle N 2008 3 3
Awful Raven Project /games/raven-project/ps-184 PlayStation 3.0 Action N 1996 11 25
Good Rayman /games/rayman/ps-69 PlayStation 7.0 Platformer N 1996 11 25
Unbearable Revolution X /games/revolution-x/ps-689 PlayStation 1.0 Action N 1996 11 25
Good Road & Track Presents: The Need for Speed /games/road-and-track-presents-the-need-for-speed/ps-1864 PlayStation 7.0 Racing N 1996 11 25
Okay Romance of the Three Kingdoms IV: Wall of Fire /games/romance-of-the-three-kingdoms-iv-wall-of-fire/ps-478 PlayStation 6.0 Strategy N 1996 11 25
Great Scarface: The World is Yours /games/scarface-money-power-respect/pc-697002 PC 8.7 Action Y 2006 10 6
Okay Silverload /games/silverload/ps-585 PlayStation 6.0 Adventure N 1996 11 25
Great Sonic & SEGA All-Stars Racing /games/sonic-sega-all-stars-racing/nds-14353445 Nintendo DS 8.0 Racing N 2010 2 23
Bad Spider-Man: Friend or Foe /games/spider-man-friend-or-foe/wii-864875 Wii 4.9 Action N 2007 10 8
Amazing Steel Talons /games/steel-talons/lynx-4159 Lynx 9.0 Flight, Action N 1999 7 6
Good Super Monkey Ball 3D /games/super-monkey-ball-3d/3ds-77816 Nintendo 3DS 7.5 Action N 2011 3 25
Good TNA Wrestling (2009) /games/tna-wrestling-2009/iphone-14335458 iPhone 7.0 Wrestling N 2009 3 31
Good The Chronicles of Riddick: Assault on Dark Athena /games/the-chronicles-of-riddick-assault-on-dark-athena/pc-14294667 PC 7.4 Shooter N 2009 3 31
Good The Political Machine /games/the-political-machine/pc-639851 PC 7.9 Strategy N 2004 9 20
Great The Sims /games/the-sims-1/xbox-498288 Xbox 8.5 Simulation Y 2003 3 24
Great Tobal No. 1 /games/tobal-no-1/ps-743 PlayStation 8.7 Fighting Y 1996 11 26
Good Twisted Metal [1996] /games/twisted-metal-1996/ps-444 PlayStation 7.0 Action N 1996 11 26
Great Wallace & Gromit’s Grand Adventures, Episode 1: Fright of the Bumblebees /games/wallace-and-gromits-grand-adventures-episode-1-fright-of-the-bumblebees/xbox-360-14330730 Xbox 360 8.0 Adventure N 2009 5 26
Amazing WipEout XL /games/wipeout-2097/ps-473 PlayStation 9.0 Racing Y 1996 11 26
Good Yu-Gi-Oh! World Championship Tournament 2004 /games/yu-gi-oh-world-championship-tournament-2004/gba-620297 Game Boy Advance 7.5 Card, Battle N 2004 2 13
Mediocre ZooCube /games/zoocube/gba-479813 Game Boy Advance 5.3 Puzzle N 2002 6 11

Dados Duplicados

#Podemos utilizar o título para verificar quantas vezes cada duplicata aparece
duplicados <- jogos_ign %>% 
  subset(duplicated(jogos_ign)) %>% 
  arrange(title)
table(jogos_ign[jogos_ign$title %in% duplicados$title, "title"]) %>% 
  sort(decreasing = T) %>% 
  data.frame %>% 
  formattable()
Var1 Freq
Spider-Man: Friend or Foe 7
Need for Speed Underground 6
Galaga 5
LEGO Racers 5
Scarface: The World is Yours 5
The Sims 5
Aladdin 4
Blur 4
Crash Twinsanity 4
Defiance 4
Dr. Muto 4
Rayman 4
Sonic & SEGA All-Stars Racing 4
The Chronicles of Riddick: Assault on Dark Athena 4
March of the Penguins 3
Romance of the Three Kingdoms IV: Wall of Fire 3
Wallace & Gromit’s Grand Adventures, Episode 1: Fright of the Bumblebees 3
ZooCube 3
Big League Sports 2
Call of Duty: Modern Warfare 2 (Hardened Edition) 2
Die Hard Trilogy 2
Discworld 2
Disney Princess: Enchanted Journey 2
Dracula the Undead 2
Final Fantasy I & II: Dawn of Souls 2
Guitar Hero On Tour: Decades (Game Only Edition) 2
Hard Drivin’ 2
Harvest Moon GBC 3 2
John Daly’s ProStroke Golf 2
Motorhead [1998] 2
Namco Museum Vol. 1 2
Olympic Summer Games: Atlanta ’96 2
PGA Tour ’96 2
Planet Minigolf 2
Puzzle Chronicles 2
Puzzle Guzzle 2
Raven Project 2
Revolution X 2
Road & Track Presents: The Need for Speed 2
Silverload 2
Steel Talons 2
Super Monkey Ball 3D 2
The Political Machine 2
TNA Wrestling (2009) 2
Tobal No. 1 2
Twisted Metal [1996] 2
WipEout XL 2
Yu-Gi-Oh! World Championship Tournament 2004 2

Dados Duplicados

#Agora vamos remover os valores duplicados
jogos_ign_unicos <- jogos_ign[-which(duplicated(jogos_ign)), ]

#Podemos realizar a mesma operação usando a função distinct do pacote dplyr
jogos_ign_unicos <- distinct(jogos_ign)

#Vejamos a diferença entre os conjuntos de dados
nrow(jogos_ign) - nrow(jogos_ign_unicos)
[1] 48

Conforme vimos, a remoção de duplicatas exatas é bastante simples. Já a remoção de duplicatas parciais é um pouco mais complexa. Existem algumas opções para realizar a tarefa.

Dados com ruído

Além dos problemas anteriormente mencionados, dados inconsistentes podem ser bastante frequentes em conjuntos de dados.

Pode-se definir dados com ruído como aqueles que não apresentam sentido dentro do banco de dados.

Geralmente a ocorrência de dados com ruído tem como origem erros de digitação, ausência de padronização na entrada de dados, alterações nos procedimentos de coleta de dados, dentre outras fontes.

Dados com ruído

A correção de dados com ruído dependerá de uma série de fatores.

A primeira delas é a frequência de ocorrência destes dados ruidosos.

Pode-se trabalhar com conjuntos de dados que apresentam um grande volume de inconsistências iguais, dados com uma série de inconsistências de pequena frequência ou mesmo dados com grandes volumes de ruído de diversas fontes.

Dados com ruído

De modo geral, tais ruídos ocorrem em dados de texto, dados monetários e dados categóricos, mas também podem ocorrer em dados de data.

Independente dos casos, é importante identificar os ruídos para avaliar qual será a estratégia de ação.

Não há uma forma única de detecção de ruídos. Neste texto será apresentada uma estratégia baseada na avaliação da frequências de determinadas ocorrências.

Dados com ruído

Vamos verificar o conjunto de dados a seguir. Ele representa informações sobre seguro saúde nos Estados Unidos. A base de dados original está disponível no Kaggle.

#Leitura dos dados
insurance <- read.csv("datasets/a6_pre_processamento/noisy_insurance.csv", h = T)

#Estrutura dos dados
glimpse(insurance)
Rows: 1,338
Columns: 7
$ age      <int> 19, 18, 28, 33, 32, 31, 46, 37, 37, 60, 25, 62, 23, 56, 27, 1…
$ sex      <chr> "female", "male", "malee", "male", "male", "femae", "female",…
$ bmi      <dbl> 27.900, 33.770, 33.000, 22.705, 28.880, 25.740, 33.440, 27.74…
$ children <int> 0, 11, 3, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, …
$ smoker   <chr> "yes", "no", "no", "no", "no", "no", "no", "no", "no", "no", …
$ region   <chr> "southwest", "southeast", "southeast", "northwest", "northwes…
$ charges  <chr> "US$ 16884.924", "US$ 1725.5523", "US$ 4449.462", "US$ 21984.…

Dados com ruído

Pela estrutura dos dados, é possível perceber que os valores cobrados, que deveriam ser numéricos, estão acompanhados do símbolo da moeda.

Vamos remover estes caracteres e realizar a conversão para número. Será utilizada a função str_remove do pacote stringr. Note que, para que o R reconheça alguns caracteres especiais, é necessário precedê-los por “\\”.

#Remove os caracteres monetários e efetua a conversão para numérico
insurance$charges <- insurance$charges %>% 
  str_remove_all("US\\$ ") %>% 
  as.numeric

#Estrutura dos dados
glimpse(insurance)
Rows: 1,338
Columns: 7
$ age      <int> 19, 18, 28, 33, 32, 31, 46, 37, 37, 60, 25, 62, 23, 56, 27, 1…
$ sex      <chr> "female", "male", "malee", "male", "male", "femae", "female",…
$ bmi      <dbl> 27.900, 33.770, 33.000, 22.705, 28.880, 25.740, 33.440, 27.74…
$ children <int> 0, 11, 3, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, …
$ smoker   <chr> "yes", "no", "no", "no", "no", "no", "no", "no", "no", "no", …
$ region   <chr> "southwest", "southeast", "southeast", "northwest", "northwes…
$ charges  <dbl> 16884.924, 1725.552, 4449.462, 21984.471, 3866.855, 3756.622,…

Dados com ruído

Vamos agora checar as variáveis numéricas para verificar se há alguma inconsistência. Podem ser utilizados gráficos e tabelas de frequências.

#Frequência de idades dos titulares dos seguros-saúde
table(insurance$age)

 18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37 
 69  68  30  29  27  28  29  27  28  28  28  27  26  26  25  27  24  26  24  26 
 38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57 
 24  23  28  27  27  25  26  29  28  28  28  28  29  30  26  28  28  25  26  26 
 58  59  60  61  62  63  64 122 125 129 132 134 136 138 142 143 144 146 148 152 
 25  25  22  22  23  23  21   1   1   2   1   1   1   1   1   1   1   1   1   2 
164 
  1 

Dados com ruído

#Boxplot de dados de IMC
boxplot(insurance$bmi)
table(insurance$age)

 18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37 
 69  68  30  29  27  28  29  27  28  28  28  27  26  26  25  27  24  26  24  26 
 38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57 
 24  23  28  27  27  25  26  29  28  28  28  28  29  30  26  28  28  25  26  26 
 58  59  60  61  62  63  64 122 125 129 132 134 136 138 142 143 144 146 148 152 
 25  25  22  22  23  23  21   1   1   2   1   1   1   1   1   1   1   1   1   2 
164 
  1 

Dados com ruído

#Frequência do número de filhos dos titulares dos seguros-saúde
table(insurance$children)

  0   1   2   3   4   5  10  11  20  25 
569 321 240 157  25  17   4   3   1   1 

Dados com ruído

#Boxplot das taxas cobradas
boxplot(insurance$charges)

Outliers

Um outlier, também conhecido como valor extremo, discrepante, aberrante, ponto fora da curva, etc., é um valor amostral que desvia tanto da amostra que tende-se a avaliar como proveniente de outro processo gerador, ou mesmo fruto de algum erro (dado ruidoso). A identificação de outliers é crucial durante o processo de limpeza de dados, pois tais valores podem acarretar alguns problemas na análise de dados, tais como:

  • Aumento na variabilidade dos dados e nos erros de modelos;

  • Influência na estimação;

  • Quebra do pressuposto de normalidade, dentre outros

Outliers

É necessário bastante cuidado ao se tratar de outliers, pois apesar dos aspectos mencionados acima, eles podem trazer informações valiosas para a análise.

Neste sentido, é importante que os mesmos não sejam tratados como dados gerados por ruído.

Por exemplo, ao excluir um valor extremo de uma base de dados, podemos deixar de contabilizar uma observação rara, mas de extrema importância, como uma empresa de faturamento recorde, um candidato acima da média, um caso clínico improvável, dentre outras possibilidades.

Outliers

Essa diferenciação as vezes é bastante complexa. É como descascar uma laranja, queremos remover toda a casca, mas não queremos remover a extremidade da polpa da fruta.

A casca seriam os dados com ruído e a extremidade da polpa da fruta seriam os outliers. Deve-se agir com bastante cautela para evitar a perda de conteúdo relevante.

Outliers

Na maioria das vezes trabalhamos com bases de dados de grande dimensão, tanto em número de observações quanto em número de variáveis. De modo geral, existem relações entre estas variáveis.

Deste modo, podem ocorrer o que chamamos de outliers multivariados.

Outliers

Outliers multivariados são observações que, analisadas variável a variável não necessariamente apresentam outliers, mas quando analisadas em conjunto, considerando suas correlações, apresentam comportamento atípico.

Este problema é ainda bastante incipiente e não existe metodologia definitiva para sua análise. Por este motivo, trataremos apenas de outliers univariados. Interessados no assunto podem acessar o trabalho de Duarte et. al. (2024) (2024), que apresenta uma revisão sobre outliers multivariados, bem como a apresentação de uma nova metodologia de detecção.

Outliers

Mesmo em outliers multivariados, existem definições distintas. Um outlier, pela definição clássica é um dado que ultrapassa, à esquerda ou à direita, as seguintes quantidades:

  • \(Q_1 - 1,5 \cdot IQR\)

  • \(Q_3 + 1,5 \cdot IQR\)

em que \(Q_1\) e \(Q_3\) são o primeiro e terceiro quartis, respectivamente, e \(IQR\) é a distância interquartílica.

Outliers

Nesta seção, utilizaremos alguns métodos clássicos para a detecção de valores extremos.

Como ilustração, utilizaremos a base de dados hflights, do pacote homônimo. Verificaremos se existem outliers dentre os tempos de atraso na decolagem dos vôos.

Outliers

Inicialmente, a verificação pode ser realizada por meio do boxplot dos dados.

#Carregamento dos pacotes
pacman::p_load(univOutl, hflights)

#Vamos verificar o boxplot dos dados de atrasos na decolagem
boxplot(hflights$DepDelay, horizontal = T)

Outliers

#Algumas estatísticas descritivas dos dados
summary(hflights$DepDelay)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
-33.000  -3.000   0.000   9.445   9.000 981.000    2905 
#Tabela com candidatos a outliers
table(hflights$DepDelay < quantile(hflights$DepDelay, .25, na.rm = T) - 1.5* IQR(hflights$DepDelay, na.rm = T) |
      hflights$DepDelay > quantile(hflights$DepDelay, .75, na.rm = T) + 1.5* IQR(hflights$DepDelay, na.rm = T))

 FALSE   TRUE 
199406  25185 

Outliers

Um primeiro indício da presença de outliers é o valor da média, bem acima do valor da mediana.

Como a média é influenciada por valores extremos, uma distância grande entre a média e a mediana já indica assimetria nos dados.

O boxplot é bastante claro ao indicar que existem muitos valores acima do esperado.

Outliers

Todos os valores representados por círculos são possíveis candidatos a outlier, ou seja, todos eles estão a mais de 1,5 distâncias interquartílicas dos quartis 1 e 3.

Como a distância interquartílica é 12, quaisquer partidas ocorridas com mais de 21 minutos de antecedência ou com mais de 27 minutos de atraso poderiam ser outliers.

Entretanto, muitas observações atendem a este critério. Temos aproximadamente 11% dos valores nesta categoria. Deste modo, é necessária a utilização de algum teste estatístico para identificar os valores que de fato são .

Outliers

Existem alguns testes para detecção de outliers, presentes no pacote outliers

  • Teste de Dixon (dixon.test)

  • Teste de Grubb (grubbs.test)

  • Variância interna e externa (cochran.test)

  • Teste qui-quadrado (chisq.out.test)

Entretanto, todos estes testes são voltados para dados em que a pressuposição de normalidade é verificada, o que claramente não é o caso. Neste caso, algumas abordagens podem ser utilizadas, como a utilização da distância de Cook e o processo descrito por Lund(1975).

Outliers

Para a distância de Cook, seja n o número de observações da variável. Qualquer valor cuja distância de Cook seja maior que \(4/n\) seria considerado um outlier. Para calcular a distância de Cook em relação à média, devemos ajustar um modelo de regressão simples, do tipo \(y = x\).

#Modelo de regressão
m <- lm(hflights$DepDelay ~ 1)

#Cálculo da distância de Cook
dc <- cooks.distance(m)
length(dc)
[1] 224591
#Agora vamos verificar quantos valores atendem ao critério
table(dc > 4 / nrow(hflights))

 FALSE   TRUE 
215659   8932 

Outliers

Ao seguir este critério, teríamos aproximadamente 3% de outliers, logo, eliminamos 72% dos candidatos iniciais a outliers, pois a análise descritiva indicava mais de 25 mil candidatos em potencial.

Entretanto, será que podemos considerar 3% dos dados como uma ocorrência rara?

Seriam todos estes valores de fato extremos?

Existe um processo diferente na geração destes dados? No fim das contas, a detecção de outliers trás mais perguntas do que respostas.

Outliers

Após a identificação, fica o seguinte questionamento: o que fazer com os outliers. A resposta é: depende. Vamos analisar alguns casos:

  • Caso 1 - A presença de outliers afeta o desempenho de seu modelo: Neste caso, se o volume de dados for grande o suficiente para que a exclusão não seja um problema (outliers representam menos de 1% da amostra, por exemplo), a retirada destes valores pode apresentar pouco impacto e o modelo seria voltado apenas para dados de comportamento “normal”, no sentido de não serem extremos.

  • Caso 2 - Existem outliers o suficiente para gerar suspeição: Neste caso, talvez sua presença seja devida a alguma falha no processo amostral e tal processo deve ser revisto.

Outliers

Após a identificação, fica o seguinte questionamento: o que fazer com os outliers. A resposta é: depende. Vamos analisar alguns casos:

  • Caso 3 - Existem muitos outliers: Neste caso, o ideal é estudar em conjunto com as demais variáveis se existe algum motivo particular para a ocorrência destes valores extremos antes de tomar a decisão de excluí-los ou não. Os mesmos podem ser tratados como um cluster, por exemplo.

  • Caso 4 - A amostra é pequena: Neste caso, não se deve excluir os outliers, pois sua remoção pode tornar a amostra não representativa.

Outliers

Os casos apresentados são alguns dos diversos cenários possíveis.

presença do outlier inclusive pode ser o elemento de interesse, como por exemplo em detecções de fraudes, detecções de catástrofes naturais, dentre outras aplicações.

A conduta com estes valores extremos dependerá da situação em estudo.

Dados Faltantes (Missing Data)

É bastante comum, ao se trabalhar com dados, se deparar com dados faltantes. Estes dados faltantes podem se originar de diversas formas. Por exemplo, problemas no processo de importação dos dados, falha na coleta de dados, ausência de informação no momento da coleta, dentre outros. Dentre os dados faltantes, existem três diferentes tipos:

Dados Faltantes (Missing Data)

  • Dados faltantes completamente ao acaso (MCAR - Missing Completely at Random): Dados que não foram computados devido à falha humana ou erros de entrada de dados. Dados faltantes do tipo MCAR indicam que a probabilidade de ausência da informação é uniforme para todos os dados, independentemente de suas características. Ou seja, não há um padrão em suas ausências. Por exemplo, um drone de aquisição de imagens de uma plantação cobre a área em forma de grid. Este drone apresenta uma falha de captura ocasionalmente. Deste modo, as falhas de captura ocorrerão de maneira aleatória. Este é o tipo de situação mais desejável, pois geralmente não afeta o processo.

Dados Faltantes (Missing Data)

  • Dados faltantes ao acaso (MAR - Missing at Random): Dados que não foram computados, mas nos quais é possível identificar algum tipo de padrão de ausência. Entretanto, este padrão não tem relação direta com a variável. Um exemplo deste fenômeno seria o seguinte: em uma população, mulheres tendem a responder mais questionários que homens. Em um questionário sobre mercado de trabalho, homens tenderiam a responder menos que mulheres, o que não implicaria necessariamente em diferenças nos dados, pois a não resposta entre homens ocorreria aleatoriamente.

Dados Faltantes (Missing Data)

  • Dados faltantes não ao acaso (MNAR - Missing not at Random): Dados que não são computados devido à características diretamente relacionadas à variável faltante. Este é o pior cenário possível, comparado aos anteriores. Este tipo de valor faltante geralmente é relacionado a um desenvolvimento ruim dos instrumentos de pesquisa. Por exemplo, em pesquisas relacionadas à renda, pessoas com renda baixa tendem a se sentir constrangidas a responder. Uma solução das potenciais soluções é a aplicação de questões indiretas, como frequência de consumo de determinados serviços, itens relacionados à residência, dentre outras possibilidades.

Dados Faltantes (Missing Data)

Uma outra forma de dados faltantes, que não se enquadra nas categorias acima, são dados classificados como faltantes, mas que não o são de fato. Por exemplo, em uma pesquisa sobre um produto, existem duas perguntas: “Consome o produto X?” e “Avaliação do produto X”. Neste caso, espera-se uma resposta nula para aqueles que não consomem o produto, mas o dado não é de fato faltante. O mesmo pode ocorrer quando novas variáveis são inseridas em bancos de dados antigos. Não haverão respostas para dados anteriores à sua implementação.

Dados Faltantes (Missing Data)

O modo de identificar o tipo de dado faltante é a análise descritiva dos dados.

Diante destes casos, como resolvemos esses problemas? Vamos apresentar algumas ideias de procedimentos para minimizar a presença de dados faltantes.

A primeira abordagem é a exclusão dos dados faltantes. Caso não haja muitas observações com dados faltantes em relação ao montante total de dados, assim como discutido em relação aos outliers, os dados faltantes podem ser removidos ou omitidos das análises. Em R, podemos utilizar funções para esta finalidade, ou parâmetros de funções específicas. Vamos utilizar novamente o conjunto de dados hflights para ilustrar. A função na.exclude remove todas as linhas que contém pelo menos um valor faltante.

Dados Faltantes (Missing Data)

#Remover todas as linhas que contém dados faltantes
hflights %>% 
  dim
[1] 227496     21
hflights %>% 
  na.exclude %>% 
  dim
[1] 223874     21
nrow(hflights) - nrow(na.exclude(hflights))
[1] 3622

Note que foram removidas 3622 linhas que continam dados faltantes.

Dados Faltantes (Missing Data)

Outra possibilidade é omitir os dados faltantes no cálculo de alguma estatística ou modelo. Geralmente se utilizam os parâmetros na.rm. Vamos calcular o tempo médio de voo.

#Cálculo do tempo médio de voo
mean(hflights$ActualElapsedTime)
[1] NA
#Note que o cálculo não foi possível devido à presença de dados faltantes. Vamos removê-los
mean(hflights$ActualElapsedTime, na.rm = T)
[1] 129.3237
#No caso de modelos, podemos omitir os dados

O descarte dos dados deve ser realizado apenas em casos do tipo MCAR, caso contrário, pode haver perda de informação.

Dados Faltantes (Missing Data)

Já para os dados do tipo MAR, existem algumas possibilidades mais específicas:

  • Substituir por um valor conveniente, como a média dos dados;

  • Utilizar o valor imediatamente anterior (hot-deck);

  • Substituir pelo valor mais frequente na coluna (moda);

  • Substituir por um valor amostrado da coluna, dada sua probabilidade de ocorrência;

  • Utilizar modelos preditivos baseados em regressão ou machine learning, baseados nas demais variáveis.

Dados Faltantes (Missing Data)

Como exemplo, vamos utiizar o conjunto de dados de tempos de viagem, disponível em https://openmv.net/info/travel-times. A variável FuelEconomy apresenta alguns valores faltantes. Vamos tentar utilizar todos os métodos acima e verificar qual o mais eficaz. Vamos verificar os resultados no R.

travel <- read.csv2("datasets/a6_pre_processamento/travel-times.csv", h = T, dec = ".")

#Tabela de frequencia dos dados faltantes
table(is.na(travel$FuelEconomy))

FALSE  TRUE 
  186    19 
#Média dos dados
mean(travel$FuelEconomy)
[1] NA
media <- mean(travel$FuelEconomy, na.rm = T)

#Substituição pela media
travel_media <- travel
travel_media$FuelEconomy[is.na(travel$FuelEconomy)] <- media
mean(travel_media$FuelEconomy)
[1] 8.690591

Dados Faltantes (Missing Data)

#Método hot-deck
travel_hd <- travel
hd <- which(is.na(travel_hd$FuelEconomy))
travel_hd$FuelEconomy[hd] <- travel_hd$FuelEconomy[hd - 1]

#Método valor mais frequente
travel_moda <- travel
moda <- which(is.na(travel_moda$FuelEconomy))
travel_moda$FuelEconomy[moda] <- table(travel_moda$FuelEconomy) %>%
  which.max %>% 
  as.numeric()
mean(travel_moda$FuelEconomy)
[1] 8.904634
#Método por probabilidades de ocorrência
travel_prob <- travel
id_prob <- which(is.na(travel_prob$FuelEconomy))
prob <- table(travel_prob$FuelEconomy)/sum(table(travel_prob$FuelEconomy))
input <- sample(as.numeric(names(prob)), prob = prob)
travel_prob$FuelEconomy[id_prob] <- input
mean(travel_prob$FuelEconomy)
[1] 8.690585

Dados Faltantes (Missing Data)

#Regressão
travel_reg <- travel
reg <- which(is.na(travel_reg$FuelEconomy))
model <- lm(FuelEconomy~., data = travel_reg)
pred <- predict(model)
travel_reg$FuelEconomy[reg] <- pred[reg]
mean(travel_prob$FuelEconomy)
[1] 8.690585

Dados Faltantes (Missing Data)

#Vamos compilar os resultados das estatísticas descritivas para comparar as metodologias

comp <- rbind(summary(travel$FuelEconomy),
      summary(travel_media$FuelEconomy),
      summary(travel_moda$FuelEconomy), 
      summary(travel_prob$FuelEconomy),
      summary(travel_reg$FuelEconomy))

comp <- data.frame(metodo = c("Original", "Média", "Moda", "Mais provável", "regressao"), comp) %>% .[, -c(2, 8)] %>% formattable()

comp
metodo X1st.Qu. Median Mean X3rd.Qu. Max.
Original 8.37 8.52 8.690591 8.97 10.05
Média 8.37 8.54 8.690591 8.93 10.05
Moda 8.37 8.54 8.904634 9.30 11.00
Mais provável 8.37 8.50 8.690585 8.97 10.05
regressao 8.37 8.54 8.702579 8.97 10.05

Dados Faltantes (Missing Data)

Note que temos 19 dados faltantes na variável.

Após a imputação, em termos médios, o melhor método é a substituição pela média.

Porém, os métodos de valor mais provável e regressão, além de se aproximarem da média, não afetaram os valores do terceiro quartil e nem do máximo.

A escolha pelo melhor método de imputação dependerá da modelagem que será aplicada aos dados. Deve-se escolher aquela que afetar menos a estrutura original dos dados

Referências

Duarte, AR, JJ Barbosa, HSR Martins, and FLP Oliveira. 2024. “Data-Driven Cluster Analysis Method: A Novel Outliers Detection Method in Multivariate Data.” Communications in Statistics-Simulation and Computation, 1–21.
Lund, Richard E. 1975. “Tables for an Approximate Test for Outliers in Linear Models.” Technometrics 17 (4): 473–76.