AED de forma rápida e um pouco de Machine Learning

Veja como é possível realizar a AED de forma muito rápida com o pacote SmartEAD, além de uma breve aplicação de técnicas de machine learning e estatística para ilustrar alguns possíveis cenários da analise da dados

Fellipe Gomes

28 minute read

A análise exploratória dos dados

A análise exploratória dos dados (AED) foi um termo que ganhou bastante popularidade quando Tukey publicou o livro Exploratory Data Analysis em 1977 que tratava uma “busca por conhecimento antes da análise de dados de fato”. Ocorre quando busca-se obter informações ocultas sobre os dados, tais como: variação, anomalias, distribuição, tendências, padrões e relações

Ao iniciar uma análise de dados, começamos pela AED para a partir dai decidir como buscar qual solução para o problema. É importante frisar que a AED e a construção de gráficos não são a mesma coisa, mesmo a AED sendo altamente baseada em produção de gráficos como de dispersão, histogramas, boxplots etc.

Por vezes a AED no R pode envolver a produção de longos scripts utilizando funções como as do pacote ggplot2 e mesmo sabendo que desejamos sempre criar o gráfico de maneira mais informativa e atraente possível, as vezes precisamos ter uma noção geral dos dados de forma rápida, não necessariamente tão detalhada e customizada de cara.

A vezes queremos apenas ter uma primeira impressão dos dados e em seguida pensar em quais os gráficos mais se adequariam para a entrega dos resultados que mesmo as funções base do R dependendo do caso também envolvem a confecção de longos scripts.

Existem pacotes que auxiliam na hora de se fazer uma rápida análise exploratória, como o skimr e o DataExplorer. Porém estava pesquisando de existiam mais opções para uma rápida abordagem de AED e me deparei com esta vinheta, por Dayanand, Kiran, Ravi.

Essa vinheta apresenta o pacote SmartEAD que trás uma série de funções que auxiliam na AED de forma bem prática. O pacote está disponível no CRAN.

Para testar o pacote foi utilizada uma base de dados do artigo A Theory of Extramarital Affairs, publicado pela The University of Chicago Press.

Gostei tanto da proposta do pacote que resolvi preparar este post que conta com a explanação de alguns tópicos apresentados pelo autor, algumas explicações da teoria estatística apresentada na análise descritiva e exploratória dos dados e além da aplicação de algumas técnicas estatísticas e de machine learning para o entendimento da base de dados.

SmartEDA

Como ele pode ajudá-lo a criar uma análise de dados exploratória? O SmartEDA inclui várias funções personalizadas para executar uma análise exploratória inicial em qualquer dado de entrada. A saída gerada pode ser obtida em formato resumido e gráfico e os resultados também podem ser exportados como relatórios.

O pacote SmartEDA ajuda a construir uma boa base de compreensão de dados, algumas de suas funcionalidades são:

  • O pacote SmartEDA fará com que você seja capaz de aplicar diferentes tipos de EDA sem ter que lembre-se dos diferentes nomes dos pacotes R e escrever longos scripts R com esforço manual para preparar o relatório da EDA, permitindo o entendimento dos dados de maneira mais rápida
  • Não há necessidade de categorizar as variáveis em caractere, numérico, fator etc. As funções do SmartEDA categorizam automaticamente todos os recursos no tipo de dados correto (caractere, numérico, fator etc.) com base nos dados de entrada.

O pacote SmartEDA ajuda a obter a análise completa dos dados exploratórios apenas executando a função em vez de escrever um longo código r.

Carregando o pacote:

# install.packages("SmartEDA")
suppressMessages(library("SmartEDA"))

outros pactes que serão utilizados no post (incluindo um script com algumas funções, que estará disponível no meu github neste link).

library(knitr)        # Para tabelas interativas
library(DT)           # Para tabelas interativas
library(dplyr)        # Para manipulacao de dados
library(plotly)       # Para gerar uma tabela
library(psych)        # para análise fatorial
source("functions.R") # script com funcoes customizadas

Base de dados utilizada:

Estava à procura de uma base de dados para testar as funcionalidades do pacote SmartEAD quando um colega de trabalho me mostrou um artigo chamado A Theory of Extramarital Affairs, publicado pela The University of Chicago Press. Neste artigo é desenvolvido um modelo pelo estimador de Tobit que explica a alocação de um tempo do indivíduo entre o trabalho e dois tipos de atividades de lazer: tempo passou com o cônjuge e tempo gasto com o amante.

Não conhecia o modelo proposto e em uma rápida pesquisa no Google notei que alguns dos dados utilizados nesse artigo estão disponíveis no pacote AER de Econometria Aplicada com R, que contém funções, conjuntos de dados, exemplos, demonstrações e vinhetas para o livro Applied Econometrics with R e como esses dados já foram tratados e estão “prontos para análise”, resolvi usar essa amostra pela conveniência.

Portanto farei aqui uma análise exploratória e ao final de cada caso (sem variável reposta, com variável resposta numérica e com variável resposta binária), para ter uma breve intuição de como se comportam os dados irei primeiro utilizar um algorítimo de machine learning não supervisionado para o agrupamento das observações (sem considerar q já conhecemos a variável resposta), depois ajustar um* modelo de regressão linear simples* considerando a variável resposta como numérica e por fim o ajuste de um algorítimo de machine learning supervisonado de classificação após discretizar a variável resposta.

A base de dados pode ser conferida a seguir:

suppressMessages(library(AER))
data(Affairs)
Affairs%>%
  datatable()

Neste post, a análise de dados será feita considerando a variável affairs (Quantas vezes envolvido em caso extraconjugal no último ano (aparentemente em 1977)) e a base de dados conta com as variáveis gênero, idade, anos de casado, se tem crianças, religiosidade, educação, ocupação e como avalia o casamento.

Informações detalhadas podem ser conferidas na tabela a seguir, retirada do artigo apresentado:

Obs.: Essa tabela foi feita com o pacote plotly, o código pode ser conferido aqui.

Visão geral dos dados

Entendendo as dimensões do conjunto de dados, nomes de variáveis, resumo geral, variáveis ausentes e tipos de dados de cada variável com a função ExpData(), se o argumento Type = 1, visualização dos dados (os nomes das colunas são “Descrições”, “Obs.”), já se Type = 2, estrutura dos dados (os nomes das colunas são “S.no”, “VarName”, “VarClass”, “VarType”) :

# Visao geral dos dados - Type = 1
ExpData(data=Affairs,
        type=1) # O tipo 1 é uma visão geral dos dados
##                                 Descriptions      Obs
## 1                         Sample size (Nrow)      601
## 2                    No. of Variables (Ncol)        9
## 3                   No. of Numeric Variables        7
## 4                    No. of Factor Variables        2
## 5                      No. of Text Variables        0
## 6                   No. of Logical Variables        0
## 7                      No. of Date Variables        0
## 8   No. of Zero variance Variables (Uniform)        0
## 9      %. of Variables having complete cases 100% (9)
## 10 %. of Variables having <50% missing cases   0% (0)
## 11 %. of Variables having >50% missing cases   0% (0)
## 12 %. of Variables having >90% missing cases   0% (0)

Conferindo o nome das variáveis e os tipos de cada uma:

# Estrutura dos dados - Type = 2
ExpData(data=Affairs,
        type=2) # O tipo 2 é a estrutura dos dados
##   S.no Variable Name Variable Type % of Missing No. of Unique values
## 1    1       affairs       numeric            0                    6
## 2    2       gender*        factor            0                    2
## 3    3           age       numeric            0                    9
## 4    4  yearsmarried       numeric            0                    8
## 5    5     children*        factor            0                    2
## 6    6 religiousness       integer            0                    5
## 7    7     education       numeric            0                    7
## 8    8    occupation       integer            0                    7
## 9    9        rating       integer            0                    5

Esta função fornece visão geral e estrutura dos quadros de dados.

Análise exploratória dos dados

As funções a seguir apresentam a saída EDA para 3 casos diferentes de análise exploratória dos dados, são elas:

  • A variável de destino não está definida

  • A variável alvo é contínua

  • A variável de destino é categórica

Para fins ilustrativos, será feita inicialmente uma análise considerando que não existe variável resposta, em seguida será considerada a variável affairs como variável resposta e por fim, será feita uma transformação nesta variável resposta numérica de forma que ela seja discretizada da seguinte maneira:

\[ 1 \text{ se já houve caso extraconjugal} \\ 0 \text{ se não houve caso extraconjugal} \]

Relatório em uma linha

Caso o interesse seja apenas ter uma noção geral dos dados de forma extremamente rápida, basta rodar a linha de código abaixo:

ExpReport(Affairs,op_file = "teste.html")

Antes de começar a explanar cada um dos casos, achei que seria legal frisar que além de tudo que será apresentado, existe a opção de se obter um relatório extenso sobre a análise exploratória dos dados em apenas uma linha!

Exemplo para o caso 1: a variável de destino não está definida

Para ilustrar o primeiro caso, onde a variável destino não é definida, vamos supor que não existe uma variável alvo na nossa base de dados e estamos interessados em simplesmente obter uma visão geral enquanto pensamos em quais técnicas estatísticas serão utilizadas para avaliar nosso dataset.

Resumo das variáveis numéricas

Resumo de de todas as variáveis numéricas:

ExpNumStat (Affairs, 
            by = "A",       # Agrupar por A (estatísticas resumidas por Todos), G (estatísticas resumidas por grupo), GA (estatísticas resumidas por grupo e Geral)
            gp = NULL,      # variável de destino, se houver, padrão NULL
            MesofShape = 2, # Medidas de formas (assimetria e curtose).
            Outlier = TRUE, # Calcular o limite inferior, o limite superior e o número de outliers
            round = 2)      # Arredondar
##   Vname Group
## 1     1   All

Podemos ver que não existem variáveis negativas e a única variável que apresentou “zero” foi a variável resposta. Nenhum registro como Inf ou como NA e além das medidas descritivas também podemos notar as medidas de skweness e kurtosis. Alguns comentários sobre essas medidas:

Medidas de forma para dar uma avaliação detalhada dos dados. Explica a quantidade e a direção do desvio.

  • Kurotsis explica o quão alto e afiado é o pico central (Achatamento).
  • Skewness não tem unidades: mas um número, como um escore z (medida da assimetria)

Onde:

Kurtose:

A curtose é uma medida de forma que caracteriza o achatamento da curva da função de distribuição de probabilidade, Assim:

  • Se o valor da curtose for = 0 (ou 3, pela segunda definição), então tem o mesmo achatamento que a distribuição normal. Chama-se a estas funções de mesocúrticas
  • Se o valor é > 0 (ou > 3), então a distribuição em questão é mais alta (afunilada) e concentrada que a distribuição normal. Diz-se que esta função probabilidade é leptocúrtica, ou que a distribuição tem caudas pesadas (o significado é que é relativamente fácil obter valores que não se aproximam da média a vários múltiplos do desvio padrão)
  • Se o valor é < 0 (ou < 3), então a função de distribuição é mais “achatada” que a distribuição normal. Chama-se-lhe platicúrtica

Skewness:

O Skewness mede a assimetria das caudas da distribuição. Distribuições assimétricas que tem uma cauda mais “pesada” que a outra apresentam obliquidade. Distribuições simétricas tem obliquidade zero. Assim:

  • Se v>0, então a distribuição tem uma cauda direita (valores acima da média) mais pesada
  • Se v<0, então a distribuição tem uma cauda esquerda (valores abaixo da média) mais pesada
  • Se v=0, então a distribuição é aproximadamente simétrica (na terceira potência do desvio em relação à média).

Distribuições de variáveis numéricas

Representação gráfica de todos os recursos numéricos com gráfico de densidade (uni variada):

# Nota: Variável excluída (se o valor único da variável for menor ou igual a 10 [im = 10])

ExpNumViz(Affairs,
          Page=c(2,2), # padrão de saída. 
          sample=8) # seleção aleatória de plots
## $`0`

Exibidos os gráficos com as densidades das variáveis numéricas. Como podemos ver a maioria da amostra não registrou caso extraconjugal, a maioria tem de 12 ou mais anos de casado. A média amostral da idade dos indivíduos é de aproximadamente 32 anos apresentando leve assimetria com cauda a direita. As demais variáveis podem ser conferidas visualmente.

Resumo de variáveis categóricas

Essa função selecionará automaticamente variáveis categóricas e gerará frequência ou tabelas cruzadas com base nas entradas do usuário. A saída inclui contagens, porcentagens, total de linhas e total de colunas.

Frequência para todas as variáveis independentes categóricas:

ExpCTable(Affairs,
          Target=NULL, # Variavel alvo
          margin=1, # margem de índice, 1 para proporções baseadas em linha e 2 para proporções baseadas em coluna
          clim=10,# quantidade de categorias máximas a serem consideradas para frequência / tabela personalizada, default 10.
          nlim=NULL, # limites exclusivos de variável numérica. Os valores padrão "nlim" são 3, a tabela exclui as variáveis numéricas que têm valores únicos maiores que "nlim"
          round=2, # Arredondar
          bin=NULL, # número de cortes para variável alvo contínua
          per=T) # valores percentuais. Tabela padrão dará contagens.
##   Variable  Valid Frequency Percent CumPercent
## 1   gender female       315   52.41      52.41
## 2   gender   male       286   47.59     100.00
## 3   gender  TOTAL       601      NA         NA
## 4 children     no       171   28.45      28.45
## 5 children    yes       430   71.55     100.00
## 6 children  TOTAL       601      NA         NA

Obs.: NA significa Not Applicable

Distribuições de variáveis categóricas

Essa função varre automaticamente cada variável e cria um gráfico de barras para variáveis categóricas.

Gráficos de barra para todas as variáveis categóricas

ExpCatViz(Affairs,
          fname=NULL, # Nome do arquivo de saida, default é pdf
          clim=10,# categorias máximas a incluir nos gráficos de barras.
          margin=2,# índice, 1 para proporções baseadas em linha e 2 para proporções baseadas em colunas
          Page = c(2,1), # padrao de saida
          sample=4) # seleção aleatória de plot
## $`0`

Machine Lerning com tarefa de agrupamento usando algorítimo não supervisionado de agrupamento

Apenas para efeitos ilustrativos, como estamos supondo que não temos a variável resposta vou remover a coluna affairs do data set e considerarei apenas as variáveis numéricas para fazer uma análise multivariada com o algorítimo de machine learning kmeans.

A função plot_kmeans() pode ser encontrada em meu github no repositório aberto de funções.

Vejamos os resultados:

plot_kmeans(Affairs[,-c(1)] %>% select_if(is.numeric) , 2)
## Loading required namespace: GPArotation

Como podemos observar, foram detectados dois grupos no conjunto de dados. O ideal agora seria fazer uma AED desses clusters identificados e avaliar qual o comportamento dos grupos formados mas como essa variável foi omitida e a seguir discutiremos a avaliação da base diante de da variável resposta, deixo essas análises aos curiosos de plantão.

Mais informações sobre análise multivariava podem ser encontrada no meu post sobre Análise Multivariada com r e também em um kernel que escrevi para a plataforma kaggle.

Além disso disponibilizo uma aplicação Shiny que criei a algum tempo para PCA (Análise de componentes Principais) e tarefa de machine learning com agrupamento nenste link.

Exemplo para o caso 2: A variável de destino é contínua

Agora vamos considerar que estamos diante de um desfecho onde a variável alvo é contínua, para isso será considerada a variável affairs como variável alvo.

Resumo da variável dependente contínua

Descrição da variável affairs:

summary(Affairs[,"affairs"])
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   0.000   0.000   1.456   0.000  12.000

Resumo das variáveis numéricas

Estatísticas de resumo quando a variável dependente é contínua Preço.

ExpNumStat(Affairs,
           by="A", # Agrupar por A (estatísticas resumidas por Todos), G (estatísticas resumidas por grupo), GA (estatísticas resumidas por grupo e Geral)
           Qnt=seq(0,1,0.1), # padrão NULL. Quantis especificados [c (0,25,0,75) encontrarão os percentis 25 e 75]
           MesofShape=1, # Medidas de formas (assimetria e curtose)
           Outlier=TRUE, # Calcular limite superior , inferior e numero de outliers
           round=2) # Arredondamento
##   Vname Group
## 1     1   All
#Se a variável de destino for contínua, as estatísticas de resumo adicionarão a coluna de correlação (Correlação entre a variável de destino e todas as variáveis independentes)

Distribuições de variáveis numéricas

Representação gráfica de todas as variáveis numéricas com gráficos de dispersão (bivariada)

Gráfico de dispersão entre todas as variáveis numéricas e a variável de destino affairs. Esta trama ajuda a examinar quão bem uma variável alvo está correlacionada com variáveis dependentes.

Variável dependente é affairs (contínuo).

ExpNumViz(Affairs,
            target="affairs", # Variavel alvo
            nlim=4, # a variável numérica com valor exclusivo é maior que 4
            Page=c(2,2), # formato de saida
            sample=8) # selecionado aleatoriamente 8 gráficos de dispersão
## $`0`

Resumo de variáveis categóricas

Resumo de variáveis categóricas de acordo com a frequência para todas as variáveis independentes categóricas por Affairs

##bin=4, descretized 4 categories based on quantiles
ExpCTable(Affairs,
          Target="affairs",
          margin=1, # margem de índice, 1 para proporções baseadas em linha e 2 para proporções baseadas em coluna
          clim=10,# quantidade de categorias máximas a serem consideradas para frequência / tabela personalizada, default 10.
          nlim=NULL, # limites exclusivos de variável numérica. Os valores padrão "nlim" são 3, a tabela exclui as variáveis numéricas que têm valores únicos maiores que "nlim"
          round=0, # Arredondar
          bin=NULL, # número de cortes para variável alvo contínua
          per=T) # valores percentuais. Tabela padrão dará contagens.
##    VARIABLE CATEGORY Number affairs:(-0.012,3] affairs:(3,6] affairs:(6,9]
## 1    gender   female     nn                273             0            22
## 2    gender     male     nn                248             0            20
## 3    gender    TOTAL     nn                521             0            42
## 4    gender   female      %                 52           NaN            52
## 5    gender     male      %                 48           NaN            48
## 6    gender    TOTAL      %                100           NaN           100
## 7  children       no     nn                157             0             7
## 8  children      yes     nn                364             0            35
## 9  children    TOTAL     nn                521             0            42
## 10 children       no      %                 30           NaN            17
## 11 children      yes      %                 70           NaN            83
## 12 children    TOTAL      %                100           NaN           100
##    affairs:(9,12] TOTAL
## 1              20   315
## 2              18   286
## 3              38   601
## 4              53    52
## 5              47    48
## 6             100   100
## 7               7   171
## 8              31   430
## 9              38   601
## 10             18    28
## 11             82    72
## 12            100   100

Distribuições de variáveis categóricas

Essa função varre automaticamente cada variável e cria um gráfico de barras para variáveis categóricas.

Gráficos de barra para todas as variáveis categóricas

ExpCatViz(Affairs,
          target="affairs", # Variavel target
          fname=NULL, # Nome do arquivo de saida, default é pdf
          clim=10,# categorias máximas a incluir nos gráficos de barras.
          margin=2,# índice, 1 para proporções baseadas em linha e 2 para proporções baseadas em colunas
          Page = c(2,1), # padrao de saida
          sample=4) # seleção aleatória de plot
## $`0`

Avaliando a correlação entre as variáveis

suppressMessages(library(ggplot2))
suppressMessages(library(dplyr))
suppressMessages(library(GGally))
data("Affairs")
#Correlaçoes cruzadas
Affairs%>%
  select(age:rating,affairs)%>%
ggpairs(lower = list(continuous = my_fn,combo=wrap("facethist", binwidth=1), 
                                       continuous=wrap(my_bin, binwidth=0.25)),aes(fill=affairs))+theme_bw()

ggcorr(Affairs,label = T,nbreaks = 5,label_round = 4)

Modelo de regressão linear usando stepwiseAIC

Por fim, vamos ajustar um modelo de regressão linear para entender quais são as variáveis significativas para explicar a variação da variável resposta e qual o efeito de cada uma dessas variáveis explicativas no nosso desfecho.

Com o R base é possível ajustar um modelo de regressão linear simples utilizando a função lm() e em seguida usar a função step() para utilizar técnicas como stepwise, porém como quero utilizar também a técnica de validação cruzada. Para isso vou utilizar o pacote caret, muito famoso por facilitar o ajuste de modelos de machine learning (ou mesmo modelos estatísticos tradicionais).

Além disso estou usando as transformações center(), que subtrai a média dos dados e scale() divide pelo desvio padrão.

data("Affairs")
suppressMessages(library(caret))
set.seed(123)
index <- sample(1:2,nrow(Affairs),replace=T,prob=c(0.8,0.2))
train = Affairs[index==1,] %>%as.data.frame()
test = Affairs[index==2,] %>%as.data.frame()

# Setando os parâmetros para o controle do ajuste do modelo:
fitControl <- trainControl(method = "repeatedcv",         # 10fold cross validation
                     number = 10, repeats=5                         # do 5 repititições of cv
                     )

# Regressão Linear com Stepwise
set.seed(825)
lmFit <- train(affairs ~ ., data = train,
                method = "lmStepAIC", 
                trControl = fitControl,
                preProc = c("center", "scale"),trace=F)
summary(lmFit)
## 
## Call:
## lm(formula = .outcome ~ age + yearsmarried + religiousness + 
##     occupation + rating, data = dat)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -5.1452 -1.7819 -0.7601  0.2719 11.3518 
## 
## Coefficients:
##               Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)     1.4146     0.1401  10.096 < 0.0000000000000002 ***
## age            -0.6890     0.2291  -3.007             0.002779 ** 
## yearsmarried    1.1058     0.2302   4.804          0.000002087 ***
## religiousness  -0.5121     0.1455  -3.519             0.000475 ***
## occupation      0.3858     0.1445   2.669             0.007858 ** 
## rating         -0.7830     0.1470  -5.326          0.000000155 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3.07 on 474 degrees of freedom
## Multiple R-squared:  0.144,  Adjusted R-squared:  0.135 
## F-statistic: 15.95 on 5 and 474 DF,  p-value: 0.00000000000001542

Como podemos ver as variáveis Idade, Anos de casado, religiosidade, ocupação e como avaliam o próprio relacionamento se apresentaram significantes

Como o \(R^2=0,144\), conclui-se que \(14,4%\) da variação da quantidade de vezes que foi envolvida em caso extraconjugal no último ano é explicada pelo modelo ajustado.

Observando a coluna das estimativas, podemos notar o quanto varia a quantidade de vezes que foi envolvido em caso extraconjugal ao aumentar em 1 unidade cada uma das variáveis explicativas.

Além disso o valor p obtido através da estatística F foi menor do que \(\alpha = 0.05\), o que implica que pelo menos uma das variáveis explicativas tem relação significativa com a variável resposta.

Selecionando apenas as variáveis selecionadas com o ajuste do modelo:

train=as.data.frame(train[,c(1,3,4,6,8,9)])
test=as.data.frame(test[,c(1,3,4,6,8,9)])

Diagnóstico do modelo

Existem varias formas e técnicas de se avaliar o ajuste de um modelo e como o foco deste post é apresentar as utilidades do pacote SmartEAD irei fazer uma avaliação muito breve sobre os resíduos, apresento mais algumas maneiras no post sobre pacotes do R para avaliar o ajuste de modelos.

Avaliando residuos
library(GGally)
# calculate all residuals prior to display
residuals <- lapply(train[2:ncol(train)], function(x) {
  summary(lm(affairs ~ x, data = train))$residuals
})

# add a 'fake' column
train$Residual <- seq_len(nrow(train))

# calculate a consistent y range for all residuals
y_range <- range(unlist(residuals))

# plot the data
ggduo(
  train,
  2:6, c(1,7),
  types = list(continuous = lm_or_resid)
)+ theme_bw()

train=train%>%
  select(-Residual)

Neste gráfico é possível observar como se comportam os ajustes de modelos lineares de cada variável explicativa em relação à variável resposta e além disso na segunda linha é possível notar o comportamento dos resíduos no modelo.

Uma das suposições do ajuste de um modelo linear normal é de que \(\epsilon \sim N(0,\sigma^2)\) e visualmente parece que essa condição não deve ser atendida, pois esperaríamos algo como uma “nuvem” aleatória de pontos em torno de zero.

Residuos e medidas de influencia

Além da suposição da normalidade dos resíduos, existem ainda mais detalhes do comportamento desses erros, uma breve apresentação no gráfico a seguir:

suppressMessages(library(ggfortify))

autoplot(lmFit$finalModel, which = 1:6, data = train,
         colour = 'affairs', label.size = 3,
         ncol = 3)+theme_classic()

Pelo que parece no gráfico com título “Normal Q-Q”, as variáveis associadas à variável resposta com valores acima de 6 se comportam de forma inesperadas quando comparadas com os quantis teóricos.

Exemplo para o caso 3: a variável de destino é categórica

Para finalizar a avaliação da base de dados, a Variável alvo será discretizado de tal forma:

\[ 1 = \text{se affairs} > 0\\ 0 = c.c. \]

Essa transformação será utilizada apenas com fins ilustrativos do algorítimo de árvore de decisões, que está ficando muito comum na ciência de dados como uma tarefa supervisionada de machine learning.

Affairs = Affairs %>% 
  mutate(daffairs = ifelse(Affairs$affairs!=0,1,0)) %>% 
  mutate(daffairs = as.factor(daffairs))%>% 
  select(-affairs)
levels(Affairs$daffairs) = c("Não", "Sim")

Resumo das variáveis numéricas

Resumo de todas as variáveis numéricas

ExpNumStat(Affairs,
           by="A", # Agrupar por A (estatísticas resumidas por Todos), G (estatísticas resumidas por grupo), GA (estatísticas resumidas por grupo e Geral)
           gp="daffairs", # Variavel alvo
           Qnt=seq(0,1,0.1), # padrão NULL. Quantis especificados [c (0,25,0,75) encontrarão os percentis 25 e 75]
           MesofShape=1, # Medidas de formas (assimetria e curtose)
           Outlier=TRUE, # Calcular limite superior , inferior e numero de outliers
           round=2) # Arredondamento
##   Vname Group
## 1     1   All

Distribuições de variáveis numéricas

Box plots para todas as variáveis numéricas vs variável dependente categórica - Comparação bivariada apenas com categorias

Boxplot para todos os atributos numéricos por cada categoria de affair

ExpNumViz(Affairs,
          target="daffairs", # Variaevl alvo
          type=1, # 1 (boxplot por categoria e global), 2 (boxplot por categoria apenas), 3 (boxplot for overall)
          nlim=NULL, # limite único da variável numérica. O padrão nlim é 3, o gráfico excluirá a variável numérica que está tendo um valor único menor que 'nlim'
          col=c("pink","yellow","orange"), # Cor dos boxplots
          Page=c(2,2),# formato de saida
          sample=8) # amostra de variaveis para o resumo
## $`0`

Resumo das variáveis categóricas

Tabulação cruzada com variável de destino com tabelas customizadas entre todas as variáveis independentes categóricas e a variável de destino daffairs:

ExpCTable(Affairs,
          Target="daffairs", # variavel alvo
          margin=1, # 1 para proporcoes por linha, 2 para colunas
          clim=10, # maximo de categorias consideradas por frequencia/ custom table
          round=2, # arredondar
          per=F) # valores percentuais. Tabela padrão dará contagens.
##   VARIABLE CATEGORY daffairs:Não daffairs:Sim TOTAL
## 1   gender   female          243           72   315
## 2   gender     male          208           78   286
## 3   gender    TOTAL          451          150   601
## 4 children       no          144           27   171
## 5 children      yes          307          123   430
## 6 children    TOTAL          451          150   601

Distribuições de variáveis categóricas

Gráfico de barras empilhadas com barras verticais ou horizontais para todas as variáveis categóricas

ExpCatViz(Affairs,
          target="daffairs",
          fname=NULL, # Nome do arquivo de saida, default é pdf
          clim=10,# categorias máximas a incluir nos gráficos de barras.
          margin=2,# índice, 1 para proporções baseadas em linha e 2 para proporções baseadas em colunas
          Page = c(2,1), # padrao de saida
          sample=4) # seleção aleatória de plot
## $`0`

Valor da informação

IV é o peso da evidência e valores da informação, \(ln(odss) \times(pct0 - pct1)\) onde \(pct1 =\frac{\text{"boas observações"}}{\text{"total boas observações"}}\); \(pct0 = \frac{"\text{observações ruins"} }{ \text{"total de observações ruins"}}\) e $odds = $

ExpCatStat(Affairs %>% mutate(daffairs = if_else(daffairs=="Não", 0, 1)) ,
           Target="daffairs",
           result = "IV") %>% 
  select(-one_of("Target","Ref_1","Ref_0"))
##           Variable  Class Out_1 Out_0 TOTAL Per_1 Per_0 Odds   WOE   IV
## 1         gender.1 female    72   243   315  0.48  0.54 1.27 -0.12 0.01
## 2         gender.2   male    78   208   286  0.52  0.46 0.79  0.12 0.01
## 3       children.1     no    27   144   171  0.18  0.32 2.14 -0.58 0.08
## 4       children.2    yes   123   307   430  0.82  0.68 0.47  0.19 0.03
## 5            age.1   17.5     3     3     6  0.02  0.01 0.46  0.69 0.01
## 6            age.2     22    16   101   117  0.11  0.22 1.21 -0.69 0.08
## 7            age.3     27    36   117   153  0.24  0.26 1.33 -0.08 0.00
## 8            age.4     32    38    77   115  0.25  0.17 1.48  0.39 0.03
## 9            age.5     37    23    65    88  0.15  0.14 1.08  0.07 0.00
## 10           age.6     42    18    38    56  0.12  0.08 1.65  0.41 0.02
## 11           age.7     47     7    16    23  0.05  0.04 0.90  0.22 0.00
## 12           age.8     52     6    15    21  0.04  0.03 0.41  0.29 0.00
## 13           age.9     57     3    19    22  0.02  0.04 3.05 -0.69 0.01
## 14  yearsmarried.1  0.125     1    10    11  0.01  0.02 1.20 -0.69 0.01
## 15  yearsmarried.2  0.417     1     9    10  0.01  0.02 1.05 -0.69 0.01
## 16  yearsmarried.3   0.75     3    28    31  0.02  0.06 1.53 -1.11 0.04
## 17  yearsmarried.4    1.5    12    76    88  0.08  0.17 1.34 -0.76 0.07
## 18  yearsmarried.5     10    21    49    70  0.14  0.11 0.43  0.24 0.01
## 19  yearsmarried.6     15    62   142   204  0.41  0.31 0.31  0.28 0.03
## 20  yearsmarried.7      4    27    78   105  0.18  0.17 0.33  0.06 0.00
## 21  yearsmarried.8      7    23    59    82  0.15  0.13 0.30  0.14 0.00
## 22 religiousness.1      1    20    28    48  0.13  0.06 0.66  0.77 0.05
## 23 religiousness.2      2    41   123   164  0.27  0.27 0.53  0.00 0.00
## 24 religiousness.3      3    43    86   129  0.29  0.19 1.71  0.43 0.04
## 25 religiousness.4      4    33   157   190  0.22  0.35 1.00 -0.46 0.06
## 26 religiousness.5      5    13    57    70  0.09  0.13 2.32 -0.37 0.01
## 27     education.1     12    13    31    44  0.09  0.07 1.21  0.25 0.00
## 28     education.2     14    35   119   154  0.23  0.26 1.00 -0.13 0.00
## 29     education.3     16    20    95   115  0.13  0.21 1.33 -0.48 0.04
## 30     education.4     17    27    62    89  0.18  0.14 1.38  0.25 0.01
## 31     education.5     18    33    79   112  0.22  0.18 0.58  0.20 0.01
## 32     education.6     20    20    60    80  0.13  0.13 0.85  0.00 0.00
## 33     education.7      9     2     5     7  0.01  0.01 1.29  0.00 0.00
## 34    occupation.1      1    23    90   113  0.15  0.20 1.91 -0.29 0.01
## 35    occupation.2      2     3    10    13  0.02  0.02 1.17  0.00 0.00
## 36    occupation.3      3    15    32    47  0.10  0.07 0.75  0.36 0.01
## 37    occupation.4      4    21    47    68  0.14  0.10 1.40  0.34 0.01
## 38    occupation.5      5    44   160   204  0.29  0.35 1.45 -0.19 0.01
## 39    occupation.6      6    39   104   143  0.26  0.23 0.90  0.12 0.00
## 40    occupation.7      7     5     8    13  0.03  0.02 0.73  0.41 0.00
## 41        rating.1      1     8     8    16  0.05  0.02 0.37  0.92 0.03
## 42        rating.2      2    33    33    66  0.22  0.07 0.98  1.14 0.17
## 43        rating.3      3    27    66    93  0.18  0.15 1.28  0.18 0.01
## 44        rating.4      4    48   146   194  0.32  0.32 3.57  0.00 0.00
## 45        rating.5      5    34   198   232  0.23  0.44 3.12 -0.65 0.14

Testes estatísticos

Além de toda a informação visual e das estatísticas descritivas, ainda contamos com alguma função que fornece estatísticas resumidas para todas as colunas de caracteres ou categóricas no data frame

ExpCatStat(Affairs %>% mutate(daffairs = if_else(daffairs=="Não", 0, 1)),
           Target="daffairs", # variavel alvo
           result = "Stat") # resumo de estatisticas
##        Variable   Target Unique Chi-squared p-value df IV Value Cramers V
## 1        gender daffairs      2       1.334   0.248  1     0.02      0.05
## 2      children daffairs      2      10.055   0.002  1     0.11      0.13
## 3           age daffairs      9      17.771   0.023  8     0.15      0.17
## 4  yearsmarried daffairs      8      17.177   0.016  7     0.17      0.17
## 5 religiousness daffairs      5      19.354   0.001  4     0.16      0.18
## 6     education daffairs      7       7.057   0.316  6     0.06      0.11
## 7    occupation daffairs      7       6.718   0.348  6     0.04      0.11
## 8        rating daffairs      5      41.433   0.000  4     0.35      0.26
##   Degree of Association    Predictive Power
## 1             Very Weak      Not Predictive
## 2                  Weak Somewhat Predictive
## 3                  Weak Somewhat Predictive
## 4                  Weak Somewhat Predictive
## 5                  Weak Somewhat Predictive
## 6                  Weak      Not Predictive
## 7                  Weak      Not Predictive
## 8              Moderate   Highly Predictive

Os critérios usados para classificação de poder preditivo variável categórico são

  • Se o valor da informação for <0,03, então, poder de previsão = “Não Preditivo”

  • Se o valor da informação é de 0,3 a 0,1, então o poder preditivo = “um pouco preditivo”

  • Se o valor da informação for de 0,1 a 0,3, então, poder preditivo = “Medium Predictive”

  • Se o valor da informação for> 0.3, então, poder preditivo = “Altamente Preditivo”

Nota para a variável rating que segundo essas regras, demonstrou alto poder preditivo.

Machine Learning com Random Forest

O algorítimo supervisionado de machine learning conhecido como Random Forest é uma grande caixa preta. Apresenta resultados muito robustos pois combina o resultado de várias árvores de decisões e pode ser facilmente aplicada com o pacote caret.

No livro do pacote caret o algorítimo é apresentado da seguinte maneira: “segundo o pacote do R: Para cada árvore, a precisão da previsão na parte fora do saco dos dados é registrada. Então, o mesmo é feito após a permutação de cada variável preditora. A diferença entre as duas precisões é calculada pela média de todas as árvores e normalizada pelo erro padrão. Para a regressão, o MSE é calculado nos dados fora da bolsa para cada árvore e, em seguida, o mesmo é computado após a permutação de uma variável. As diferenças são calculadas e normalizadas pelo erro padrão. Se o erro padrão é igual a 0 para uma variável, a divisão não é feita.”

Não entrarei em muitos detalhes sobre o algorítimo pois esta parte é apenas um demonstrativo dos diferentes cenários de análise exploratória dos dados. Serão comentadas apenas algumas métricas utilizadas.

Ajuste com o algorítimo Random Forest:

suppressMessages(library(caret))
set.seed(1)
index <- sample(1:2,nrow(Affairs),replace=T,prob=c(0.8,0.2))
train = Affairs[index==1,] %>%as.data.frame()
test = Affairs[index==2,] %>%as.data.frame()


# Setando os parâmetros para o controle do ajuste do modelo:
fitControl <- trainControl(method = "repeatedcv",         # 10fold cross validation
                     number = 10
                     )

# Random Forest
set.seed(825)
antes = Sys.time()
rfFit <- train(daffairs ~ ., data = train,
                method = "rf", 
                trControl = fitControl,
                trace=F,
                preProc = c("center", "scale"))

antes - Sys.time() # Para saber quanto tempo durou o ajuste
## Time difference of -6.990173 secs

Resultados do ajuste:

rfFit
## Random Forest 
## 
## 484 samples
##   8 predictor
##   2 classes: 'Não', 'Sim' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Cross-Validated (10 fold, repeated 1 times) 
## Summary of sample sizes: 436, 436, 435, 435, 435, 436, ... 
## Resampling results across tuning parameters:
## 
##   mtry  Accuracy   Kappa    
##   2     0.7539966  0.1369868
##   5     0.7292942  0.1727691
##   8     0.7231718  0.1613695
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 2.

Accurary e Kappa

Essas são as métricas padrão usadas para avaliar algoritmos em conjuntos de dados de classificação binária.

  • Accuray: é a porcentagem de classificar corretamente as instâncias fora de todas as instâncias. É mais útil em uma classificação binária do que problemas de classificação de várias classes, porque pode ser menos claro exatamente como a precisão é dividida entre essas classes (por exemplo, você precisa ir mais fundo com uma matriz de confusão).
  • Kappa ou Kappa de Cohen é como a precisão da classificação, exceto que é normalizado na linha de base da chance aleatória em seu conjunto de dados. É uma medida mais útil para usar em problemas que têm um desequilíbrio nas classes (por exemplo, divisão de 70 a 30 para as classes 0 e 1 e você pode atingir 70% de precisão prevendo que todas as instâncias são para a classe 0).

A seguir a “Variable Importance” de cada variável:

rfImp = varImp(rfFit);rfImp
## rf variable importance
## 
##               Overall
## rating         100.00
## age             94.66
## religiousness   85.77
## education       78.99
## yearsmarried    67.41
## occupation      62.48
## gendermale       6.94
## childrenyes      0.00
plot(rfImp)

A função dimensiona automaticamente as pontuações de importância entre 0 e 100, os escores de importância da variável em Random Forest são medidas agregadas. Eles apenas quantificam o impacto do preditor, não o efeito específico, para isso utilizamos o ajuste um modelo paramétrico onde conseguimos estimar termos estruturais.

É claro que existem muitos adentos a serem feitos tanto na forma como os dados foram apresentados no ajuste do modelo linear e no Random Forest, mas como a finalidade do post continua sendo apresentar o pacote SmartEAD, encerrarei a avaliação por aqui.

Caso alguém queira entender com mais detalhes a avaliação de modelos de machine learning, talvez o livro do pacote caret seja uma alternativa interessante para ter uma noção geral.

Todos os modelos estão errados, alguns são úteis - George Box

Não conseguimos nenhum modelo útil que quantificasse as incertezas nas modelagens deste post mas conseguimos executar praticamente todas as funções do pacote SmartEAD e foi muito útil para conhecer a base em poucas linhas, obrigado Dayanand Ubrangala, Kiran R. e Ravi Prasad Kondapalli!

comments powered by Disqus