Introdução

Objetivo desse documento:

Estudar, entender e reproduzir os exercícios e metodologias do livro Data Mining with Rattle and R (Graham Williams), com o intuito de aprender mais sobre o processo de Mineração de Dados.


Mineração de dados

O que é?

Mineração de dados (data mining), é o processo que visa descobrir e retirar insights significativos dos dados.

O processo de Data Mining

Um típico projeto de data mining consiste em 6 passos básicos:

  1. Entender o problema
  2. Entender os dados
  3. Preparar os dados
  4. Modelagem
  5. Validação
  6. Implantação

Algumas considerações:

Vale a pena olhar essa lista e sempre se ter em mente:

  1. Foco nos dados e entendimento do negócio.
  2. Usar training/validate/test datasets para cirar/melhorar/validar modelos.
  3. Cronstruir modelos multiplos: a maioria trará resultados parecidos.
  4. Questionar o modelo “perfeito”
  5. Não esqueça de verificar o modo como o modeo será implementado
  6. Use e abuse de reproducibilidade e eficiência, use scripts para tudo
  7. Deixe os dados falarem com você, e não te enganar
  8. Comunique suas descobertas claramente e visualmente

Recursos para continuar a aprender R:

(Meus arquivos):
R for Data Science, incrível para aprender R e a framework do tidyverse.
curso-R, mantido por Brasileiros e apresenta tutoriais/cursos fantásticos.

(Dados pelo autor do livro):
Data Manipulation with R (Spector, 2008)
Modern Applied Statistics with R (Venables and Ripley, 2002)
Data Analysis and Graphics Using R (Maindonald and Braun, 2007)
The Elements of Statistical Learning (Hastie et al., 2009) (recomendado também por professores do IME)
Elegant Graphics for Data Analysis (Wickham, 2009)


Começando

Antes de iniciar a parte mais divertida do livro, é necessário instalarmos alguns pacotes (estou supondo que o leitor esteja utilizando RStudio):

# Pacotes a serem utilizados:
library(rattle)
library(tidyverse)
library(datasets)
library(reshape2)

# Caso não tenha os pacotes instalados utilize o comando install.packages("nome_do_pacote")

rattle()

A página inicial do Rattle é:

A chave para usar o Rattle é suprir o programa com a informação apropriada e SEMPRE apertar o botão de Executar antes de ir para o próximo passo.

Primeiro contato

Ao clicar em Executar, o Rattle irá perceber que nenhum dataset foi colocado e te perguntará se você quer escolher um dataset. Clique em Sim.

A partir de agora, o dataset weather.csv será carregado. Para entender mais sobre o dataset utilize

?weather

Clique na aba Model, e depois em Executar.

Pronto! Seu primeiro modelo de Decision Tree foi criado pelo Rattle. Uma representação textual do modelo aparecerá na tela do Rattle.

Entendendo melhor o primeiro modelo

Target Variable

Na aba Data, vemos que a variável target chama-se RainTomorrow. O Rattle escolheu essa variável automaticamente pois é a variável binária do nosso dataset. Olhamos essa variável pois o nosso propósito é prever se choverá ou não amanhã, dado os dados que temos hoje.

Por enquanto, não focaremos no entendimento textual do modelo mas sim na sua representação gráfica. No canto direito, clique em Draw para ver tal representação (você entenderá o razão do modelo se chamar árvore de decisão).

Clicando na tab Rules veremos uma lista de regras utilizadas pelo Rattle para formar o modelo de árvore de decisão.

Uma das vantagens desse modelo é que o caminho para a árvore pode ser traçado seguindo essas regras:

Desenho da árvore de decisão:

Por enquanto, podemos entender tais regras da seguinte forma:

Rule 7 é a regra mais forte para predizer chuva (tendo a maior probabilidade de Yes). Podemos ler que se a pressão atmosférica as 3 pm fosse menor que 1012 hectopascals e a quantidade de luz do sol de hoje fosse menor que 8.85 horas, então teríamos a chance de 74% de chover amanhã. Portanto, na maioria dos dias onde vimos essas condições (baseado no nosso dataset), choveu no dia seguinte.

Se continuarmos a olhar a liste de regras, podemos ver que a Regra 4 apresenta duas condições: a pressão atmosférica >= 1012 hectopascals e cloud cover as 3 pm < 7.5. Quando essas condições são válidas, historicamente, os dados nos dizem que existe somente 5% (prob = 0.05) de chance de chover amanhã.

Entendendo os dados

Por enquanto, apenas olhamos os outputs do modelo sem muita atenção aos dados que estamos estudando. A tab Explore do Rattle é usada para isso.

Nessa tab podemos explorar como nossas variáveis estão distribuidas dentro da base de dados.

Podemos, por exemplo, verificar como está distrbuida nossa variável target (RainTomorrow). Indo para a tab Explore, retirando o Group By, clicando em Bar Plot para a variável RainTomorrow e depois em Executar. Temos:

Vemos que a variável target é altamente assimétrica. Em mais de 80% dos dias não há chuva.

É importantíssimo sabermos da assimetria para avaliar qualquer modelo que criarmos - um modelo que preve que jamais choverá estará correto mas de 80% das vezes, mas será um tanto quanto inútil.

Ao selecionar Group By (RainTomorrow), Box Plot e Histogram para as variáveis MaxTemp e Sunshine teremos:

Aqui, podemos ver como as variáveis MaxTemp e Sunshine estão distribuidas quando agrupamos pela variável target. Quais conclusões podemos tirar?

As vizualizações são cruicais para contar uma história satisfatória com os dados.

É altamente recomendável que o leitor “brinque” com as possibilidades de gráficos do Rattle e anote suas conclusões sobre as variáveis.

Mais exemplos:

Um gráfico não tão comum, mas muito bacana para perceber proporçoes associadas com os níveis da variável target é o gráfico de mosaico:

Ao analisar esse gráfico, podemos perceber que ventos com a direção Norte (prefixo “N”) tendem a apresentar uma chance de chuva maior que ventos em outras direções.

Também podemos criar os gráficos utilizando o tidyverse + ggplot2 - o exemplo abaixo cria um gráfico simples para analisar uma variável categórica da nossa base de dados.

library(tidyverse)
## Loading tidyverse: ggplot2
## Loading tidyverse: tibble
## Loading tidyverse: tidyr
## Loading tidyverse: readr
## Loading tidyverse: purrr
## Loading tidyverse: dplyr
## Conflicts with tidy packages ----------------------------------------------
## filter(): dplyr, stats
## lag():    dplyr, stats
fname <- system.file("csv", "weather.csv", package="rattle") 
weather <- read.csv(fname, encoding = "UTF-8")

weather %>% 
  group_by(WindDir9am, RainTomorrow) %>% 
  summarise(freq = n()) %>% 
  ggplot(aes(x = reorder(WindDir9am, freq), y= freq, fill = RainTomorrow)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(x = "Direção do vento as 9 am",
       y = "Frequência") +
  theme_bw() +
  theme(legend.position = "top")

Avaliando o Modelo

A fim de simplificar o processo de avaliação do modelo, usaremos como método de avaliação a matriz de confusão (ou matriz de erros).

Como de praxe, o Rattle divide a base de dados em 70/15/15. Isso quer dizer que 70% dos dados da base serão utilizados como training dataset, 15% como validation dataset e 15% como testing dataset. Bem resumidamente, podemos pensar nessa divisão da base de dados como:

  • Training Dataset: Usaremos para “treinar” o modelo.
  • Validation Dataset: Usaremos para validar o impacto de diferentes parâmetros e variáveis no modelo (importante lembrar que esse dataset não será usado para estimar erros no modelo, pois foi usado no processo de mineração de dados).
  • Testing Dataset: Dataset usado apenas para prever o resultado do modelo. (Vai medir a performance do modelo)

A matriz de confusão.

A matriz de confusão simplesmente compara as previsões feitas pelo modelo com os dados que de fato aconteceram.
Isso nos dará um nível de entendimento sobre quão acurado está o nosso modelo, pois será testado numa base de dados totalmente nova (espera-se).

Para avaliar o modelo no Rattle, usaremos a aba Evaluate, clicaremos em Error Matrix e escolheremos o modelo em questão. Além disso, podemos avaliar o modelo no validation dataset ou no testing dataset. Como queremos avaliar a acurácia do nosso modelo, usaremos o testing dataset.

Duas tabelas são apresentadas.

A primeira tabela mostra a contagem bruta das observações e a segunda as porcentagens.

Para entender os resultados das tabelas, podemos pensar da seguinte maneira:
Qual o resultado da soma de todos os valores da tabela de percentagem?
R: 100%
Qual a % de vezes que o modelo preveu que iria chover e choveu? (Na tabela de percetagens, olhe o Predicted: Yes e Actual: Yes)
R: 17.9%
Qual o total de dias em que choveu (na tabela de contagens, some a linha Actual: Yes)?
R: 15 dias
Qual a quantidade de dias onde o modelo preveu que choveria e choveu (na tabela de contagens, olhe o Predicted: Yes e Actual: Yes)?
R: 10 dias (ou seja, 67% das vezes o modelo acertou) - esse é a taxa de verdadeiros positivos do modelo
Qual a quantidade de dias onde o modelo preveu que não choveria e de fato não choveu?
R: 35 dos 41 dias (ou seja, 85% das vezes) - essa é a taxa de veridadeiros negativos do modelo
Qual a acurácia geral do modelo?
R: some as diagonais da tabela: 80.4% (isso quer dizer que em situações normais, o modelo terá aproximadamente essa performance)

Se estivessemos usando o modelo para decidir se pegaríamos ou não nosso guarda chuva ao sair de casa, apenas 6 dos 56 dias teríamos pego o guarda chuva e não utilizado o mesmo. Similarmente, em 5 dos 56 dias teríamos deixado o guarda chuva em casa e pego uma chuva.
Nesse caso, as implicações dos erros no modelo teriam consequências mínimas: ficaríamos molhados ou carregaríamos um peso a mais na mochila. Porém, ao pensarmos em modelos que fazem previsões de doenças as implicações dos erros do modelo seriam muito mais drásticas.

Também podemos avaliar qual a performance do modelo em todos os datasets. Para isso, basta selecionarmos cada dataset e Executar cada uma das ações. Os resultados estarão escritos no Rattle.


Trabalhando com os dados

O livro mostra vários aspectos de como lidar com a qualidade dos dados, ETL, documentação dos dados e afins. Não irei documentar todos os aspectos pois acredito que o tidyverse seja o pacote mais equipado para lidar com a maioria dessas tarefas. Entretando, documentarei alumas técnicas úteis para explorar os dados.

Criando summaries

Alguns exemplos de funções utilizadas para criar resumos com estatísticas básicas das variáveis.

summary()
Essa função também é usada em muitas outras ocasiões (por exemplo para puxar resumos de modelos).

fname <- system.file("csv", "weather.csv", package="rattle") 
weather <- read.csv(fname, encoding = "UTF-8")

summary(weather[7:9])
##     Sunshine       WindGustDir  WindGustSpeed  
##  Min.   : 0.000   NW     : 73   Min.   :13.00  
##  1st Qu.: 5.950   NNW    : 44   1st Qu.:31.00  
##  Median : 8.600   E      : 37   Median :39.00  
##  Mean   : 7.909   WNW    : 35   Mean   :39.84  
##  3rd Qu.:10.500   ENE    : 30   3rd Qu.:46.00  
##  Max.   :13.600   (Other):144   Max.   :98.00  
##  NA's   :3        NA's   :  3   NA's   :2

Utilizando describe(), do pacote Hmisc.

fname <- system.file("csv", "weather.csv", package="rattle") 
weather <- read.csv(fname, encoding = "UTF-8")

library(Hmisc)
## Loading required package: lattice
## Loading required package: survival
## Loading required package: Formula
## 
## Attaching package: 'Hmisc'
## The following objects are masked from 'package:dplyr':
## 
##     combine, src, summarize
## The following objects are masked from 'package:base':
## 
##     format.pval, round.POSIXt, trunc.POSIXt, units
describe(weather[7])
## weather[7] 
## 
##  1  Variables      366  Observations
## ---------------------------------------------------------------------------
## Sunshine 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##      363        3      114        1    7.909    3.875     0.60     2.04 
##      .25      .50      .75      .90      .95 
##     5.95     8.60    10.50    11.80    12.60 
## 
## lowest :  0.0  0.1  0.2  0.3  0.4, highest: 13.1 13.2 13.3 13.5 13.6
## ---------------------------------------------------------------------------
describe(weather[8])
## weather[8] 
## 
##  1  Variables      366  Observations
## ---------------------------------------------------------------------------
## WindGustDir 
##        n  missing distinct 
##      363        3       16 
##                                                                       
## Value          E   ENE   ESE     N    NE   NNE   NNW    NW     S    SE
## Frequency     37    30    23    21    16     8    44    73    22    12
## Proportion 0.102 0.083 0.063 0.058 0.044 0.022 0.121 0.201 0.061 0.033
##                                               
## Value        SSE   SSW    SW     W   WNW   WSW
## Frequency     12     5     3    20    35     2
## Proportion 0.033 0.014 0.008 0.055 0.096 0.006
## ---------------------------------------------------------------------------

Para um resumo ainda mais detalhado, podemos usar a função basicStats(), do pacote fBasics.

fname <- system.file("csv", "weather.csv", package="rattle") 
weather <- read.csv(fname, encoding = "UTF-8")

library(fBasics)
## Warning: package 'fBasics' was built under R version 3.4.2
## Loading required package: timeDate
## Loading required package: timeSeries
## Warning: package 'timeSeries' was built under R version 3.4.2
## 
## Rmetrics Package fBasics
## Analysing Markets and calculating Basic Statistics
## Copyright (C) 2005-2014 Rmetrics Association Zurich
## Educational Software for Financial Engineering and Computational Science
## Rmetrics is free software and comes with ABSOLUTELY NO WARRANTY.
## https://www.rmetrics.org --- Mail to: info@rmetrics.org
basicStats(weather$Sunshine)

Nesse exemplo, esse resumo também nos mostra o lower e upper confidence level do verdadeiro valor da média. Ou seja, com 95% de nível de confiança, podemos dizer que o valor da média estará entre 7.55 e 8.27.

Assimetria

(Retirado do Portal Action): O coeficiente de assimetria permite distinguir as distribuições assimétricas. Um valor negativo indica que a cauda do lado esquerdo da função densidade de probabilidade é maior que a do lado direito. Um valor positivo para a assimetria indica que a cauda do lado direito é maior que a do lado esquerdo. Um valor nulo indica que os valores são distribuídos de maneira relativamente iguais em ambos os lados da média, mas não implica necessariamente, uma distribuição simétrica.

No R:

fname <- system.file("csv", "weather.csv", package="rattle") 
weather <- read.csv(fname, encoding = "UTF-8")

library(tidyverse)
weather %>% select(7,9,12,13) %>% summarise_all(skewness, na.rm = T)

Curtose

(Retirado em parte do Portal Action):
Curtose é uma medida de dispersão que caracteriza o “achatamento” da curva da função de distribuição. Se o restultado > 0, então de distribuição é leptocúrtica e possui a curva da função de distribuição mais afunilada com um pico mais alto do que a distribuição normal. Neste caso dizemos que essa distribuição possui caudas pesadas. Se o resultado < 0, então a funçao de distribuição é mais achatada do que a distribuição normal . Dizemos que esta curva da função de distribuição é platicúrtica. Se o reultado = 0 então a função de distribuição tem o mesmo achatamento da distribuição normal (mesócurticas).

No R:

fname <- system.file("csv", "weather.csv", package="rattle") 
weather <- read.csv(fname, encoding = "UTF-8")

library(tidyverse)
weather %>% select(7,9,12,13) %>% summarise_all(kurtosis, na.rm = T)