Material de apoio para o curso Análise de Dados 1, em Computação@UFCG.

Pacotes e fixando os números aleatórios que serão gerados.

require(caret)
## Loading required package: caret
## Warning: package 'caret' was built under R version 3.1.3
## Loading required package: lattice
## Loading required package: ggplot2
require(dplyr)
## Loading required package: dplyr
## 
## Attaching package: 'dplyr'
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
require(kernlab)
## Loading required package: kernlab
set.seed(3456)

Separação de dados em treino e teste. Estamos usando os mesmos dados de spam do problema de regressão logística.

emails <- read.table("./email.txt", sep = "\t", header = T)
emails <- select(emails, spam, to_multiple, from, cc, sent_email, image, dollar, password, num_char, line_breaks, format, exclaim_mess)
emails$spam <- as.factor(emails$spam)

trainIndex <- createDataPartition(emails$spam, p = .75,
                                  list = FALSE,
                                  times = 1)
head(trainIndex)
##      Resample1
## [1,]         1
## [2,]         2
## [3,]         3
## [4,]         4
## [5,]         5
## [6,]         6
emailsTrain <- emails[ trainIndex,]
emailsTest  <- emails[-trainIndex,]

Para treinar o modelo, é importante entender o algoritmo que o caret usa:

Algoritmo de treino do caret

Repare que ele precisa de: 1. os conjuntos de valores para os parâmetros que testará, 2. um método para decidir as amostras em que ele testará cada conjunto de valores dos parâmetros (ressampling) 3. (opcional) do pre-processamento que deve ser feito para cada atributo dos dados antes do fit em cada amostra

Depois de avaliar os valores dos parâmetros em várias amostras, ele escolhe o melhor conjunto e treina um modelo com todos os dados. Esse é o modelo final que usaremos. Para avaliá-lo, podemos usar os dados de teste que separamos mais acima.

Fazendo na prática. Primeiro criamos um objeto com algumas “configurações” para o algoritmo acima:

fitControl <- trainControl(## 10-fold CV
                           method = "cv",
                           number = 10)

Aqui estamos usando validação cruzada (cross-validation) que divide os dados em 10 partes e roda o modelo 10 vezes, cada vez usando uma das partes diferentes como validação. Dê uma explorada nas possibilidades do parâmetro ‘method’. repeatedcv é um bom começo.

Sobre o pré-processamento, como vamos usar primeiro knn, e há variáveis numéricas, é preciso pré-processá-las. Isso é feito mais abaixo. Primeiro, como o dataset é muito desbalanceado, precisamos balanceá-lo:

table(emailsTrain$spam)
## 
##    0    1 
## 2666  276
probs_balanceads <- ifelse(emailsTrain$spam == 0, .1 / 2666, .9 / 276)
is <- sample(1:NROW(emailsTrain), 500, prob = probs_balanceads, replace = F)
emailsTrain_b <- emailsTrain[is, ]
table(emailsTrain_b$spam)
## 
##   0   1 
## 224 276

Agora vamos estimar o melhor k do knn com essa configuração de treinamento.

# o treinamento pode demorar... aqui por exemplo: 
ptm <- proc.time()

knnFit1 <- train(spam ~ ., data = emailsTrain_b,
                 method = "knn",
                 trControl = fitControl, 
                 preProcess = c("center","scale"), 
                 tuneGrid = data.frame(.k = 2:15))

proc.time() - ptm
##    user  system elapsed 
##   1.741   0.042   2.292
knnFit1
## k-Nearest Neighbors 
## 
## 500 samples
##  11 predictor
##   2 classes: '0', '1' 
## 
## Pre-processing: centered, scaled 
## Resampling: Cross-Validated (10 fold) 
## 
## Summary of sample sizes: 451, 449, 450, 449, 451, 449, ... 
## 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa      Accuracy SD  Kappa SD  
##    2  0.7915110  0.5774484  0.05869125   0.11851145
##    3  0.7919520  0.5762433  0.04561655   0.09467405
##    4  0.7977935  0.5861272  0.04789043   0.10047463
##    5  0.7896727  0.5683705  0.04675646   0.09941960
##    6  0.7957919  0.5829874  0.03470413   0.07300186
##    7  0.8155958  0.6235336  0.04349820   0.08908015
##    8  0.8075926  0.6081355  0.03885852   0.07792319
##    9  0.8174358  0.6283976  0.04791410   0.09670586
##   10  0.8194766  0.6327796  0.04618713   0.09391225
##   11  0.8214390  0.6366529  0.04860560   0.09915409
##   12  0.8174374  0.6276019  0.04882094   0.10104391
##   13  0.8135974  0.6195562  0.04475565   0.09348686
##   14  0.8094766  0.6113425  0.05439212   0.11325701
##   15  0.8114750  0.6162050  0.05037744   0.10382115
## 
## Accuracy was used to select the optimal model using  the largest value.
## The final value used for the model was k = 11.

Repare que a variação é pequena…

plot(knnFit1)

Avaliando o modelo com os dados de teste:

knnPredict <- predict(knnFit1,newdata = emailsTest)
confusionMatrix(knnPredict, emailsTest$spam)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 666   7
##          1 222  84
##                                           
##                Accuracy : 0.7661          
##                  95% CI : (0.7383, 0.7923)
##     No Information Rate : 0.907           
##     P-Value [Acc > NIR] : 1               
##                                           
##                   Kappa : 0.3267          
##  Mcnemar's Test P-Value : <2e-16          
##                                           
##             Sensitivity : 0.7500          
##             Specificity : 0.9231          
##          Pos Pred Value : 0.9896          
##          Neg Pred Value : 0.2745          
##              Prevalence : 0.9070          
##          Detection Rate : 0.6803          
##    Detection Prevalence : 0.6874          
##       Balanced Accuracy : 0.8365          
##                                           
##        'Positive' Class : 0               
## 
mosaicplot(table(knnPredict, emailsTest$spam), xlab = "knn", ylab = "dados")

Bem mais ou menos. Veja também que não nos preocupamos com o fato de que os falsos positivos são piores que os falsos negativos.

Tentemos com uma SVM. Aqui não precisamos balancear os dados de treino:

# Aqui demora mais ainda :)
ptm <- proc.time()

svmFit <- train(spam ~ ., data = emailsTrain_b,
                method = "svmRadial",
                trControl = fitControl, 
                preProcess = c("center","scale"), 
                tuneLength = 8, 
                metric = "Kappa") # outra opção além de accuracy

proc.time() - ptm
##    user  system elapsed 
##   3.156   0.056   3.484
svmFit
## Support Vector Machines with Radial Basis Function Kernel 
## 
## 500 samples
##  11 predictor
##   2 classes: '0', '1' 
## 
## Pre-processing: centered, scaled 
## Resampling: Cross-Validated (10 fold) 
## 
## Summary of sample sizes: 451, 450, 451, 451, 450, 449, ... 
## 
## Resampling results across tuning parameters:
## 
##   C      Accuracy   Kappa      Accuracy SD  Kappa SD 
##    0.25  0.7956271  0.5884748  0.06027119   0.1226626
##    0.50  0.7975878  0.5914668  0.05643274   0.1158216
##    1.00  0.8135910  0.6216148  0.06546872   0.1344724
##    2.00  0.8096695  0.6127901  0.06673562   0.1379402
##    4.00  0.7978263  0.5870305  0.06936767   0.1445179
##    8.00  0.8079112  0.6077786  0.06603478   0.1369330
##   16.00  0.8119520  0.6159082  0.06517210   0.1357424
##   32.00  0.8099520  0.6117370  0.06382676   0.1329561
## 
## Tuning parameter 'sigma' was held constant at a value of 2.531382
## Kappa was used to select the optimal model using  the largest value.
## The final values used for the model were sigma = 2.531382 and C = 1.
svmPredict <- predict(svmFit,newdata = emailsTest)
confusionMatrix(svmPredict, emailsTest$spam)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 697  14
##          1 191  77
##                                           
##                Accuracy : 0.7906          
##                  95% CI : (0.7637, 0.8157)
##     No Information Rate : 0.907           
##     P-Value [Acc > NIR] : 1               
##                                           
##                   Kappa : 0.337           
##  Mcnemar's Test P-Value : <2e-16          
##                                           
##             Sensitivity : 0.7849          
##             Specificity : 0.8462          
##          Pos Pred Value : 0.9803          
##          Neg Pred Value : 0.2873          
##              Prevalence : 0.9070          
##          Detection Rate : 0.7120          
##    Detection Prevalence : 0.7263          
##       Balanced Accuracy : 0.8155          
##                                           
##        'Positive' Class : 0               
## 
mosaicplot(table(svmPredict, emailsTest$spam), xlab = "svm", ylab = "dados")

Bem melhor, embora ruim também. Parece que as características que escolhemos dos dados realmente não ajudam…