Validação Cruzada

Tarssio Barreto

21 de abril de 2019

Objetivo

Esta pequena apresentação tem como objetivo demonstrar o funcionamento de métodos de validação cruzada utilizando o algoritmo KNN.

Para isto usaremos o pacote caret que nos possibilita criar uma estrutura base para aplicação de algoritmos de aprendizado de máquinas.

Neste pacote, a modelagem ocorre em “camadas”, ou seja, configuramos uma camada de entrada de dados, outra camada para pré-processamento de dados e outra para a validação cruzada. É possível, também, realizar o afunilamento dos parâmetros a serem determinados, conseguindo maior precisão na determinação destes e no resultado final, porém não será o foco deste breve documento.

Nesta demonstração será utilizado os dados referentes a classificação do uso doméstico de água. Para tornar mais didático será utilizado, apenas, as categórias referentes ao uso de chuveiro, bacia e torneira interna.

Serão, também, simulados, a partir destes dados, três diferentes tipos de bancos de dados:

  1. Neste primeiro, haverá uma amostra composta de mil unidades de cada uma das categorias;

  2. Neste, a amostra é de 10 observações de cada uma destas;

  3. No último, haverá 50 observações de chuveiro e bacia, porém, apenas 20 de torneira interna.

Queremos, por fim, comparar a performace dos métodos de validação cruzada para cada um destes. Os métodos utilizados serão o de Boostrap, k folds e Repeated k folds.

Por fim, será comparado o tempo de computação quando o método é o Repeated k folds versus Leave One Out.

# Bibliotecas

require(caret)
## Loading required package: caret
## Loading required package: lattice
## Loading required package: ggplot2
require(tidyverse)
## Loading required package: tidyverse
## -- Attaching packages --------------------------------------------------------------------- tidyverse 1.2.1 --
## v tibble  2.0.1     v purrr   0.2.5
## v tidyr   0.8.2     v dplyr   0.7.8
## v readr   1.1.1     v stringr 1.3.1
## v tibble  2.0.1     v forcats 0.3.0
## -- Conflicts ------------------------------------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
## x purrr::lift()   masks caret::lift()
require(profvis)
## Loading required package: profvis
require(gridExtra)
## Loading required package: gridExtra
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine

Carregando dados

data <- load("data_041218_1138.RData")

Exemplo A

Obtendo a amostragem desejada:

# Criando amostragem

set.seed(1)

dados <- features_atual %>% 
  filter(categoria %in% c("Bacia", "Chuveiro", "Torneira Interna")) %>% 
  filter(casa == "B")

dados$categoria <- fct_drop(dados$categoria)  # Removendo as categórias não utilizadas

sample <- dados %>%
  group_by(categoria) %>%
  sample_n(1000) %>%  # Escolhendo 1000 observações de cada
  select(-c(10:18)) %>% 
  na.omit()

head(sample)
## # A tibble: 6 x 9
## # Groups:   categoria [1]
##   categoria duracao nmoda volume inercia  moda media  pico mediana
##   <fct>       <dbl> <int>  <dbl>   <dbl> <dbl> <dbl> <dbl>   <dbl>
## 1 Bacia          40     3  0.700   3      1.20  1.05  1.20    1.20
## 2 Bacia         110    10  5.30   10      3     2.89  3       3   
## 3 Bacia         160    12  4.40    4.33   1.80  1.65  2.40    1.80
## 4 Bacia          60     3  7.80    2      8.60  7.80  9.20    8.60
## 5 Bacia         120     7  6.10    1.4    3.60  3.05  3.60    3.60
## 6 Bacia         140     5  9.90    0.556  4.80  4.24  4.80    4.20

Criando o grupo de treino e de teste:

# Definindo Split

split=0.80

trainIndex <- createDataPartition(sample$categoria, p=split, list=FALSE)

# Separando 

data_train <- sample[ trainIndex,]

data_test <- sample[-trainIndex,]

Com Bootstrap

model <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method = "boot"))

model
## k-Nearest Neighbors 
## 
## 2400 samples
##    8 predictor
##    3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Bootstrapped (25 reps) 
## Summary of sample sizes: 2400, 2400, 2400, 2400, 2400, 2400, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa    
##    5  0.6335375  0.4504252
##    7  0.6402937  0.4605450
##    9  0.6445510  0.4670280
##   11  0.6473185  0.4712062
##   13  0.6490409  0.4737846
##   15  0.6506494  0.4762175
##   17  0.6487977  0.4734362
##   19  0.6490465  0.4738308
##   21  0.6501826  0.4755473
##   23  0.6516640  0.4777978
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 23.
# Armazenando o número ótimo de vizinhos

k1 <- model$finalModel$k

Obtido, então, a melhor estimativa de vizinhos próximos com o bootstrap, será avaliada a acurácia deste modelo aplicado ao teste:

# Realizando a predição para o teste

predictions <- predict(model, data_test)

# Observando os resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia              145               22       84
##   Torneira Interna    12              144        8
##   Chuveiro            43               34      108
## 
## Overall Statistics
##                                           
##                Accuracy : 0.6617          
##                  95% CI : (0.6222, 0.6995)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.4925          
##  Mcnemar's Test P-Value : 4.585e-07       
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.7250                  0.7200          0.5400
## Specificity                0.7350                  0.9500          0.8075
## Pos Pred Value             0.5777                  0.8780          0.5838
## Neg Pred Value             0.8424                  0.8716          0.7783
## Prevalence                 0.3333                  0.3333          0.3333
## Detection Rate             0.2417                  0.2400          0.1800
## Detection Prevalence       0.4183                  0.2733          0.3083
## Balanced Accuracy          0.7300                  0.8350          0.6738
aux <- confusionMatrix(predictions, data_test$categoria)

# Armazenando para futuras comparações

acc1 <- aux$overall[1]

k-fold

model2 <- train(categoria ~ ., 
      data = data_train,
      method = "knn",
      preProcess = c("center", "scale"),
      tuneLength = 10, 
      trControl = trainControl(method="cv", number=10))

model2
## k-Nearest Neighbors 
## 
## 2400 samples
##    8 predictor
##    3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Cross-Validated (10 fold) 
## Summary of sample sizes: 2160, 2160, 2160, 2160, 2160, 2160, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa   
##    5  0.6500000  0.475000
##    7  0.6570833  0.485625
##    9  0.6525000  0.478750
##   11  0.6529167  0.479375
##   13  0.6608333  0.491250
##   15  0.6650000  0.497500
##   17  0.6654167  0.498125
##   19  0.6633333  0.495000
##   21  0.6658333  0.498750
##   23  0.6687500  0.503125
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 23.
# Armazenando o número ótimo de vizinhos

k2 <- model2$finalModel$k

Observando, então, os resultados para o conjunto de dados do teste:

# Realizando a predição para os dados de teste

predictions <- predict(model2, data_test)

# Observando os resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia              148               22       83
##   Torneira Interna    12              145        8
##   Chuveiro            40               33      109
## 
## Overall Statistics
##                                           
##                Accuracy : 0.67            
##                  95% CI : (0.6308, 0.7075)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.505           
##  Mcnemar's Test P-Value : 2.898e-07       
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.7400                  0.7250          0.5450
## Specificity                0.7375                  0.9500          0.8175
## Pos Pred Value             0.5850                  0.8788          0.5989
## Neg Pred Value             0.8501                  0.8736          0.7823
## Prevalence                 0.3333                  0.3333          0.3333
## Detection Rate             0.2467                  0.2417          0.1817
## Detection Prevalence       0.4217                  0.2750          0.3033
## Balanced Accuracy          0.7388                  0.8375          0.6813
aux <- confusionMatrix(predictions, data_test$categoria)

# Armazenando 

acc2 <- aux$overall[1]

Repeated k-fold Cross Validation

Repetiremos o mesmo feito para o “repeated k-fold”

model3 <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method="repeatedcv", number=10, repeats=10))


model3
## k-Nearest Neighbors 
## 
## 2400 samples
##    8 predictor
##    3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 2160, 2160, 2160, 2160, 2160, 2160, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa   
##    5  0.6555833  0.483375
##    7  0.6570000  0.485500
##    9  0.6565833  0.484875
##   11  0.6595833  0.489375
##   13  0.6600000  0.490000
##   15  0.6612500  0.491875
##   17  0.6631667  0.494750
##   19  0.6650000  0.497500
##   21  0.6644167  0.496625
##   23  0.6624167  0.493625
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 19.
k3 <- model3$finalModel$k

Observando, então, os resultados para o grupo de testes:

# Predição

predictions <- predict(model3, data_test)

# Resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia              152               18       80
##   Torneira Interna    11              148        8
##   Chuveiro            37               34      112
## 
## Overall Statistics
##                                           
##                Accuracy : 0.6867          
##                  95% CI : (0.6479, 0.7236)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.53            
##  Mcnemar's Test P-Value : 2.42e-07        
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.7600                  0.7400          0.5600
## Specificity                0.7550                  0.9525          0.8225
## Pos Pred Value             0.6080                  0.8862          0.6120
## Neg Pred Value             0.8629                  0.8799          0.7890
## Prevalence                 0.3333                  0.3333          0.3333
## Detection Rate             0.2533                  0.2467          0.1867
## Detection Prevalence       0.4167                  0.2783          0.3050
## Balanced Accuracy          0.7575                  0.8462          0.6913
aux <- confusionMatrix(predictions, data_test$categoria)

acc3 <- aux$overall[1]

Comparações

A primeira comparação, será aquela de vizinhos próximos:

metodos <- c("bootstrap", "k-folds", "rep. k-folds")

k <- cbind(k1,k2,k3)

colnames(k) <- metodos

k
##      bootstrap k-folds rep. k-folds
## [1,]        23      23           19

Outra comparação, de grande importância, versa sobre a distribuição da acurácia (boxplot) de cada um dos métodos:

boxplot(model[["resample"]][["Accuracy"]], model2[["resample"]][["Accuracy"]], model3[["resample"]][["Accuracy"]])

Por fim, comparando a acurácia do teste:

acc <- cbind(acc1, acc2, acc3)

colnames(acc) <- metodos

acc
##          bootstrap k-folds rep. k-folds
## Accuracy 0.6616667    0.67    0.6866667

É interessante observar que o modelo de repetidos k-folds possui melhores resultados quanto a acurácia do teste e tem o menor número ótimos de vizinhos, sendo um modelo mais simples quando comparado aos demais.

Pontua-se, também, que o bootstrap é o modelo com os piores valores de acurácia, quando se observa os conjuntos de validação cruzada, enquanto que os repetidos k-folds apresentam grande variabilidade, mas bom resultado mediano.

Exemplo B

Neste exemplo há menos dados, 10 de cada uma dos métodos, observaremos, como os métodos de validação cruzadas reagirão.

Ajustando a amostragem:

set.seed(1)

dados <- features_atual %>% 
  filter(categoria %in% c("Bacia", "Chuveiro", "Torneira Interna" )) %>% 
  filter(casa == "B")

dados$categoria <- fct_drop(dados$categoria)

sample <- dados %>%
  group_by(categoria) %>%
  sample_n(10) %>% 
  select(-c(10:18))


# Definindo Split

split=0.80

trainIndex <- createDataPartition(sample$categoria, p=split, list=FALSE)

data_train <- sample[ trainIndex,]

data_test <- sample[-trainIndex,]

Com Bootstrap

model <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method = "boot"))

model
## k-Nearest Neighbors 
## 
## 24 samples
##  8 predictor
##  3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Bootstrapped (25 reps) 
## Summary of sample sizes: 24, 24, 24, 24, 24, 24, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa        
##    5  0.4185960   0.1689475688
##    7  0.3981284   0.1694012245
##    9  0.3903478   0.1617269789
##   11  0.3464747   0.1032896027
##   13  0.3018687   0.0473766703
##   15  0.2991212   0.0621640749
##   17  0.2704214   0.0384434124
##   19  0.2320058  -0.0001058204
##   21  0.2308615  -0.0027628721
##   23  0.2176118  -0.0273536608
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 5.
# Armazenando o número ótimo de vizinhos

k1 <- model$finalModel$k

Obtido, então, a melhor estimativa de vizinhos próximos com o bootstrap, para o exemplo B, será avaliada a acurácia deste modelo aplicado ao teste:

# Realizando a predição para o teste

predictions <- predict(model, data_test)

# Observando os resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia                1                0        2
##   Torneira Interna     0                2        0
##   Chuveiro             1                0        0
## 
## Overall Statistics
##                                           
##                Accuracy : 0.5             
##                  95% CI : (0.1181, 0.8819)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : 0.3196          
##                                           
##                   Kappa : 0.25            
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.5000                  1.0000          0.0000
## Specificity                0.5000                  1.0000          0.7500
## Pos Pred Value             0.3333                  1.0000          0.0000
## Neg Pred Value             0.6667                  1.0000          0.6000
## Prevalence                 0.3333                  0.3333          0.3333
## Detection Rate             0.1667                  0.3333          0.0000
## Detection Prevalence       0.5000                  0.3333          0.1667
## Balanced Accuracy          0.5000                  1.0000          0.3750
aux <- confusionMatrix(predictions, data_test$categoria)

# Armazenando para futuras comparações

acc1 <- aux$overall[1]

k-fold

model2 <- train(categoria ~ ., 
      data = data_train,
      method = "knn",
      preProcess = c("center", "scale"),
      tuneLength = 10, 
      trControl = trainControl(method="cv", number=10))

model2
## k-Nearest Neighbors 
## 
## 24 samples
##  8 predictor
##  3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Cross-Validated (10 fold) 
## Summary of sample sizes: 21, 23, 22, 21, 21, 22, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa      
##    5  0.5833333   0.25925926
##    7  0.4833333   0.14814815
##    9  0.4500000   0.09259259
##   11  0.4666667   0.14814815
##   13  0.3500000  -0.09259259
##   15  0.4166667   0.07407407
##   17  0.3666667   0.03703704
##   19  0.3666667   0.03703704
##   21  0.3833333   0.14814815
##   23  0.1333333  -0.05000000
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 5.
# Armazenando o número ótimo de vizinhos

k2 <- model2$finalModel$k

Observando, então, os resultados para o conjunto de dados do teste:

# Realizando a predição para os dados de teste

predictions <- predict(model2, data_test)

# Observando os resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia                1                0        2
##   Torneira Interna     1                2        0
##   Chuveiro             0                0        0
## 
## Overall Statistics
##                                           
##                Accuracy : 0.5             
##                  95% CI : (0.1181, 0.8819)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : 0.3196          
##                                           
##                   Kappa : 0.25            
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.5000                  1.0000          0.0000
## Specificity                0.5000                  0.7500          1.0000
## Pos Pred Value             0.3333                  0.6667             NaN
## Neg Pred Value             0.6667                  1.0000          0.6667
## Prevalence                 0.3333                  0.3333          0.3333
## Detection Rate             0.1667                  0.3333          0.0000
## Detection Prevalence       0.5000                  0.5000          0.0000
## Balanced Accuracy          0.5000                  0.8750          0.5000
aux <- confusionMatrix(predictions, data_test$categoria)

# Armazenando 

acc2 <- aux$overall[1]

Repeated k-fold Cross Validation

Repetiremos o mesmo feito para o “repeated k-fold”

model3 <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method="repeatedcv", number=10, repeats=10))


model3
## k-Nearest Neighbors 
## 
## 24 samples
##  8 predictor
##  3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 22, 21, 22, 22, 22, 22, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa       
##    5  0.5505051   0.310283688
##    7  0.5488215   0.289007092
##    9  0.3771044   0.088541667
##   11  0.3501684   0.064236111
##   13  0.3367003   0.032646048
##   15  0.3451178   0.036458333
##   17  0.3636364   0.064236111
##   19  0.2811448  -0.003401361
##   21  0.2659933   0.073129252
##   23  0.1784512   0.015151515
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 5.
k3 <- model3$finalModel$k

Observando, então, os resultados para o grupo de testes:

# Predição

predictions <- predict(model3, data_test)

# Resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia                1                0        1
##   Torneira Interna     0                2        0
##   Chuveiro             1                0        1
## 
## Overall Statistics
##                                           
##                Accuracy : 0.6667          
##                  95% CI : (0.2228, 0.9567)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : 0.1001          
##                                           
##                   Kappa : 0.5             
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.5000                  1.0000          0.5000
## Specificity                0.7500                  1.0000          0.7500
## Pos Pred Value             0.5000                  1.0000          0.5000
## Neg Pred Value             0.7500                  1.0000          0.7500
## Prevalence                 0.3333                  0.3333          0.3333
## Detection Rate             0.1667                  0.3333          0.1667
## Detection Prevalence       0.3333                  0.3333          0.3333
## Balanced Accuracy          0.6250                  1.0000          0.6250
aux <- confusionMatrix(predictions, data_test$categoria)

acc3 <- aux$overall[1]

Comparações

Comparando o “k” ótimo:

A primeira comparação, será aquela de vizinhos próximos:

metodos <- c("bootstrap", "k-folds", "rep. k-folds")

k <- cbind(k1,k2,k3)

colnames(k) <- metodos

k
##      bootstrap k-folds rep. k-folds
## [1,]         5       5            5

Outra comparação, de grande importância, versa sobre a distribuição da acurácia (boxplot) de cada um dos métodos:

boxplot(model[["resample"]][["Accuracy"]], model2[["resample"]][["Accuracy"]], model3[["resample"]][["Accuracy"]])

Por fim, comparando a acurácia do teste:

acc <- cbind(acc1, acc2, acc3)

colnames(acc) <- metodos

acc
##          bootstrap k-folds rep. k-folds
## Accuracy       0.5     0.5    0.6666667

Uma vez reduzido o número de observações, também são diminuido o número de vizinhos próximos considerados no knn. Outra questão visível diz respeito a distribuição da acurácia nos dados de treino que é igual para o k-fold e para os repetidos k-folds, consequência, também, da baixa quantidade de observações.

Porém, novamente, os repetidos k-folds demonstraram melhores resultados frente aos dados de treino. Enquanto que os resultados do boostrap e do k-folds são parecidos.

Exemplo C

Criando amostragem

set.seed(1)

dados <- features_atual %>% 
  filter(categoria %in% c("Bacia", "Chuveiro")) %>% 
  filter(casa == "B")


sample <- dados %>%
  group_by(categoria) %>%
  sample_n(50)


dados2 <- features_atual %>% 
  filter(categoria %in% c("Torneira Interna")) %>% 
  filter(casa == "B")

sample2 <- dados2 %>%
  sample_n(10) 

sample_final <- bind_rows(sample, sample2) %>% 
  select(-c(10:18))

sample_final$categoria <- fct_drop(sample_final$categoria)
# Definindo Split

split=0.80

trainIndex <- createDataPartition(sample_final$categoria, p=split, list=FALSE)

data_train <- sample_final[trainIndex,]

data_test <- sample_final[-trainIndex,]

Por Boostrap

model <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method = "boot"))

model
## k-Nearest Neighbors 
## 
## 88 samples
##  8 predictor
##  3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Bootstrapped (25 reps) 
## Summary of sample sizes: 88, 88, 88, 88, 88, 88, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa     
##    5  0.5390613  0.18943653
##    7  0.5194965  0.14943477
##    9  0.5032134  0.11701582
##   11  0.4687869  0.05644428
##   13  0.4807345  0.07379152
##   15  0.4765920  0.06828667
##   17  0.4806196  0.07477825
##   19  0.4637459  0.04845997
##   21  0.4525194  0.02780356
##   23  0.4584021  0.03508098
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 5.
# Armazenando o número ótimo de vizinhos

k1 <- model$finalModel$k

Obtido, então, a melhor estimativa de vizinhos próximos com o bootstrap, para o exemplo B, será avaliada a acurácia deste modelo aplicado ao teste:

# Realizando a predição para o teste

predictions <- predict(model, data_test)

# Observando os resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia                7                0        3
##   Torneira Interna     0                0        0
##   Chuveiro             3                2        7
## 
## Overall Statistics
##                                          
##                Accuracy : 0.6364         
##                  95% CI : (0.4066, 0.828)
##     No Information Rate : 0.4545         
##     P-Value [Acc > NIR] : 0.06715        
##                                          
##                   Kappa : 0.3333         
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.7000                 0.00000          0.7000
## Specificity                0.7500                 1.00000          0.5833
## Pos Pred Value             0.7000                     NaN          0.5833
## Neg Pred Value             0.7500                 0.90909          0.7000
## Prevalence                 0.4545                 0.09091          0.4545
## Detection Rate             0.3182                 0.00000          0.3182
## Detection Prevalence       0.4545                 0.00000          0.5455
## Balanced Accuracy          0.7250                 0.50000          0.6417
aux <- confusionMatrix(predictions, data_test$categoria)

# Armazenando para futuras comparações

acc1 <- aux$overall[1]

k-fold

model2 <- train(categoria ~ ., 
      data = data_train,
      method = "knn",
      preProcess = c("center", "scale"),
      tuneLength = 10, 
      trControl = trainControl(method="cv", number=10))

model2
## k-Nearest Neighbors 
## 
## 88 samples
##  8 predictor
##  3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Cross-Validated (10 fold) 
## Summary of sample sizes: 79, 79, 79, 79, 79, 79, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa    
##    5  0.6263889  0.3317647
##    7  0.6388889  0.3412500
##    9  0.6055556  0.2862500
##   11  0.6027778  0.2700000
##   13  0.5680556  0.2050000
##   15  0.5805556  0.2300000
##   17  0.5819444  0.2350000
##   19  0.5625000  0.2050000
##   21  0.5625000  0.2050000
##   23  0.5263889  0.1350000
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 7.
# Armazenando o número ótimo de vizinhos

k2 <- model2$finalModel$k

Observando, então, os resultados para o conjunto de dados do teste:

# Realizando a predição para os dados de teste

predictions <- predict(model2, data_test)

# Observando os resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia                6                0        6
##   Torneira Interna     0                0        0
##   Chuveiro             4                2        4
## 
## Overall Statistics
##                                           
##                Accuracy : 0.4545          
##                  95% CI : (0.2439, 0.6779)
##     No Information Rate : 0.4545          
##     P-Value [Acc > NIR] : 0.582           
##                                           
##                   Kappa : 0               
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.6000                 0.00000          0.4000
## Specificity                0.5000                 1.00000          0.5000
## Pos Pred Value             0.5000                     NaN          0.4000
## Neg Pred Value             0.6000                 0.90909          0.5000
## Prevalence                 0.4545                 0.09091          0.4545
## Detection Rate             0.2727                 0.00000          0.1818
## Detection Prevalence       0.5455                 0.00000          0.4545
## Balanced Accuracy          0.5500                 0.50000          0.4500
aux <- confusionMatrix(predictions, data_test$categoria)

# Armazenando 

acc2 <- aux$overall[1]

Repeated k-fold Cross Validation

Repetiremos o mesmo feito para o “repeated k-fold”

model3 <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method="repeatedcv", number=10, repeats=10))


model3
## k-Nearest Neighbors 
## 
## 88 samples
##  8 predictor
##  3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 80, 79, 79, 79, 79, 80, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa    
##    5  0.6254167  0.3216765
##    7  0.6026389  0.2721667
##    9  0.5993056  0.2670000
##   11  0.5625000  0.1961111
##   13  0.5752778  0.2190000
##   15  0.5694444  0.2080000
##   17  0.5486111  0.1710000
##   19  0.5256944  0.1285000
##   21  0.5245833  0.1265000
##   23  0.5162500  0.1105000
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 5.
k3 <- model3$finalModel$k

Observando, então, os resultados para o grupo de testes:

# Predição

predictions <- predict(model3, data_test)

# Resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia                7                0        3
##   Torneira Interna     0                0        0
##   Chuveiro             3                2        7
## 
## Overall Statistics
##                                          
##                Accuracy : 0.6364         
##                  95% CI : (0.4066, 0.828)
##     No Information Rate : 0.4545         
##     P-Value [Acc > NIR] : 0.06715        
##                                          
##                   Kappa : 0.3333         
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.7000                 0.00000          0.7000
## Specificity                0.7500                 1.00000          0.5833
## Pos Pred Value             0.7000                     NaN          0.5833
## Neg Pred Value             0.7500                 0.90909          0.7000
## Prevalence                 0.4545                 0.09091          0.4545
## Detection Rate             0.3182                 0.00000          0.3182
## Detection Prevalence       0.4545                 0.00000          0.5455
## Balanced Accuracy          0.7250                 0.50000          0.6417
aux <- confusionMatrix(predictions, data_test$categoria)

acc3 <- aux$overall[1]

Comparações

Comparando o “k” ótimo:

A primeira comparação, será aquela de vizinhos próximos:

metodos <- c("bootstrap", "k-folds", "rep. k-folds")

k <- cbind(k1,k2,k3)

colnames(k) <- metodos

k
##      bootstrap k-folds rep. k-folds
## [1,]         5       7            5

Outra comparação, de grande importância, versa sobre a distribuição da acurácia (boxplot) de cada um dos métodos:

boxplot(model[["resample"]][["Accuracy"]], model2[["resample"]][["Accuracy"]], model3[["resample"]][["Accuracy"]])

Por fim, comparando a acurácia do teste:

acc <- cbind(acc1, acc2, acc3)

colnames(acc) <- metodos

acc
##          bootstrap   k-folds rep. k-folds
## Accuracy 0.6363636 0.4545455    0.6363636

Neste último caso, a despeito de uma boa diferença entre a distribuição das acurácias para os métodos de bootstrap e repetidos k-folds, se obteve o mesmo resultado para os dados de treino.

Comparando tempo de processamento

Nesta última etapa, será utilizado o pacote profvis para visualizar o tempo gasto para realizar a validação cruzada utilizando os métodos: repeated k-folds e Leave One Out.

Para isto, recriará-se a amostragem feita no exemplo A.

Obtendo a amostragem desejada:

# Criando amostragem

set.seed(1)

dados <- features_atual %>% 
  filter(categoria %in% c("Bacia", "Chuveiro", "Torneira Interna")) %>% 
  filter(casa == "B")

dados$categoria <- fct_drop(dados$categoria)  # Removendo as categórias não utilizadas

sample <- dados %>%
  group_by(categoria) %>%
  sample_n(1000) %>%  # Escolhendo 1000 observações de cada
  select(-c(10:18)) %>% 
  na.omit()

head(sample)
## # A tibble: 6 x 9
## # Groups:   categoria [1]
##   categoria duracao nmoda volume inercia  moda media  pico mediana
##   <fct>       <dbl> <int>  <dbl>   <dbl> <dbl> <dbl> <dbl>   <dbl>
## 1 Bacia          40     3  0.700   3      1.20  1.05  1.20    1.20
## 2 Bacia         110    10  5.30   10      3     2.89  3       3   
## 3 Bacia         160    12  4.40    4.33   1.80  1.65  2.40    1.80
## 4 Bacia          60     3  7.80    2      8.60  7.80  9.20    8.60
## 5 Bacia         120     7  6.10    1.4    3.60  3.05  3.60    3.60
## 6 Bacia         140     5  9.90    0.556  4.80  4.24  4.80    4.20

Criando o grupo de treino e de teste:

# Definindo Split

split=0.80

trainIndex <- createDataPartition(sample$categoria, p=split, list=FALSE)

# Separando 

data_train <- sample[ trainIndex,]

data_test <- sample[-trainIndex,]

Rodando novamente o modelo :

Repetidos K-Folds:

model1 <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method="repeatedcv", number=10, repeats=10))
model1
## k-Nearest Neighbors 
## 
## 2400 samples
##    8 predictor
##    3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 2160, 2160, 2160, 2160, 2160, 2160, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa    
##    5  0.6557917  0.4836875
##    7  0.6593750  0.4890625
##    9  0.6557083  0.4835625
##   11  0.6558750  0.4838125
##   13  0.6579583  0.4869375
##   15  0.6621667  0.4932500
##   17  0.6622500  0.4933750
##   19  0.6649583  0.4974375
##   21  0.6624583  0.4936875
##   23  0.6615417  0.4923125
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 19.
# Testando os resultados obtidos


# Predição

predictions <- predict(model1, data_test)

# Resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia              151               18       82
##   Torneira Interna    11              148        7
##   Chuveiro            38               34      111
## 
## Overall Statistics
##                                           
##                Accuracy : 0.6833          
##                  95% CI : (0.6444, 0.7204)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.525           
##  Mcnemar's Test P-Value : 9.083e-08       
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.7550                  0.7400          0.5550
## Specificity                0.7500                  0.9550          0.8200
## Pos Pred Value             0.6016                  0.8916          0.6066
## Neg Pred Value             0.8596                  0.8802          0.7866
## Prevalence                 0.3333                  0.3333          0.3333
## Detection Rate             0.2517                  0.2467          0.1850
## Detection Prevalence       0.4183                  0.2767          0.3050
## Balanced Accuracy          0.7525                  0.8475          0.6875
# Testando o tempo de processamento 

profvis({model1 <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method="repeatedcv", number=10, repeats=10))})
#### Leave one Out: 

model2 <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method="repeatedcv", number=10, repeats=10))

model2
## k-Nearest Neighbors 
## 
## 2400 samples
##    8 predictor
##    3 classes: 'Bacia', 'Torneira Interna', 'Chuveiro' 
## 
## Pre-processing: centered (8), scaled (8) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 2160, 2160, 2160, 2160, 2160, 2160, ... 
## Resampling results across tuning parameters:
## 
##   k   Accuracy   Kappa    
##    5  0.6540833  0.4811250
##    7  0.6582500  0.4873750
##    9  0.6546250  0.4819375
##   11  0.6580417  0.4870625
##   13  0.6568333  0.4852500
##   15  0.6616667  0.4925000
##   17  0.6618333  0.4927500
##   19  0.6630833  0.4946250
##   21  0.6637500  0.4956250
##   23  0.6626250  0.4939375
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was k = 21.
# Testando os resultados obtidos

# Predição

predictions <- predict(model2, data_test)

# Resultados

confusionMatrix(predictions, data_test$categoria) 
## Confusion Matrix and Statistics
## 
##                   Reference
## Prediction         Bacia Torneira Interna Chuveiro
##   Bacia              152               20       80
##   Torneira Interna    11              146        9
##   Chuveiro            37               34      111
## 
## Overall Statistics
##                                           
##                Accuracy : 0.6817          
##                  95% CI : (0.6427, 0.7188)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.5225          
##  Mcnemar's Test P-Value : 3.298e-07       
## 
## Statistics by Class:
## 
##                      Class: Bacia Class: Torneira Interna Class: Chuveiro
## Sensitivity                0.7600                  0.7300          0.5550
## Specificity                0.7500                  0.9500          0.8225
## Pos Pred Value             0.6032                  0.8795          0.6099
## Neg Pred Value             0.8621                  0.8756          0.7871
## Prevalence                 0.3333                  0.3333          0.3333
## Detection Rate             0.2533                  0.2433          0.1850
## Detection Prevalence       0.4200                  0.2767          0.3033
## Balanced Accuracy          0.7550                  0.8400          0.6887
profvis({model2 <- train(categoria ~ ., 
               data = data_train,
               method = "knn",
               preProcess = c("center", "scale"),
               tuneLength = 10, 
               trControl = trainControl(method="repeatedcv", number=10, repeats=10))})

Interessante observar que ambos métodos levam a resultados semelhantes em tempo semelhantes.