Carga de las librerías y la tabla con los datos, convirtiendo la variable cultivar en un factor.

library(class)
library(FactoMineR)
## Warning: package 'FactoMineR' was built under R version 3.3.3
wine <- read.table( "http://gauss.inf.um.es/datos/wine.data", header = TRUE, sep = "," )

head(wine)
##   cultivar alcohol malic  ash alcalinity magnesium phenols flavonoids
## 1        1   14.23  1.71 2.43       15.6       127    2.80       3.06
## 2        1   13.20  1.78 2.14       11.2       100    2.65       2.76
## 3        1   13.16  2.36 2.67       18.6       101    2.80       3.24
## 4        1   14.37  1.95 2.50       16.8       113    3.85       3.49
## 5        1   13.24  2.59 2.87       21.0       118    2.80       2.69
## 6        1   14.20  1.76 2.45       15.2       112    3.27       3.39
##   phenols_no_flavonoids proanthocyanins color_intensity  hue OD280_OD315
## 1                  0.28            2.29            5.64 1.04        3.92
## 2                  0.26            1.28            4.38 1.05        3.40
## 3                  0.30            2.81            5.68 1.03        3.17
## 4                  0.24            2.18            7.80 0.86        3.45
## 5                  0.39            1.82            4.32 1.04        2.93
## 6                  0.34            1.97            6.75 1.05        2.85
##   proline
## 1    1065
## 2    1050
## 3    1185
## 4    1480
## 5     735
## 6    1450
str(wine)
## 'data.frame':    178 obs. of  14 variables:
##  $ cultivar             : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ alcohol              : num  14.2 13.2 13.2 14.4 13.2 ...
##  $ malic                : num  1.71 1.78 2.36 1.95 2.59 1.76 1.87 2.15 1.64 1.35 ...
##  $ ash                  : num  2.43 2.14 2.67 2.5 2.87 2.45 2.45 2.61 2.17 2.27 ...
##  $ alcalinity           : num  15.6 11.2 18.6 16.8 21 15.2 14.6 17.6 14 16 ...
##  $ magnesium            : int  127 100 101 113 118 112 96 121 97 98 ...
##  $ phenols              : num  2.8 2.65 2.8 3.85 2.8 3.27 2.5 2.6 2.8 2.98 ...
##  $ flavonoids           : num  3.06 2.76 3.24 3.49 2.69 3.39 2.52 2.51 2.98 3.15 ...
##  $ phenols_no_flavonoids: num  0.28 0.26 0.3 0.24 0.39 0.34 0.3 0.31 0.29 0.22 ...
##  $ proanthocyanins      : num  2.29 1.28 2.81 2.18 1.82 1.97 1.98 1.25 1.98 1.85 ...
##  $ color_intensity      : num  5.64 4.38 5.68 7.8 4.32 6.75 5.25 5.05 5.2 7.22 ...
##  $ hue                  : num  1.04 1.05 1.03 0.86 1.04 1.05 1.02 1.06 1.08 1.01 ...
##  $ OD280_OD315          : num  3.92 3.4 3.17 3.45 2.93 2.85 3.58 3.58 2.85 3.55 ...
##  $ proline              : int  1065 1050 1185 1480 735 1450 1290 1295 1045 1045 ...
wine$cultivar <- factor(wine$cultivar)
str(wine$cultivar)
##  Factor w/ 3 levels "1","2","3": 1 1 1 1 1 1 1 1 1 1 ...

Extracción de los datos de entrenamiento y testeo.

wine.train <- wine[sample(c(1:178), 100), 1:14]

wine.test <- wine[sample(c(1:178), 50), 1:14]

Aplicación de KNN sobre los datos crudos.

wine.pred <- knn(train = wine.train[, 2:14], test = wine.test[ ,2:14], cl = wine.train[, 1], k = 3 )

Comprobación del clasificador.

prediction <- table(Predic = wine.pred, Test = wine.test[, 1])
prediction
##       Test
## Predic  1  2  3
##      1 14  0  0
##      2  0 17  8
##      3  2  4  5
percentage_of_error <- function(numeric_matrix){
  all_tested <- sum(numeric_matrix)
  right_ones <- sum(diag(numeric_matrix))
  
  return ((all_tested - right_ones) * 100 / all_tested)
}

percentage_of_error(prediction)
## [1] 28

Aplicación de PCA a los datos de wine. Se extrae la matriz de datos del PCA y se le une la columna con el dato del cultivar al que pertenece cada observación.

wine_pca <- PCA(wine[, 2:14])

wine_dim <- wine_pca$ind$coord
wine_dim <- cbind(wine[, 1], wine_dim)

Extracción de los datos de entrenamiento y testeo.

wine_dim.train <- wine_dim[sample(c(1:178), 100), 1:6]

wine_dim.test <- wine_dim[sample(c(1:178), 50), 1:6]

Aplicación de KNN sobre la matriz de datos generada por PCA.

wine_dim.pred <- knn(train = wine_dim.train[, 2:6], test = wine_dim.test[, 2:6], cl = wine_dim.train[, 1], k = 3 )

Comprobación del nuevo clasificador.

prediction_pca <- table(Predic = wine_dim.pred, Test = wine_dim.test[, 1])
prediction_pca
##       Test
## Predic  1  2  3
##      1 20  0  0
##      2  0 19  0
##      3  0  1 10
percentage_of_error(prediction_pca)
## [1] 2

Preguntas.

  1. ¿Qué modelo ha clasificado mejor, sobre datos crudos o sobre las componentes obtenidas del PCA?

El modelo KNN generado a partir de las componentes obtenidas del PCA es mucho mejor, apenas comete fallos.

  1. ¿Cuántos componentes son necesarios para acumular más de un 70 % de la varianza?

Son necesarios 4 componentes para explicar en conjunto un 73.599 % de la varianza:

wine_pca$eig$`cumulative percentage of variance`
##  [1]  36.19885  55.40634  66.52997  73.59900  80.16229  85.09812  89.33680
##  [8]  92.01754  94.23970  96.16972  97.90655  99.20479 100.00000
  1. ¿Cuál es la variable original que más contribuye al primer eje?

“flavonoids”

wine_pca$var$contrib[, 1]
##               alcohol                 malic                   ash 
##          2.083097e+00          6.011695e+00          4.206853e-04 
##            alcalinity             magnesium               phenols 
##          5.727426e+00          2.016174e+00          1.557572e+01 
##            flavonoids phenols_no_flavonoids       proanthocyanins 
##          1.788734e+01          8.912201e+00          9.823804e+00 
##       color_intensity                   hue           OD280_OD315 
##          7.852920e-01          8.803953e+00          1.415019e+01 
##               proline 
##          8.222684e+00
max(wine_pca$var$contrib[, 1])
## [1] 17.88734
  1. ¿Tendrá alto o bajo contenido en flavonoides un vino que se sitúe sobre el eje de abscisas en la parte derecha de dicho eje?

Tendrá un alto contenido en flavonoides, como puede verse en el mapa de variables factores o bien consultando las correlaciones para la dimensión 1, siendo en el caso de “flavonoids” de 0.917, muy cercana a 1.

PCA(wine[, 2:14])

## **Results for the Principal Component Analysis (PCA)**
## The analysis was performed on 178 individuals, described by 13 variables
## *The results are available in the following objects:
## 
##    name               description                          
## 1  "$eig"             "eigenvalues"                        
## 2  "$var"             "results for the variables"          
## 3  "$var$coord"       "coord. for the variables"           
## 4  "$var$cor"         "correlations variables - dimensions"
## 5  "$var$cos2"        "cos2 for the variables"             
## 6  "$var$contrib"     "contributions of the variables"     
## 7  "$ind"             "results for the individuals"        
## 8  "$ind$coord"       "coord. for the individuals"         
## 9  "$ind$cos2"        "cos2 for the individuals"           
## 10 "$ind$contrib"     "contributions of the individuals"   
## 11 "$call"            "summary statistics"                 
## 12 "$call$centre"     "mean of the variables"              
## 13 "$call$ecart.type" "standard error of the variables"    
## 14 "$call$row.w"      "weights for the individuals"        
## 15 "$call$col.w"      "weights for the variables"
wine_pca$var$cor[, 1]
##               alcohol                 malic                   ash 
##           0.313093350          -0.531884726          -0.004449362 
##            alcalinity             magnesium               phenols 
##          -0.519157081           0.308022936           0.856136658 
##            flavonoids phenols_no_flavonoids       proanthocyanins 
##           0.917470177          -0.647607018           0.679921705 
##       color_intensity                   hue           OD280_OD315 
##          -0.192235968           0.643662066           0.816018903 
##               proline 
##           0.622050797
  1. ¿Y para ese mismo vino, cómo será su alcalinidad más alta o más baja que la media?

Su alcalinidad será más baja que la media, puede visualizarse de forma análoga al apartado 4.

Bonus: simulación de aplicar KNN a tras diferentes generaciones aleatorias de los datos de entrenamiento y testeo para los datos crudos y para la matriz PCA.

simulation_errors <- matrix(ncol=2, nrow = 20)
colnames(simulation_errors) <- c("Raw", "After PCA")

for(n in 1:20){
  # Con los datos crudos
  wine.train <- wine[sample(c(1:178), 100), 1:14]
  wine.test <- wine[sample(c(1:178), 50), 1:14]
  
  wine.pred <- knn(train = wine.train[, 2:14], test = wine.test[ ,2:14], cl = wine.train[, 1], k = 3 )
  
  prediction <- table(Predic = wine.pred, Test = wine.test[, 1])
  error_raw <- percentage_of_error(prediction)
  
  
  # Con la matriz de datos de PCA
  wine_dim.train <- wine_dim[sample(c(1:178), 100), 1:6]
  wine_dim.test <- wine_dim[sample(c(1:178), 50), 1:6]
  
  wine_dim.pred <- knn(train = wine_dim.train[, 2:6], test = wine_dim.test[, 2:6], cl = wine_dim.train[, 1], k = 3 )
  
  prediction_pca <- table(Predic = wine_dim.pred, Test = wine_dim.test[, 1])
  error_pca <- percentage_of_error(prediction_pca)
  
  
  # Guardado de los porcentajes de error
  simulation_errors[n, ] <- c(error_raw, error_pca)
}

simulation_errors
##       Raw After PCA
##  [1,]  12         4
##  [2,]  28         4
##  [3,]  20         0
##  [4,]  28         2
##  [5,]  18        10
##  [6,]  30         2
##  [7,]  24         2
##  [8,]  20         6
##  [9,]  24         6
## [10,]  22         2
## [11,]  22         6
## [12,]  18         6
## [13,]  16         0
## [14,]  28         6
## [15,]  22         2
## [16,]  12         4
## [17,]  24         2
## [18,]  28         4
## [19,]  20         0
## [20,]  12         4
summary(simulation_errors)
##       Raw         After PCA   
##  Min.   :12.0   Min.   : 0.0  
##  1st Qu.:18.0   1st Qu.: 2.0  
##  Median :22.0   Median : 4.0  
##  Mean   :21.4   Mean   : 3.6  
##  3rd Qu.:25.0   3rd Qu.: 6.0  
##  Max.   :30.0   Max.   :10.0

Creo que la simulación deja clara la supremacía del modelo KNN aplicado sobre la matriz de datos obtenida por PCA respecto al KNN aplicado sobre los datos crudos:

  1. La mediana de fallos del modelo con datos crudos es del 21% (tiende a fallar 1 de cada 5 cultivares), mientras que la del generado a partir de la matriz de PCA es del 4% (tiende a fallar 1 de cada 25 cultivares, podría estimarse que es “5 veces mejor”).

  2. El mínimo porcentaje de fallos cometido por el modelo de datos crudos y observado en la simulación es de un 10%, es decir, fallaría como mínimo en 5 cultivares de los 50 que le damos para testear.

  3. El máximo porcentaje de fallos cometido por el modelo generado a partir de la matriz de datos de PCA es del 8%, inferior al mínimo observado para los datos crudos. Mientras que en ocasiones, el modelo generado a partir de PCA acierta todos los cultivares del test.