terça-feira, 28 de abril de 2015

Olá!

Hoje apresentamos uma aplicação de rede neural artificial no R. Para um entendimento teórico do assunto, recomendamos a leitura de 2 livros:


e


Neste exemplo, utilizamos o pacote NNET e a base disponível no repositório da UCI  Bank Marketing Data Set.

Sobre a base de dados, ela contém 45.211 registros com 21 atributos, descritos abaixo:

Variáveis independentes:
1 - age - Idade
2 - job - Tipo de trabalho
3 - marital : Estado Civil
4 - education - Escolaridade
5 - default - Crédito em atraso?
6 - housing - Possui financiamento imobiliário?
7 - loan - Possui empréstimo pessoal?
8 - contact - meio de contato
9 - month - mês do contato
10 - day_of_week - dia da semana do contato
11 - duration - tempo da ligação
12 - campaign - quantidade de contatos
13 - pdays: tempo de contato decorrido desde a última tentativa (o valor 999 indica que o cliente nunca foi contactado antes)
14 - previous - número de contatos antes desta companha
15 - poutcome - indicação de sucesso da última campanha

Variável alvo/ variável dependente
16 - y - O cliente efetuou algum depósito?

Vamos ao código em R. Teremos 2 arquivos: um para rodar a rede e outro que nos dará suporte à visualização. Os dois arquivos estão em nosso GitHub com os nomes de NN.R para o primeiro e plot.net.R para o segundo, sendo que este último foi atualizado deste outro repositório: https://gist.github.com/fawda123'.

Primeiramente, instalamos a biblioteca nnet, e chamamos o arquivo plot.net.R com o comando source. Também lemos a base com o comando read.csv (veja que renomeamos a base para banco_UMF).

 install.packages("nnet")  
 library(nnet)  
 source("./plot.net.R")  
 base <- read.csv("banco_UMF.csv",header = TRUE, sep = ';')  

Agora, fazemos um reconhecimento da base.

 > names(base)  
  [1] "age"    "job"    "marital"  "education" "default"  "balance"   
  [7] "housing"  "loan"   "contact"  "day"    "month"   "duration"   
 [13] "campaign" "pdays"   "previous" "poutcome" "deposito"   
 > head(base)  
  age     job marital education default balance housing loan contact day month  
 1 58  management married tertiary   no  2143   yes  no unknown  5  may  
 2 44  technician single secondary   no   29   yes  no unknown  5  may  
 3 33 entrepreneur married secondary   no    2   yes yes unknown  5  may  
 4 47 blue-collar married  unknown   no  1506   yes  no unknown  5  may  
 5 33   unknown single  unknown   no    1   no  no unknown  5  may  
 6 35  management married tertiary   no   231   yes  no unknown  5  may  
  duration campaign pdays previous poutcome deposito  
 1   261    1  -1    0 unknown    no  
 2   151    1  -1    0 unknown    no  
 3    76    1  -1    0 unknown    no  
 4    92    1  -1    0 unknown    no  
 5   198    1  -1    0 unknown    no  
 6   139    1  -1    0 unknown    no  
 >   

Vemos que todas as variáveis foram carregas e que também temos algumas variáveis que são categóricas, como job ou education. Para rodar uma rede neural, todas as variáveis devem ser numéricas. Logo, precisamos executar alguma outra função que faça a conversão das variáveis categóricas em contínuas. Uma técnica que podemos utilizar é converter estas variáveis em dummies, que nada mais são do que uma binarização de cada um dos termos presentes nos dados categóricos. Podemos fazer isso facilmente no R, utilizando a função model.matrix(), como abaixo.

 dummies <- as.data.frame(  
             model.matrix(   
              ~ job + marital + education + default + housing  
              + loan + contact + month + poutcome + deposito -1 ,  
              data=base)  
             )  
 base2 <- cbind(base$age,base$balance,base$day,base$duration,  
         base$campaign,base$pdays,base$previous,dummies)  

Note que criamos um data frame para inserir as variáveis dummies e, na sequência, criamos uma variável chamada base2 que recebe este novo dado concatenado por coluna com o nosso alvo e as demais variáveis numéricas que não foram binarizadas. Ao verificar nossa nova base, temos um total de 43 variáveis preditoras, contra as 16 iniciais.

 > names(base2)  
  [1] "base$age"      "base$balance"    "base$day"       
  [4] "base$duration"   "base$campaign"   "base$pdays"      
  [7] "base$previous"   "jobadmin."     "jobblue-collar"    
 [10] "jobentrepreneur"  "jobhousemaid"    "jobmanagement"     
 [13] "jobretired"     "jobself-employed"  "jobservices"      
 [16] "jobstudent"     "jobtechnician"   "jobunemployed"     
 [19] "jobunknown"     "maritalmarried"   "maritalsingle"     
 [22] "educationsecondary" "educationtertiary" "educationunknown"   
 [25] "defaultyes"     "housingyes"     "loanyes"        
 [28] "contacttelephone"  "contactunknown"   "monthaug"       
 [31] "monthdec"      "monthfeb"      "monthjan"       
 [34] "monthjul"      "monthjun"      "monthmar"       
 [37] "monthmay"      "monthnov"      "monthoct"       
 [40] "monthsep"      "poutcomeother"   "poutcomesuccess"    
 [43] "poutcomeunknown"  "depositoyes"   

Agora, vamos utilizar a biblioteca caret para separar a base entre treinamento e teste para treinar a rede e fazer uma avaliação dos resultados.

 set.seed(611)  
 library(caret)  
 inTrain <- createDataPartition(y=base2$depositoyes,p = 0.70, list=FALSE)  
 training <- base2[inTrain,]  
 testing <- base2[-inTrain,]  
 dim(training); dim(testing)  

Separamos agora as variáveis preditoras (x_training) do nosso alvo (y_training).

 x_training <- training[,-44]  
 y_training <- training$depositoyes  
 x_testing <- testing[,-44]  

Agora, chamamos a função nnet() que treina a rede neural. Em nosso exemplo, a rede possui uma camada intermediária com 5 neurônios e 1.000 interações para treinamento.

 nn1<-nnet(x_training,y_training,size=5,linout=T,  
       rang = 0.1,decay = 5e-2, maxit = 1000)  

Agora, utilizamos a função predict() para rodar nossa rede treinada na base de teste (x_testing). Na sequencia concatenamos o alvo com os valores preditos e escrevemos os resultados em um arquivo .csv

 prediction <- predict(nn1,x_testing)   
 evaluation <- cbind(prediction,testing$depositoyes)  
 write.csv2(evaluation,file='evaluation_2.csv')  

Para visualizar a rede, chamamos a função plot.nnet(), importada do arquivo plot.net.R. Nossa rede armazenada no objeto nn1 é passada como parâmetro da função. Também configuramos para que pesos negativos ficassem em vermelho e os positivos, em azul.

 plot.nnet(nn1,pos.col='darkgreen',neg.col='darkblue',alpha.val=0.3,rel.rsc=5,  
      circle.cex=1,cex=1,  
      circle.col='brown')  


Com este destaque, podemos ver que a variável poutcomeunknown é majoritariamente negativa, ou seja, termos o desconhecimento de como foi o contato na última campanha afete negativamente o desempenho da campanha atual, assim como os meses de novembro e setembro.

A avaliação da rede nos mostra que temos um sensitivity de 0,92 (nossa taxa de falso negativo é baixa) enquanto nossa AUC é de 91,43%, resultados que são excelentes.

Um abraço e até o próximo post!

6 comentários:

  1. Curiosa a visualização. Ok, caso esteja trabalhando com um multilayer perceptron a coisa irá ficar bem confusa, mas ainda assim tem um valor didático interessante.

    No aguardo do post sobre DBN. :)

    ResponderExcluir
  2. Evandro, isto que você comentou é alvo de muita discussão nas redes neurais. Visualizar a rede em si geralmente é bem difícil, ainda mais nesta complexidade que você mencionou. Mas já dá para entender alguma coisa...o interessante é saber avaliar os pesos e evitar o overfit.

    Sobre o DBN, vou pensar em alguma aplicação e posto aqui :) Abraço

    ResponderExcluir
  3. Redes Neurais, IA são assuntos que adoro, gostaria de ver mais posts sobre o assunto e sempre com uma abordagem técnica, seja com R ou Python.
    Excelente post !

    ResponderExcluir
  4. PHP is an excellent programming language used widely by most of the web developers. Your article made me learn PHP certification. Thanks for the motivation.
    Regards:
    Best PHP training in chennai
    PHP Training

    ResponderExcluir
  5. Excellent blog!! Such an interesting content to read, your idea made to take Web Designing Certifications. Keep updating more ideas. Thank you.
    Regards:
    web design training course
    web designing institute

    ResponderExcluir