Librerías y Dependencias

#install.packages("ggplot2") # Gráficas
library(ggplot2)

#install.packages("lattice") # Crear gráficos
library(lattice)

#install.packages("caret") # Algoritmos de aprendizaje automático
library(caret)

#install.packages("DataExplorer") # Análisis Exploratorio
library(DataExplorer)

#install.packages("randomForest") # Necesario para el método "rf"
library(randomForest)

#install.packages("nnet") # Necesario para redes neuronales
library(nnet)

Carga de la Base de Datos

# Cargar la base de datos
df <- read.csv("C:/Users/joseo/Downloads/M1_data.csv")

# Visualizamos las primeras filas
head(df)
##   trust_apple interest_computers age_computer user_pcmac appleproducts_count
## 1          No                  4            8         PC                   0
## 2         Yes                  2            4         PC                   1
## 3         Yes                  5            6         PC                   0
## 4         Yes                  2            6      Apple                   4
## 5         Yes                  4            4      Apple                   7
## 6         Yes                  3            1      Apple                   2
##   familiarity_m1 f_batterylife f_price f_size f_multitasking f_noise
## 1             No             5       4      3              4       4
## 2             No             5       5      5              3       4
## 3             No             3       4      2              4       1
## 4             No             4       3      3              4       4
## 5            Yes             5       3      3              4       4
## 6             No             5       5      4              4       5
##   f_performance f_neural f_synergy f_performanceloss m1_consideration
## 1             2        2         1                 1                1
## 2             5        2         2                 4                2
## 3             4        2         2                 2                4
## 4             4        4         4                 3                2
## 5             5        3         4                 4                4
## 6             5        5         4                 2                2
##   m1_purchase gender age_group income_group   status          domain
## 1         Yes   Male         2            2  Student         Science
## 2          No   Male         2            3 Employed         Finance
## 3         Yes   Male         2            2  Student IT & Technology
## 4          No Female         2            2  Student  Arts & Culture
## 5         Yes   Male         5            7 Employed     Hospitality
## 6          No Female         2            2  Student        Politics

Preparación y Formato de Variables

# Convertimos variables categóricas a factor

df$m1_purchase <- as.factor(df$m1_purchase)
df$trust_apple <- as.factor(df$trust_apple)
df$user_pcmac <- as.factor(df$user_pcmac)
df$familiarity_m1 <- as.factor(df$familiarity_m1)
df$gender <- as.factor(df$gender)
df$status <- as.factor(df$status)
df$domain <- as.factor(df$domain)

# Verificamos estructura
str(df)
## 'data.frame':    133 obs. of  22 variables:
##  $ trust_apple        : Factor w/ 2 levels "No","Yes": 1 2 2 2 2 2 2 1 2 2 ...
##  $ interest_computers : int  4 2 5 2 4 3 3 3 4 5 ...
##  $ age_computer       : int  8 4 6 6 4 1 2 0 2 0 ...
##  $ user_pcmac         : Factor w/ 4 levels "Apple","Hp","Other",..: 4 4 4 1 1 1 1 4 1 1 ...
##  $ appleproducts_count: int  0 1 0 4 7 2 7 0 6 7 ...
##  $ familiarity_m1     : Factor w/ 2 levels "No","Yes": 1 1 1 1 2 1 1 1 2 2 ...
##  $ f_batterylife      : int  5 5 3 4 5 5 4 5 4 5 ...
##  $ f_price            : int  4 5 4 3 3 5 3 5 4 3 ...
##  $ f_size             : int  3 5 2 3 3 4 4 4 3 5 ...
##  $ f_multitasking     : int  4 3 4 4 4 4 5 4 4 5 ...
##  $ f_noise            : int  4 4 1 4 4 5 5 3 4 5 ...
##  $ f_performance      : int  2 5 4 4 5 5 5 3 4 5 ...
##  $ f_neural           : int  2 2 2 4 3 5 3 2 3 3 ...
##  $ f_synergy          : int  1 2 2 4 4 4 3 2 3 5 ...
##  $ f_performanceloss  : int  1 4 2 3 4 2 2 3 4 5 ...
##  $ m1_consideration   : int  1 2 4 2 4 2 3 1 5 5 ...
##  $ m1_purchase        : Factor w/ 2 levels "No","Yes": 2 1 2 1 2 1 2 1 2 2 ...
##  $ gender             : Factor w/ 2 levels "Female","Male": 2 2 2 1 2 1 2 2 2 2 ...
##  $ age_group          : int  2 2 2 2 5 2 6 2 8 4 ...
##  $ income_group       : int  2 3 2 2 7 2 7 2 7 6 ...
##  $ status             : Factor w/ 6 levels "Employed","Retired",..: 4 1 4 4 1 4 1 4 1 1 ...
##  $ domain             : Factor w/ 22 levels "Administration & Public Services",..: 21 10 13 3 12 17 13 22 13 12 ...

Entender la Base de Datos

summary(df)
##  trust_apple interest_computers  age_computer   user_pcmac appleproducts_count
##  No : 19     Min.   :2.000      Min.   :0.000   Apple:86   Min.   :0.000      
##  Yes:114     1st Qu.:3.000      1st Qu.:1.000   Hp   : 1   1st Qu.:1.000      
##              Median :4.000      Median :3.000   Other: 1   Median :3.000      
##              Mean   :3.812      Mean   :2.827   PC   :45   Mean   :2.609      
##              3rd Qu.:5.000      3rd Qu.:5.000              3rd Qu.:4.000      
##              Max.   :5.000      Max.   :9.000              Max.   :8.000      
##                                                                               
##  familiarity_m1 f_batterylife      f_price          f_size      f_multitasking
##  No :75         Min.   :1.000   Min.   :1.000   Min.   :1.000   Min.   :2.00  
##  Yes:58         1st Qu.:4.000   1st Qu.:3.000   1st Qu.:2.000   1st Qu.:4.00  
##                 Median :5.000   Median :4.000   Median :3.000   Median :4.00  
##                 Mean   :4.526   Mean   :3.872   Mean   :3.158   Mean   :4.12  
##                 3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:4.000   3rd Qu.:5.00  
##                 Max.   :5.000   Max.   :5.000   Max.   :5.000   Max.   :5.00  
##                                                                               
##     f_noise      f_performance      f_neural       f_synergy    
##  Min.   :1.000   Min.   :2.000   Min.   :1.000   Min.   :1.000  
##  1st Qu.:3.000   1st Qu.:4.000   1st Qu.:2.000   1st Qu.:3.000  
##  Median :4.000   Median :5.000   Median :3.000   Median :4.000  
##  Mean   :3.729   Mean   :4.398   Mean   :3.165   Mean   :3.466  
##  3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:4.000   3rd Qu.:4.000  
##  Max.   :5.000   Max.   :5.000   Max.   :5.000   Max.   :5.000  
##                                                                 
##  f_performanceloss m1_consideration m1_purchase    gender     age_group    
##  Min.   :1.000     Min.   :1.000    No :45      Female:61   Min.   : 1.00  
##  1st Qu.:3.000     1st Qu.:3.000    Yes:88      Male  :72   1st Qu.: 2.00  
##  Median :4.000     Median :4.000                            Median : 2.00  
##  Mean   :3.376     Mean   :3.609                            Mean   : 2.97  
##  3rd Qu.:4.000     3rd Qu.:5.000                            3rd Qu.: 3.00  
##  Max.   :5.000     Max.   :5.000                            Max.   :10.00  
##                                                                            
##   income_group                   status               domain  
##  Min.   :1.00   Employed            :41   IT & Technology:33  
##  1st Qu.:1.00   Retired             : 1   Marketing      :21  
##  Median :2.00   Self-Employed       : 5   Business       :14  
##  Mean   :2.97   Student             :84   Engineering    : 7  
##  3rd Qu.:4.00   Student ant employed: 1   Finance        : 7  
##  Max.   :7.00   Unemployed          : 1   Science        : 7  
##                                           (Other)        :44
str(df)
## 'data.frame':    133 obs. of  22 variables:
##  $ trust_apple        : Factor w/ 2 levels "No","Yes": 1 2 2 2 2 2 2 1 2 2 ...
##  $ interest_computers : int  4 2 5 2 4 3 3 3 4 5 ...
##  $ age_computer       : int  8 4 6 6 4 1 2 0 2 0 ...
##  $ user_pcmac         : Factor w/ 4 levels "Apple","Hp","Other",..: 4 4 4 1 1 1 1 4 1 1 ...
##  $ appleproducts_count: int  0 1 0 4 7 2 7 0 6 7 ...
##  $ familiarity_m1     : Factor w/ 2 levels "No","Yes": 1 1 1 1 2 1 1 1 2 2 ...
##  $ f_batterylife      : int  5 5 3 4 5 5 4 5 4 5 ...
##  $ f_price            : int  4 5 4 3 3 5 3 5 4 3 ...
##  $ f_size             : int  3 5 2 3 3 4 4 4 3 5 ...
##  $ f_multitasking     : int  4 3 4 4 4 4 5 4 4 5 ...
##  $ f_noise            : int  4 4 1 4 4 5 5 3 4 5 ...
##  $ f_performance      : int  2 5 4 4 5 5 5 3 4 5 ...
##  $ f_neural           : int  2 2 2 4 3 5 3 2 3 3 ...
##  $ f_synergy          : int  1 2 2 4 4 4 3 2 3 5 ...
##  $ f_performanceloss  : int  1 4 2 3 4 2 2 3 4 5 ...
##  $ m1_consideration   : int  1 2 4 2 4 2 3 1 5 5 ...
##  $ m1_purchase        : Factor w/ 2 levels "No","Yes": 2 1 2 1 2 1 2 1 2 2 ...
##  $ gender             : Factor w/ 2 levels "Female","Male": 2 2 2 1 2 1 2 2 2 2 ...
##  $ age_group          : int  2 2 2 2 5 2 6 2 8 4 ...
##  $ income_group       : int  2 3 2 2 7 2 7 2 7 6 ...
##  $ status             : Factor w/ 6 levels "Employed","Retired",..: 4 1 4 4 1 4 1 4 1 1 ...
##  $ domain             : Factor w/ 22 levels "Administration & Public Services",..: 21 10 13 3 12 17 13 22 13 12 ...
# Visualización de valores faltantes
plot_missing(df)

# Distribución de variables numéricas
plot_histogram(df)

# Correlación entre variables numéricas
plot_correlation(df)

Partir la Base de Datos

# Normalmente 80-20
set.seed(123)
renglones_entrenamiento <- createDataPartition(df$m1_purchase, p=0.8, list=FALSE)

entrenamiento <- df[renglones_entrenamiento, ]
prueba <- df[-renglones_entrenamiento, ]

# Verificamos el tamaño de cada set
dim(entrenamiento)
## [1] 107  22
dim(prueba)
## [1] 26 22
# Verificamos proporción de clases (Yes/No) en cada set
table(entrenamiento$m1_purchase)
## 
##  No Yes 
##  36  71
table(prueba$m1_purchase)
## 
##  No Yes 
##   9  17
prop.table(table(entrenamiento$m1_purchase))
## 
##        No       Yes 
## 0.3364486 0.6635514
prop.table(table(prueba$m1_purchase))
## 
##        No       Yes 
## 0.3461538 0.6538462

Modelo 1. SVM Lineal

modelo1 <- train(m1_purchase ~ ., data=entrenamiento,
                 method = "svmLinear",
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method="cv", number=10),
                 tuneGrid = data.frame(C=1)
                 )

resultado_entrenamiento1 <- predict(modelo1, entrenamiento)
resultado_prueba1 <- predict(modelo1, prueba)

# Matriz de Confusión del Resultado del Entrenamiento
mcre1 <- confusionMatrix(resultado_entrenamiento1, entrenamiento$m1_purchase)
mcre1
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No  30   4
##        Yes  6  67
##                                           
##                Accuracy : 0.9065          
##                  95% CI : (0.8348, 0.9543)
##     No Information Rate : 0.6636          
##     P-Value [Acc > NIR] : 4.281e-09       
##                                           
##                   Kappa : 0.7878          
##                                           
##  Mcnemar's Test P-Value : 0.7518          
##                                           
##             Sensitivity : 0.8333          
##             Specificity : 0.9437          
##          Pos Pred Value : 0.8824          
##          Neg Pred Value : 0.9178          
##              Prevalence : 0.3364          
##          Detection Rate : 0.2804          
##    Detection Prevalence : 0.3178          
##       Balanced Accuracy : 0.8885          
##                                           
##        'Positive' Class : No              
## 
# Matriz de Confusión del Resultado de la Prueba
mcrp1 <- confusionMatrix(resultado_prueba1, prueba$m1_purchase)
mcrp1
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No   3   6
##        Yes  6  11
##                                           
##                Accuracy : 0.5385          
##                  95% CI : (0.3337, 0.7341)
##     No Information Rate : 0.6538          
##     P-Value [Acc > NIR] : 0.9231          
##                                           
##                   Kappa : -0.0196         
##                                           
##  Mcnemar's Test P-Value : 1.0000          
##                                           
##             Sensitivity : 0.3333          
##             Specificity : 0.6471          
##          Pos Pred Value : 0.3333          
##          Neg Pred Value : 0.6471          
##              Prevalence : 0.3462          
##          Detection Rate : 0.1154          
##    Detection Prevalence : 0.3462          
##       Balanced Accuracy : 0.4902          
##                                           
##        'Positive' Class : No              
## 

Modelo 2. SVM Radial

modelo2 <- train(m1_purchase ~ ., data=entrenamiento,
                 method = "svmRadial",
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method="cv", number=10),
                 tuneGrid = data.frame(sigma=0.1, C=1)
                 )

resultado_entrenamiento2 <- predict(modelo2, entrenamiento)
resultado_prueba2 <- predict(modelo2, prueba)

# Matriz de Confusión del Resultado del Entrenamiento
mcre2 <- confusionMatrix(resultado_entrenamiento2, entrenamiento$m1_purchase)
mcre2
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No  34   0
##        Yes  2  71
##                                           
##                Accuracy : 0.9813          
##                  95% CI : (0.9341, 0.9977)
##     No Information Rate : 0.6636          
##     P-Value [Acc > NIR] : <2e-16          
##                                           
##                   Kappa : 0.9576          
##                                           
##  Mcnemar's Test P-Value : 0.4795          
##                                           
##             Sensitivity : 0.9444          
##             Specificity : 1.0000          
##          Pos Pred Value : 1.0000          
##          Neg Pred Value : 0.9726          
##              Prevalence : 0.3364          
##          Detection Rate : 0.3178          
##    Detection Prevalence : 0.3178          
##       Balanced Accuracy : 0.9722          
##                                           
##        'Positive' Class : No              
## 
# Matriz de Confusión del Resultado de la Prueba
mcrp2 <- confusionMatrix(resultado_prueba2, prueba$m1_purchase)
mcrp2
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No   0   0
##        Yes  9  17
##                                           
##                Accuracy : 0.6538          
##                  95% CI : (0.4433, 0.8279)
##     No Information Rate : 0.6538          
##     P-Value [Acc > NIR] : 0.589398        
##                                           
##                   Kappa : 0               
##                                           
##  Mcnemar's Test P-Value : 0.007661        
##                                           
##             Sensitivity : 0.0000          
##             Specificity : 1.0000          
##          Pos Pred Value :    NaN          
##          Neg Pred Value : 0.6538          
##              Prevalence : 0.3462          
##          Detection Rate : 0.0000          
##    Detection Prevalence : 0.0000          
##       Balanced Accuracy : 0.5000          
##                                           
##        'Positive' Class : No              
## 

Modelo 3. SVM Polinómico (degree = 2)

modelo3 <- train(m1_purchase ~ ., data=entrenamiento,
                 method = "svmPoly",
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method="cv", number=10),
                 tuneGrid = data.frame(degree=2, scale=1, C=1)
                 )

resultado_entrenamiento3 <- predict(modelo3, entrenamiento)
resultado_prueba3 <- predict(modelo3, prueba)

# Matriz de Confusión del Resultado del Entrenamiento
mcre3 <- confusionMatrix(resultado_entrenamiento3, entrenamiento$m1_purchase)
mcre3
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No  34   0
##        Yes  2  71
##                                           
##                Accuracy : 0.9813          
##                  95% CI : (0.9341, 0.9977)
##     No Information Rate : 0.6636          
##     P-Value [Acc > NIR] : <2e-16          
##                                           
##                   Kappa : 0.9576          
##                                           
##  Mcnemar's Test P-Value : 0.4795          
##                                           
##             Sensitivity : 0.9444          
##             Specificity : 1.0000          
##          Pos Pred Value : 1.0000          
##          Neg Pred Value : 0.9726          
##              Prevalence : 0.3364          
##          Detection Rate : 0.3178          
##    Detection Prevalence : 0.3178          
##       Balanced Accuracy : 0.9722          
##                                           
##        'Positive' Class : No              
## 
# Matriz de Confusión del Resultado de la Prueba
mcrp3 <- confusionMatrix(resultado_prueba3, prueba$m1_purchase)
mcrp3
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No   1   4
##        Yes  8  13
##                                           
##                Accuracy : 0.5385          
##                  95% CI : (0.3337, 0.7341)
##     No Information Rate : 0.6538          
##     P-Value [Acc > NIR] : 0.9231          
##                                           
##                   Kappa : -0.1387         
##                                           
##  Mcnemar's Test P-Value : 0.3865          
##                                           
##             Sensitivity : 0.11111         
##             Specificity : 0.76471         
##          Pos Pred Value : 0.20000         
##          Neg Pred Value : 0.61905         
##              Prevalence : 0.34615         
##          Detection Rate : 0.03846         
##    Detection Prevalence : 0.19231         
##       Balanced Accuracy : 0.43791         
##                                           
##        'Positive' Class : No              
## 
#Se probó svmPoly con degree=2 para que fuera realmente no lineal, aumentar el grado probablemente incrementaría sobreajuste sin mejorar prueba dada la muestra pequeña

Modelo 4. Árbol de Decisión

modelo4 <- train(m1_purchase ~ ., data=entrenamiento,
                 method = "rpart",
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method="cv", number=10),
                 tuneLength = 10
                 )

resultado_entrenamiento4 <- predict(modelo4, entrenamiento)
resultado_prueba4 <- predict(modelo4, prueba)

# Matriz de Confusión del Resultado del Entrenamiento
mcre4 <- confusionMatrix(resultado_entrenamiento4, entrenamiento$m1_purchase)
mcre4
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No  17   2
##        Yes 19  69
##                                           
##                Accuracy : 0.8037          
##                  95% CI : (0.7158, 0.8742)
##     No Information Rate : 0.6636          
##     P-Value [Acc > NIR] : 0.0010139       
##                                           
##                   Kappa : 0.5025          
##                                           
##  Mcnemar's Test P-Value : 0.0004803       
##                                           
##             Sensitivity : 0.4722          
##             Specificity : 0.9718          
##          Pos Pred Value : 0.8947          
##          Neg Pred Value : 0.7841          
##              Prevalence : 0.3364          
##          Detection Rate : 0.1589          
##    Detection Prevalence : 0.1776          
##       Balanced Accuracy : 0.7220          
##                                           
##        'Positive' Class : No              
## 
# Matriz de Confusión del Resultado de la Prueba
mcrp4 <- confusionMatrix(resultado_prueba4, prueba$m1_purchase)
mcrp4
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No   4   6
##        Yes  5  11
##                                           
##                Accuracy : 0.5769          
##                  95% CI : (0.3692, 0.7665)
##     No Information Rate : 0.6538          
##     P-Value [Acc > NIR] : 0.8485          
##                                           
##                   Kappa : 0.0892          
##                                           
##  Mcnemar's Test P-Value : 1.0000          
##                                           
##             Sensitivity : 0.4444          
##             Specificity : 0.6471          
##          Pos Pred Value : 0.4000          
##          Neg Pred Value : 0.6875          
##              Prevalence : 0.3462          
##          Detection Rate : 0.1538          
##    Detection Prevalence : 0.3846          
##       Balanced Accuracy : 0.5458          
##                                           
##        'Positive' Class : No              
## 

Modelo 5. Redes Neuronales

modelo5 <- train(m1_purchase ~ ., data=entrenamiento,
                 method = "nnet",
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method="cv", number=10),
                 trace = FALSE
                 )

resultado_entrenamiento5 <- predict(modelo5, entrenamiento)
resultado_prueba5 <- predict(modelo5, prueba)

# Matriz de Confusión del Resultado del Entrenamiento
mcre5 <- confusionMatrix(resultado_entrenamiento5, entrenamiento$m1_purchase)
mcre5
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No  32   2
##        Yes  4  69
##                                           
##                Accuracy : 0.9439          
##                  95% CI : (0.8819, 0.9791)
##     No Information Rate : 0.6636          
##     P-Value [Acc > NIR] : 3.021e-12       
##                                           
##                   Kappa : 0.8727          
##                                           
##  Mcnemar's Test P-Value : 0.6831          
##                                           
##             Sensitivity : 0.8889          
##             Specificity : 0.9718          
##          Pos Pred Value : 0.9412          
##          Neg Pred Value : 0.9452          
##              Prevalence : 0.3364          
##          Detection Rate : 0.2991          
##    Detection Prevalence : 0.3178          
##       Balanced Accuracy : 0.9304          
##                                           
##        'Positive' Class : No              
## 
# Matriz de Confusión del Resultado de la Prueba
mcrp5 <- confusionMatrix(resultado_prueba5, prueba$m1_purchase)
mcrp5
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No   4   6
##        Yes  5  11
##                                           
##                Accuracy : 0.5769          
##                  95% CI : (0.3692, 0.7665)
##     No Information Rate : 0.6538          
##     P-Value [Acc > NIR] : 0.8485          
##                                           
##                   Kappa : 0.0892          
##                                           
##  Mcnemar's Test P-Value : 1.0000          
##                                           
##             Sensitivity : 0.4444          
##             Specificity : 0.6471          
##          Pos Pred Value : 0.4000          
##          Neg Pred Value : 0.6875          
##              Prevalence : 0.3462          
##          Detection Rate : 0.1538          
##    Detection Prevalence : 0.3846          
##       Balanced Accuracy : 0.5458          
##                                           
##        'Positive' Class : No              
## 

Modelo 6. Random Forest

modelo6 <- train(m1_purchase ~ ., data=entrenamiento,
                 method = "rf",
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method="cv", number=10),
                 tuneGrid = expand.grid(mtry = c(2,4,6))
                 )

resultado_entrenamiento6 <- predict(modelo6, entrenamiento)
resultado_prueba6 <- predict(modelo6, prueba)

# Matriz de Confusión del Resultado del Entrenamiento
mcre6 <- confusionMatrix(resultado_entrenamiento6, entrenamiento$m1_purchase)
mcre6
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No  34   0
##        Yes  2  71
##                                           
##                Accuracy : 0.9813          
##                  95% CI : (0.9341, 0.9977)
##     No Information Rate : 0.6636          
##     P-Value [Acc > NIR] : <2e-16          
##                                           
##                   Kappa : 0.9576          
##                                           
##  Mcnemar's Test P-Value : 0.4795          
##                                           
##             Sensitivity : 0.9444          
##             Specificity : 1.0000          
##          Pos Pred Value : 1.0000          
##          Neg Pred Value : 0.9726          
##              Prevalence : 0.3364          
##          Detection Rate : 0.3178          
##    Detection Prevalence : 0.3178          
##       Balanced Accuracy : 0.9722          
##                                           
##        'Positive' Class : No              
## 
# Matriz de Confusión del Resultado de la Prueba
mcrp6 <- confusionMatrix(resultado_prueba6, prueba$m1_purchase)
mcrp6
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction No Yes
##        No   4   3
##        Yes  5  14
##                                           
##                Accuracy : 0.6923          
##                  95% CI : (0.4821, 0.8567)
##     No Information Rate : 0.6538          
##     P-Value [Acc > NIR] : 0.4267          
##                                           
##                   Kappa : 0.2828          
##                                           
##  Mcnemar's Test P-Value : 0.7237          
##                                           
##             Sensitivity : 0.4444          
##             Specificity : 0.8235          
##          Pos Pred Value : 0.5714          
##          Neg Pred Value : 0.7368          
##              Prevalence : 0.3462          
##          Detection Rate : 0.1538          
##    Detection Prevalence : 0.2692          
##       Balanced Accuracy : 0.6340          
##                                           
##        'Positive' Class : No              
## 

Tabla de Resultados

resultados <- data.frame(
  "svmLinear" = c(mcre1$overall["Accuracy"], mcrp1$overall["Accuracy"]),
  "svmRadial" = c(mcre2$overall["Accuracy"], mcrp2$overall["Accuracy"]),
  "svmPoly"   = c(mcre3$overall["Accuracy"], mcrp3$overall["Accuracy"]),
  "rpart"     = c(mcre4$overall["Accuracy"], mcrp4$overall["Accuracy"]),
  "nnet"      = c(mcre5$overall["Accuracy"], mcrp5$overall["Accuracy"]),
  "rf"        = c(mcre6$overall["Accuracy"], mcrp6$overall["Accuracy"])
)

rownames(resultados) <- c("Precisión de entrenamiento", "Precisión de prueba")
resultados
##                            svmLinear svmRadial   svmPoly     rpart      nnet
## Precisión de entrenamiento 0.9065421 0.9813084 0.9813084 0.8037383 0.9439252
## Precisión de prueba        0.5384615 0.6538462 0.5384615 0.5769231 0.5769231
##                                   rf
## Precisión de entrenamiento 0.9813084
## Precisión de prueba        0.6923077

Conclusiones

Con base en los resultados obtenidos, la mayoría de los modelos complejos (SVM radial, polinómico y redes neuronales) presentaron un sobreajuste importante, alcanzando precisiones cercanas al 98% en entrenamiento pero disminuyendo considerablemente en los datos de prueba. Esto indica que, aunque logran aprender muy bien el patrón interno del conjunto de entrenamiento, no generalizan adecuadamente a nuevos datos, probablemente debido al tamaño reducido de la muestra y al alto número de variables categóricas con múltiples niveles.

El modelo que mostró el mejor equilibrio entre desempeño y capacidad de generalización fue Random Forest, ya que obtuvo la mayor precisión en prueba (65%) sin colapsar completamente a la clase mayoritaria, además de presentar un mejor Kappa y Balanced Accuracy en comparación con los demás modelos. Por lo tanto, dentro de los métodos evaluados y bajo el mismo nivel de configuración aplicado en clase, Random Forest representa la opción más sólida para este conjunto de datos.

LS0tDQp0aXRsZTogIk1vZHVsbyAxIg0KYXV0aG9yOiAiSm9zZSBNaWd1ZWwgT3J0aXogLSBBMDE1NjkxMTAiDQpkYXRlOiAiMjAyNi0wMy0wMSINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIHRoZW1lOiBmbGF0bHkNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgZWNobyA9IFRSVUUsDQogIHdhcm5pbmcgPSBGQUxTRSwNCiAgbWVzc2FnZSA9IEZBTFNFDQopDQpgYGANCg0KIVtdKGh0dHBzOi8vbWVkaWE0LmdpcGh5LmNvbS9tZWRpYS92MS5ZMmxrUFRjNU1HSTNOakV4WkROMVlucG9kMnRuWlhwdWNtSjJhWGc1TVRFeGNuTnBZbTlyTUdGemNXY3lNelpsTlRReU9TWmxjRDEyTVY5cGJuUmxjbTVoYkY5bmFXWmZZbmxmYVdRbVkzUTlady81WmVzdTVWUE5HSmxtL2dpcGh5LmdpZikNCg0KDQojIFsgTGlicmVyw61hcyB5IERlcGVuZGVuY2lhcyBde3N0eWxlPSJjb2xvcjogIzVBNUE1QSJ9DQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoImdncGxvdDIiKSAjIEdyw6FmaWNhcw0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojaW5zdGFsbC5wYWNrYWdlcygibGF0dGljZSIpICMgQ3JlYXIgZ3LDoWZpY29zDQpsaWJyYXJ5KGxhdHRpY2UpDQoNCiNpbnN0YWxsLnBhY2thZ2VzKCJjYXJldCIpICMgQWxnb3JpdG1vcyBkZSBhcHJlbmRpemFqZSBhdXRvbcOhdGljbw0KbGlicmFyeShjYXJldCkNCg0KI2luc3RhbGwucGFja2FnZXMoIkRhdGFFeHBsb3JlciIpICMgQW7DoWxpc2lzIEV4cGxvcmF0b3Jpbw0KbGlicmFyeShEYXRhRXhwbG9yZXIpDQoNCiNpbnN0YWxsLnBhY2thZ2VzKCJyYW5kb21Gb3Jlc3QiKSAjIE5lY2VzYXJpbyBwYXJhIGVsIG3DqXRvZG8gInJmIg0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQoNCiNpbnN0YWxsLnBhY2thZ2VzKCJubmV0IikgIyBOZWNlc2FyaW8gcGFyYSByZWRlcyBuZXVyb25hbGVzDQpsaWJyYXJ5KG5uZXQpDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6ICM1QTVBNUEiPiBDYXJnYSBkZSBsYSBCYXNlIGRlIERhdG9zIDwvc3Bhbj4NCg0KYGBge3J9DQojIENhcmdhciBsYSBiYXNlIGRlIGRhdG9zDQpkZiA8LSByZWFkLmNzdigiQzovVXNlcnMvam9zZW8vRG93bmxvYWRzL00xX2RhdGEuY3N2IikNCg0KIyBWaXN1YWxpemFtb3MgbGFzIHByaW1lcmFzIGZpbGFzDQpoZWFkKGRmKQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiAjNUE1QTVBIj4gUHJlcGFyYWNpw7NuIHkgRm9ybWF0byBkZSBWYXJpYWJsZXMgPC9zcGFuPg0KYGBge3J9DQojIENvbnZlcnRpbW9zIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXMgYSBmYWN0b3INCg0KZGYkbTFfcHVyY2hhc2UgPC0gYXMuZmFjdG9yKGRmJG0xX3B1cmNoYXNlKQ0KZGYkdHJ1c3RfYXBwbGUgPC0gYXMuZmFjdG9yKGRmJHRydXN0X2FwcGxlKQ0KZGYkdXNlcl9wY21hYyA8LSBhcy5mYWN0b3IoZGYkdXNlcl9wY21hYykNCmRmJGZhbWlsaWFyaXR5X20xIDwtIGFzLmZhY3RvcihkZiRmYW1pbGlhcml0eV9tMSkNCmRmJGdlbmRlciA8LSBhcy5mYWN0b3IoZGYkZ2VuZGVyKQ0KZGYkc3RhdHVzIDwtIGFzLmZhY3RvcihkZiRzdGF0dXMpDQpkZiRkb21haW4gPC0gYXMuZmFjdG9yKGRmJGRvbWFpbikNCg0KIyBWZXJpZmljYW1vcyBlc3RydWN0dXJhDQpzdHIoZGYpDQpgYGANCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiAjNUE1QTVBIj4gRW50ZW5kZXIgbGEgQmFzZSBkZSBEYXRvcyA8L3NwYW4+DQpgYGB7cn0NCnN1bW1hcnkoZGYpDQpzdHIoZGYpDQoNCiMgVmlzdWFsaXphY2nDs24gZGUgdmFsb3JlcyBmYWx0YW50ZXMNCnBsb3RfbWlzc2luZyhkZikNCg0KIyBEaXN0cmlidWNpw7NuIGRlIHZhcmlhYmxlcyBudW3DqXJpY2FzDQpwbG90X2hpc3RvZ3JhbShkZikNCg0KIyBDb3JyZWxhY2nDs24gZW50cmUgdmFyaWFibGVzIG51bcOpcmljYXMNCnBsb3RfY29ycmVsYXRpb24oZGYpDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6ICM1QTVBNUEiPiBQYXJ0aXIgbGEgQmFzZSBkZSBEYXRvcyA8L3NwYW4+DQpgYGB7cn0NCiMgTm9ybWFsbWVudGUgODAtMjANCnNldC5zZWVkKDEyMykNCnJlbmdsb25lc19lbnRyZW5hbWllbnRvIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZGYkbTFfcHVyY2hhc2UsIHA9MC44LCBsaXN0PUZBTFNFKQ0KDQplbnRyZW5hbWllbnRvIDwtIGRmW3Jlbmdsb25lc19lbnRyZW5hbWllbnRvLCBdDQpwcnVlYmEgPC0gZGZbLXJlbmdsb25lc19lbnRyZW5hbWllbnRvLCBdDQoNCiMgVmVyaWZpY2Ftb3MgZWwgdGFtYcOxbyBkZSBjYWRhIHNldA0KZGltKGVudHJlbmFtaWVudG8pDQpkaW0ocHJ1ZWJhKQ0KDQojIFZlcmlmaWNhbW9zIHByb3BvcmNpw7NuIGRlIGNsYXNlcyAoWWVzL05vKSBlbiBjYWRhIHNldA0KdGFibGUoZW50cmVuYW1pZW50byRtMV9wdXJjaGFzZSkNCnRhYmxlKHBydWViYSRtMV9wdXJjaGFzZSkNCnByb3AudGFibGUodGFibGUoZW50cmVuYW1pZW50byRtMV9wdXJjaGFzZSkpDQpwcm9wLnRhYmxlKHRhYmxlKHBydWViYSRtMV9wdXJjaGFzZSkpDQpgYGANCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiAjNUE1QTVBIj4gTW9kZWxvIDEuIFNWTSBMaW5lYWwgPC9zcGFuPg0KYGBge3J9DQptb2RlbG8xIDwtIHRyYWluKG0xX3B1cmNoYXNlIH4gLiwgZGF0YT1lbnRyZW5hbWllbnRvLA0KICAgICAgICAgICAgICAgICBtZXRob2QgPSAic3ZtTGluZWFyIiwNCiAgICAgICAgICAgICAgICAgcHJlUHJvY2VzcyA9IGMoInNjYWxlIiwgImNlbnRlciIpLA0KICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kPSJjdiIsIG51bWJlcj0xMCksDQogICAgICAgICAgICAgICAgIHR1bmVHcmlkID0gZGF0YS5mcmFtZShDPTEpDQogICAgICAgICAgICAgICAgICkNCg0KcmVzdWx0YWRvX2VudHJlbmFtaWVudG8xIDwtIHByZWRpY3QobW9kZWxvMSwgZW50cmVuYW1pZW50bykNCnJlc3VsdGFkb19wcnVlYmExIDwtIHByZWRpY3QobW9kZWxvMSwgcHJ1ZWJhKQ0KDQojIE1hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGVsIEVudHJlbmFtaWVudG8NCm1jcmUxIDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRhZG9fZW50cmVuYW1pZW50bzEsIGVudHJlbmFtaWVudG8kbTFfcHVyY2hhc2UpDQptY3JlMQ0KDQojIE1hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGUgbGEgUHJ1ZWJhDQptY3JwMSA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX3BydWViYTEsIHBydWViYSRtMV9wdXJjaGFzZSkNCm1jcnAxDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6ICM1QTVBNUEiPiBNb2RlbG8gMi4gU1ZNIFJhZGlhbCA8L3NwYW4+DQoNCmBgYHtyfQ0KbW9kZWxvMiA8LSB0cmFpbihtMV9wdXJjaGFzZSB+IC4sIGRhdGE9ZW50cmVuYW1pZW50bywNCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInN2bVJhZGlhbCIsDQogICAgICAgICAgICAgICAgIHByZVByb2Nlc3MgPSBjKCJzY2FsZSIsICJjZW50ZXIiKSwNCiAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZD0iY3YiLCBudW1iZXI9MTApLA0KICAgICAgICAgICAgICAgICB0dW5lR3JpZCA9IGRhdGEuZnJhbWUoc2lnbWE9MC4xLCBDPTEpDQogICAgICAgICAgICAgICAgICkNCg0KcmVzdWx0YWRvX2VudHJlbmFtaWVudG8yIDwtIHByZWRpY3QobW9kZWxvMiwgZW50cmVuYW1pZW50bykNCnJlc3VsdGFkb19wcnVlYmEyIDwtIHByZWRpY3QobW9kZWxvMiwgcHJ1ZWJhKQ0KDQojIE1hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGVsIEVudHJlbmFtaWVudG8NCm1jcmUyIDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRhZG9fZW50cmVuYW1pZW50bzIsIGVudHJlbmFtaWVudG8kbTFfcHVyY2hhc2UpDQptY3JlMg0KDQojIE1hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGUgbGEgUHJ1ZWJhDQptY3JwMiA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX3BydWViYTIsIHBydWViYSRtMV9wdXJjaGFzZSkNCm1jcnAyDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6ICM1QTVBNUEiPiBNb2RlbG8gMy4gU1ZNIFBvbGluw7NtaWNvIChkZWdyZWUgPSAyKSA8L3NwYW4+DQoNCmBgYHtyfQ0KbW9kZWxvMyA8LSB0cmFpbihtMV9wdXJjaGFzZSB+IC4sIGRhdGE9ZW50cmVuYW1pZW50bywNCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInN2bVBvbHkiLA0KICAgICAgICAgICAgICAgICBwcmVQcm9jZXNzID0gYygic2NhbGUiLCAiY2VudGVyIiksDQogICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluQ29udHJvbChtZXRob2Q9ImN2IiwgbnVtYmVyPTEwKSwNCiAgICAgICAgICAgICAgICAgdHVuZUdyaWQgPSBkYXRhLmZyYW1lKGRlZ3JlZT0yLCBzY2FsZT0xLCBDPTEpDQogICAgICAgICAgICAgICAgICkNCg0KcmVzdWx0YWRvX2VudHJlbmFtaWVudG8zIDwtIHByZWRpY3QobW9kZWxvMywgZW50cmVuYW1pZW50bykNCnJlc3VsdGFkb19wcnVlYmEzIDwtIHByZWRpY3QobW9kZWxvMywgcHJ1ZWJhKQ0KDQojIE1hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGVsIEVudHJlbmFtaWVudG8NCm1jcmUzIDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRhZG9fZW50cmVuYW1pZW50bzMsIGVudHJlbmFtaWVudG8kbTFfcHVyY2hhc2UpDQptY3JlMw0KDQojIE1hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGUgbGEgUHJ1ZWJhDQptY3JwMyA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX3BydWViYTMsIHBydWViYSRtMV9wdXJjaGFzZSkNCm1jcnAzDQoNCiNTZSBwcm9iw7Mgc3ZtUG9seSBjb24gZGVncmVlPTIgcGFyYSBxdWUgZnVlcmEgcmVhbG1lbnRlIG5vIGxpbmVhbCwgYXVtZW50YXIgZWwgZ3JhZG8gcHJvYmFibGVtZW50ZSBpbmNyZW1lbnRhcsOtYSBzb2JyZWFqdXN0ZSBzaW4gbWVqb3JhciBwcnVlYmEgZGFkYSBsYSBtdWVzdHJhIHBlcXVlw7FhDQoNCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogIzVBNUE1QSI+IE1vZGVsbyA0LiDDgXJib2wgZGUgRGVjaXNpw7NuIDwvc3Bhbj4NCmBgYHtyfQ0KbW9kZWxvNCA8LSB0cmFpbihtMV9wdXJjaGFzZSB+IC4sIGRhdGE9ZW50cmVuYW1pZW50bywNCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJwYXJ0IiwNCiAgICAgICAgICAgICAgICAgcHJlUHJvY2VzcyA9IGMoInNjYWxlIiwgImNlbnRlciIpLA0KICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kPSJjdiIsIG51bWJlcj0xMCksDQogICAgICAgICAgICAgICAgIHR1bmVMZW5ndGggPSAxMA0KICAgICAgICAgICAgICAgICApDQoNCnJlc3VsdGFkb19lbnRyZW5hbWllbnRvNCA8LSBwcmVkaWN0KG1vZGVsbzQsIGVudHJlbmFtaWVudG8pDQpyZXN1bHRhZG9fcHJ1ZWJhNCA8LSBwcmVkaWN0KG1vZGVsbzQsIHBydWViYSkNCg0KIyBNYXRyaXogZGUgQ29uZnVzacOzbiBkZWwgUmVzdWx0YWRvIGRlbCBFbnRyZW5hbWllbnRvDQptY3JlNCA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX2VudHJlbmFtaWVudG80LCBlbnRyZW5hbWllbnRvJG0xX3B1cmNoYXNlKQ0KbWNyZTQNCg0KIyBNYXRyaXogZGUgQ29uZnVzacOzbiBkZWwgUmVzdWx0YWRvIGRlIGxhIFBydWViYQ0KbWNycDQgPC0gY29uZnVzaW9uTWF0cml4KHJlc3VsdGFkb19wcnVlYmE0LCBwcnVlYmEkbTFfcHVyY2hhc2UpDQptY3JwNA0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiAjNUE1QTVBIj4gTW9kZWxvIDUuIFJlZGVzIE5ldXJvbmFsZXMgPC9zcGFuPg0KYGBge3J9DQptb2RlbG81IDwtIHRyYWluKG0xX3B1cmNoYXNlIH4gLiwgZGF0YT1lbnRyZW5hbWllbnRvLA0KICAgICAgICAgICAgICAgICBtZXRob2QgPSAibm5ldCIsDQogICAgICAgICAgICAgICAgIHByZVByb2Nlc3MgPSBjKCJzY2FsZSIsICJjZW50ZXIiKSwNCiAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZD0iY3YiLCBudW1iZXI9MTApLA0KICAgICAgICAgICAgICAgICB0cmFjZSA9IEZBTFNFDQogICAgICAgICAgICAgICAgICkNCg0KcmVzdWx0YWRvX2VudHJlbmFtaWVudG81IDwtIHByZWRpY3QobW9kZWxvNSwgZW50cmVuYW1pZW50bykNCnJlc3VsdGFkb19wcnVlYmE1IDwtIHByZWRpY3QobW9kZWxvNSwgcHJ1ZWJhKQ0KDQojIE1hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGVsIEVudHJlbmFtaWVudG8NCm1jcmU1IDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRhZG9fZW50cmVuYW1pZW50bzUsIGVudHJlbmFtaWVudG8kbTFfcHVyY2hhc2UpDQptY3JlNQ0KDQojIE1hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGUgbGEgUHJ1ZWJhDQptY3JwNSA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX3BydWViYTUsIHBydWViYSRtMV9wdXJjaGFzZSkNCm1jcnA1DQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6ICM1QTVBNUEiPiBNb2RlbG8gNi4gUmFuZG9tIEZvcmVzdCA8L3NwYW4+DQpgYGB7cn0NCm1vZGVsbzYgPC0gdHJhaW4obTFfcHVyY2hhc2UgfiAuLCBkYXRhPWVudHJlbmFtaWVudG8sDQogICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJyZiIsDQogICAgICAgICAgICAgICAgIHByZVByb2Nlc3MgPSBjKCJzY2FsZSIsICJjZW50ZXIiKSwNCiAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZD0iY3YiLCBudW1iZXI9MTApLA0KICAgICAgICAgICAgICAgICB0dW5lR3JpZCA9IGV4cGFuZC5ncmlkKG10cnkgPSBjKDIsNCw2KSkNCiAgICAgICAgICAgICAgICAgKQ0KDQpyZXN1bHRhZG9fZW50cmVuYW1pZW50bzYgPC0gcHJlZGljdChtb2RlbG82LCBlbnRyZW5hbWllbnRvKQ0KcmVzdWx0YWRvX3BydWViYTYgPC0gcHJlZGljdChtb2RlbG82LCBwcnVlYmEpDQoNCiMgTWF0cml6IGRlIENvbmZ1c2nDs24gZGVsIFJlc3VsdGFkbyBkZWwgRW50cmVuYW1pZW50bw0KbWNyZTYgPC0gY29uZnVzaW9uTWF0cml4KHJlc3VsdGFkb19lbnRyZW5hbWllbnRvNiwgZW50cmVuYW1pZW50byRtMV9wdXJjaGFzZSkNCm1jcmU2DQoNCiMgTWF0cml6IGRlIENvbmZ1c2nDs24gZGVsIFJlc3VsdGFkbyBkZSBsYSBQcnVlYmENCm1jcnA2IDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRhZG9fcHJ1ZWJhNiwgcHJ1ZWJhJG0xX3B1cmNoYXNlKQ0KbWNycDYNCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogIzVBNUE1QSI+IFRhYmxhIGRlIFJlc3VsdGFkb3MgPC9zcGFuPg0KYGBge3J9DQpyZXN1bHRhZG9zIDwtIGRhdGEuZnJhbWUoDQogICJzdm1MaW5lYXIiID0gYyhtY3JlMSRvdmVyYWxsWyJBY2N1cmFjeSJdLCBtY3JwMSRvdmVyYWxsWyJBY2N1cmFjeSJdKSwNCiAgInN2bVJhZGlhbCIgPSBjKG1jcmUyJG92ZXJhbGxbIkFjY3VyYWN5Il0sIG1jcnAyJG92ZXJhbGxbIkFjY3VyYWN5Il0pLA0KICAic3ZtUG9seSIgICA9IGMobWNyZTMkb3ZlcmFsbFsiQWNjdXJhY3kiXSwgbWNycDMkb3ZlcmFsbFsiQWNjdXJhY3kiXSksDQogICJycGFydCIgICAgID0gYyhtY3JlNCRvdmVyYWxsWyJBY2N1cmFjeSJdLCBtY3JwNCRvdmVyYWxsWyJBY2N1cmFjeSJdKSwNCiAgIm5uZXQiICAgICAgPSBjKG1jcmU1JG92ZXJhbGxbIkFjY3VyYWN5Il0sIG1jcnA1JG92ZXJhbGxbIkFjY3VyYWN5Il0pLA0KICAicmYiICAgICAgICA9IGMobWNyZTYkb3ZlcmFsbFsiQWNjdXJhY3kiXSwgbWNycDYkb3ZlcmFsbFsiQWNjdXJhY3kiXSkNCikNCg0Kcm93bmFtZXMocmVzdWx0YWRvcykgPC0gYygiUHJlY2lzacOzbiBkZSBlbnRyZW5hbWllbnRvIiwgIlByZWNpc2nDs24gZGUgcHJ1ZWJhIikNCnJlc3VsdGFkb3MNCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogIzVBNUE1QSI+IENvbmNsdXNpb25lcyA8L3NwYW4+DQpDb24gYmFzZSBlbiBsb3MgcmVzdWx0YWRvcyBvYnRlbmlkb3MsIGxhIG1heW9yw61hIGRlIGxvcyBtb2RlbG9zIGNvbXBsZWpvcyAoU1ZNIHJhZGlhbCwgcG9saW7Ds21pY28geSByZWRlcyBuZXVyb25hbGVzKSBwcmVzZW50YXJvbiB1biBzb2JyZWFqdXN0ZSBpbXBvcnRhbnRlLCBhbGNhbnphbmRvIHByZWNpc2lvbmVzIGNlcmNhbmFzIGFsIDk4JSBlbiBlbnRyZW5hbWllbnRvIHBlcm8gZGlzbWludXllbmRvIGNvbnNpZGVyYWJsZW1lbnRlIGVuIGxvcyBkYXRvcyBkZSBwcnVlYmEuIEVzdG8gaW5kaWNhIHF1ZSwgYXVucXVlIGxvZ3JhbiBhcHJlbmRlciBtdXkgYmllbiBlbCBwYXRyw7NuIGludGVybm8gZGVsIGNvbmp1bnRvIGRlIGVudHJlbmFtaWVudG8sIG5vIGdlbmVyYWxpemFuIGFkZWN1YWRhbWVudGUgYSBudWV2b3MgZGF0b3MsIHByb2JhYmxlbWVudGUgZGViaWRvIGFsIHRhbWHDsW8gcmVkdWNpZG8gZGUgbGEgbXVlc3RyYSB5IGFsIGFsdG8gbsO6bWVybyBkZSB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzIGNvbiBtw7psdGlwbGVzIG5pdmVsZXMuDQoNCkVsIG1vZGVsbyBxdWUgbW9zdHLDsyBlbCBtZWpvciBlcXVpbGlicmlvIGVudHJlIGRlc2VtcGXDsW8geSBjYXBhY2lkYWQgZGUgZ2VuZXJhbGl6YWNpw7NuIGZ1ZSBSYW5kb20gRm9yZXN0LCB5YSBxdWUgb2J0dXZvIGxhIG1heW9yIHByZWNpc2nDs24gZW4gcHJ1ZWJhICg2NSUpIHNpbiBjb2xhcHNhciBjb21wbGV0YW1lbnRlIGEgbGEgY2xhc2UgbWF5b3JpdGFyaWEsIGFkZW3DoXMgZGUgcHJlc2VudGFyIHVuIG1lam9yIEthcHBhIHkgQmFsYW5jZWQgQWNjdXJhY3kgZW4gY29tcGFyYWNpw7NuIGNvbiBsb3MgZGVtw6FzIG1vZGVsb3MuIFBvciBsbyB0YW50bywgZGVudHJvIGRlIGxvcyBtw6l0b2RvcyBldmFsdWFkb3MgeSBiYWpvIGVsIG1pc21vIG5pdmVsIGRlIGNvbmZpZ3VyYWNpw7NuIGFwbGljYWRvIGVuIGNsYXNlLCBSYW5kb20gRm9yZXN0IHJlcHJlc2VudGEgbGEgb3BjacOzbiBtw6FzIHPDs2xpZGEgcGFyYSBlc3RlIGNvbmp1bnRvIGRlIGRhdG9zLg==