A maioria dos “modeleiros”, Estatísticos, Analistas de Dados, “Machine Learners” concordam que a parte que toma a maior parte do tempo no desenvolvimento de um modelo é a limpeza e a preparação da base de dados. Uns dizem que isso toma 80% do tempo do trabalho.
Por isso, vamos aqui pegar uma base de dados não tratada e preparar e limpar essa base para um algoritmo de Machine Learning. Vamos acessar os dados de rotatividade de clientes de uma empresa. Nossa variável alvo é a que chamamos de “Saiu”, que significa se o cliente deixou ou não a empresa.
library(tidyverse)
dados <- read.csv("Churn.csv", sep = ';', na.strings = "",stringsAsFactors = TRUE)
head(dados)
## X0 X1 X2 X3 X4 X4.1 X6 X7 X8 X9 X10 X11
## 1 1 619 RS Feminino 42 2 0 1 1 1 10134888 1
## 2 2 608 SC Feminino 41 1 8380786 1 0 1 11254258 0
## 3 3 502 RS Feminino 42 8 1596608 3 1 0 11393157 1
## 4 4 699 RS Feminino 39 1 0 2 0 0 9382663 0
## 5 5 850 SC Feminino 43 2 12551082 1 1 1 790841 0
## 6 6 645 SC Masculino 44 8 11375578 2 1 0 14975671 1
Como as colunas não tinham nome, vamos colocar os nomes das colunas de acordo com o conhecimento adquirido, por exemplo com o analista de negócio da empresa.
#Dar nomes corretos as colunas
colnames(dados) <- c("Id","Score","Estado","Genero","Idade","Patrimonio","Saldo","Produtos","TemCartCredito","Ativo","Salario","Saiu")
head(dados)
## Id Score Estado Genero Idade Patrimonio Saldo Produtos TemCartCredito
## 1 1 619 RS Feminino 42 2 0 1 1
## 2 2 608 SC Feminino 41 1 8380786 1 0
## 3 3 502 RS Feminino 42 8 1596608 3 1
## 4 4 699 RS Feminino 39 1 0 2 0
## 5 5 850 SC Feminino 43 2 12551082 1 1
## 6 6 645 SC Masculino 44 8 11375578 2 1
## Ativo Salario Saiu
## 1 1 10134888 1
## 2 1 11254258 0
## 3 0 11393157 1
## 4 0 9382663 0
## 5 1 790841 0
## 6 0 14975671 1
Agora sim conseguimos entender os dados e podemos fazer as primeiras análises
Vamos explorar as colunas categóricas.
Vamos criar as variáveis para os gráficos
#Estado
count_estado <- dados %>% count(Estado)
ggplot(count_estado, aes(x=Estado, y=n)) + geom_bar(stat='identity', aes(fill=Estado))+ theme_bw() +
ggtitle('Estados')
Parece que há um erro na variável, vamos corrigir isso. Só há dados do sul.Logo não há os Estados RP,SP e TD. Vamos substitutir todos para RS
dados<-dados %>% mutate(Estado= case_when(
Estado=='RP' ~ 'RS',
Estado=='TD' ~ 'RS',
Estado=='RS' ~ 'RS',
Estado=='SP' ~ 'RS',
Estado=='SC' ~ 'SC',
Estado=='PR' ~ 'PR',
))
Agora vamos refazer o graficos
#Estado
count_estado <- dados %>% count(Estado)
ggplot(count_estado, aes(x=Estado, y=n)) + geom_bar(stat='identity', aes(fill=Estado))+ theme_bw() +
ggtitle('Estados')
Agora sim a variavel Estado esta correta
#Genero
count_genero<- dados %>% count(Genero)
count_genero
## Genero n
## 1 F 2
## 2 Fem 1
## 3 Feminino 461
## 4 M 6
## 5 Masculino 521
## 6 <NA> 8
Parece que a variavel genero também tem problemas. Vamos corrir e deixar somente as categorias Masculino e Feminino.
dados<-dados %>% mutate(Genero= case_when(
Genero == 'Fem'~ 'Feminino',
Genero == 'F'~ 'Feminino',
Genero == 'Feminino'~ 'Feminino',
Genero == 'M'~ 'Masculino',
Genero == 'Masculino'~ 'Masculino'
))
Vamos ver se há valores faltantes(NA)
sum(is.na(dados$Genero))
## [1] 8
Há 8 nulos, vamos transformar na classe majoritaria. Poderiamos também excluir esses valores.
dados$Genero<- ifelse(is.na(dados$Genero), 'Masculino', dados$Genero)
sum(is.na(dados$Genero))
## [1] 0
Agora o gráfico:
count_genero<- dados %>% count(Genero)
ggplot(count_genero, aes(x=Genero, y=n)) + geom_bar(stat = 'identity', aes(fill=Genero))+
ggtitle('Genero') + theme_bw()
Agora vamos verificar a variavel alvo:
count_target<-dados %>% count(Saiu)
count_target$Saiu <- as.factor(count_target$Saiu)
ggplot(count_target, aes(x= Saiu, y=n)) + geom_bar(stat='identity', aes(fill=Saiu))+ theme_bw()+
ggtitle('Target')
Base um pouco desbalanceada, talvez fosse interessante fazer um oversampling. Porém o objetivo aqui é só explorar os dados e coriigir dados faltantes e duplicados.
Vamos agora olhar a variavel categorica x a variavel alvo:
round(prop.table(table(dados$Estado,dados$Saiu, dnn = c('Estados','Alvo')))*100,2)
## Alvo
## Estados 0 1
## PR 18.22 7.51
## RS 40.74 7.71
## SC 20.72 5.11
round(prop.table(table(dados$Genero,dados$Saiu, dnn = c('Genero','Alvo')))*100,2)
## Alvo
## Genero 0 1
## Feminino 34.43 12.01
## Masculino 45.25 8.31
Agora as as variáveis numéricas:
ggplot(dados, aes(x=Score)) + geom_histogram(aes(y=..density..),color="black", fill="white")+
geom_density(alpha=.2, fill="#FF6666") + theme_bw() + ggtitle('Score')
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Parece não ter problemas nos dados de score. Seria interessante saber se tem sentido os valores máximos e minimos de score apontados no histograma. Podemos visualizar também o boxplot:
ggplot(dados, aes( x=1, y=Score)) + geom_boxplot(color="black", fill="red") + theme_bw()+
ggtitle('Score')
Score versus variavel alvo:
dados$Saiu <- as.factor(dados$Saiu)
ggplot(dados, aes(x=Saiu, y=Score,fill=Saiu)) + geom_boxplot() + theme_bw()+
ggtitle("Score x Target")
Variavel Idade
ggplot(dados, aes(x=Idade))+ geom_histogram(aes(y=..density..),color="black", fill="white")+
geom_density(alpha=.2, fill='#99d8c9')
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Os dados parecem ter distribuição aproxiamdamente normal. Porém parece ter idades negativas. Vamos olhar o boxplot desses dados:
ggplot(dados, aes(x=1, y=Idade)) + geom_boxplot()+ theme_bw()+
ggtitle('Idade')
Veja que há idades negativas e idades com mais de 130 anos.
Esses dados devem ser corrigidos, uma forma é susbtitutir esses valores pela idade mediana. Antes vejamos se tem NAS:
sum(is.na(dados$Idade))
## [1] 0
sum(dados$Idade<0)
## [1] 2
Não há NAS mas há 2 negativos, agora sim vamos ajustar os dados:
dados <- dados %>% mutate(Idade=ifelse(Idade<0 | Idade>120,median(Idade, na.rm = TRUE),Idade))
Refazendo o grafico:
ggplot(dados, aes(x=1, y=Idade)) + geom_boxplot()+ theme_bw()+
ggtitle('Idade')
Agora sim, não há mais outliers na variável. Podemos ver o boxplot da idade x target
ggplot(dados, aes(x=Saiu, y=Idade,fill=Saiu)) + geom_boxplot()+ theme_bw()+
ggtitle('Idade')
Variável patrimonio:
sum(is.na(dados$Patrimonio))
## [1] 0
Perceba que não há NA
Olhando o máximo e mínimo parece que os dados estão ok.
max(dados$Patrimonio)
## [1] 10
min(dados$Patrimonio)
## [1] 0
Variável Saldo
Parece não ter problema também:
sum(is.na(dados$Saldo))
## [1] 0
max(dados$Saldo)
## [1] 21177431
min(dados$Saldo)
## [1] 0
Variável Produtos
Parece não ter problema também:
sum(is.na(dados$Produtos))
## [1] 0
max(dados$Produtos)
## [1] 4
min(dados$Produtos)
## [1] 1
Variável TemCartCredito
Parece não ter problema também:
count_card <- dados %>% count(TemCartCredito)
count_card
## TemCartCredito n
## 1 0 297
## 2 1 702
Contra a variavel alvo
count_card_targer <- dados %>% count(TemCartCredito, Saiu)
count_card_targer
## TemCartCredito Saiu n
## 1 0 0 237
## 2 0 1 60
## 3 1 0 559
## 4 1 1 143
Vamos analisar graficamente:
dados<- dados %>% mutate(tem_cartao=ifelse(TemCartCredito==1,'sim', 'não'))
count_card_targer <- dados %>% count(tem_cartao, Saiu)
count_card_targer
## tem_cartao Saiu n
## 1 não 0 237
## 2 não 1 60
## 3 sim 0 559
## 4 sim 1 143
ggplot(count_card_targer, aes(x=Saiu, y=n)) + geom_bar(stat = 'identity', aes(fill=tem_cartao))+
theme_bw()+ ggtitle('Cartão x saiu')
Cartão Ativo ou Não. Vamos só ver se há algum numero distinjto de 0 ou 1. caso Contrário estará ok,
unique(dados$Ativo)
## [1] 1 0
Logo está ok
Agora a variável salario.
Tirando NAS:
#tratar salários
summary(dados$Salario)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 9.677e+03 3.029e+06 8.703e+06 3.529e+07 1.405e+07 1.193e+10 7
#ver mediana
median(dados$Salario,na.rm = T)
## [1] 8703250
#atribuir mediana a NAs
dados[is.na(dados$Salario),]$Salario = median(dados$Salario,na.rm = T)
#buscar NAS em salario para checar
dados[!complete.cases(dados$Salario),]
## [1] Id Score Estado Genero Idade
## [6] Patrimonio Saldo Produtos TemCartCredito Ativo
## [11] Salario Saiu tem_cartao
## <0 rows> (or 0-length row.names)
Plotando o grafico:
ggplot(dados, aes(x=1, y=Salario))+ geom_boxplot()
Veja que há outliers, criando um parametro com desvio padrão para eliminar os outliers:
desv = sd(dados$Salario, na.rm = T)
desv
## [1] 528720617
dados[dados$Salario >= 2 *desv , ]$Salario
## [1] 11934688000 11563829000 1640178900 1119811900
Substituindo os outliers pela mediana:
#atualizamos todos para mediana
median(dados$Salario)
## [1] 8703250
dados[dados$Salario >= 2 *desv , ]$Salario = median(dados$Salario)
Agora fazendo o gráfico:
ggplot(dados, aes(x=1, y=Salario))+ geom_boxplot()
Agora sim a base já está limpa e pronta para ser usada em algoritmos de Machine Learning.
Era isso.
Keep calm and analysing data!