Cargar paquetes
library(pacman)
p_load("class","caret","tidyr","mlbench","e1071","ggplot2","knitr","dplyr","readr", "prettydoc","xfun")
Vecino cercano
Esta práctica se basa en una de las aplicaciones de algoritmos de clasificación, desarrolladas con K-NN y árboles de decisión.
K-NN (o k-vecinos) es un sistema de clasificación basado en la comparación de instancias nuevas con instancias presentes en el juego de datos de entrenamiento. La construcción de grupos se realiza a partir del propio juego de datos de entrenamiento, tomando como referencia el parámetro k indicado por el investigador. El algoritmo de los K vecinos más cercanos es uno de los algoritmos más simples que existen que muestran la esencia del aprendizaje basado en instancias. Este algoritmo asume que todas las instancias corresponden a puntos que se encuentran en un espacio de dimensión n. El vecino más cercano de una instancia es definido en términos de la distancia Euclidiana estándar.
Los árboles de decisión son algoritmos que construyen modelos de decisión que forman estructuras similares a los diagramas de flujo donde los nodos internos suelen ser puntos de decisión sobre un atributo del juego de datos. Son muy dependientes del concepto de ganancia de la información ya que es el criterio que utilizan para construir las ramificaciones del árbol. A grandes rasgos existen dos tipos de árboles de decisión: * Árboles de decisión simples: el resultado se construye mediante un proceso de clasificación. * Árboles de decisión múltiples (random forest): el resultado se construye mediante el desarrollo iterativo de n procesos de clasificación.
Introducción al k Nearest Neighbors (kNN) en R
El algoritmo kNN es muy sencilla: me guardo la tabla de datos de entrenamiento y cuando me llegue un nuevo dato, encuentro los k observaciones (vecinos) más cercanos y hago la clasificación en base a esas observaciones. Al fin y al cabo, es de esperar que observaciones cercanas sean similares a la nueva observación.
Como ves, aquí vemos una gran diferencia respecto a la mayoría de algoritmos supervisados, y es que se trata de un algoritmo no paramétrico. Es decir, que el algoritmo no debe aprender el valor de ningún parámetro, por lo que no hay un proceso de entrenamiento como tal.
Así pues, la clave del algoritmo kNN que programaremos en R se basa en tres aspectos clave que debemos conocer:
Conocer las distintas medidas de distancia que existen, cómo funcionan y cuándo usar cada una de las medidas.
Entender cómo elegir la cantidad de k vecinos a los que se debe observar.
Conocer cómo hace el algortimo kNN las predicciones.
Así pues, si te parece, vamos a ir viendo cada uno de estos aspectos.
Medidas de distancia que puede usar el algoritmo kNN
Dentro del algoritmo kNN las medidas de distancia más utilizadas son: distancia Euclídea, distancia de Minkowski, distancia Manhattan, distancia de Coseno y distancia Jaccard. Estas no son las únicas, el algoritmo kNN puede usar cualquier otra medida de distancia, aunque con estas cubriremos la gran mayoría de casos.
Distancia Euclídea
La distancia Euclídea es algo que ya hemos visto en este blog al programar el algoritmo K-means tanto en R como en Python. La distancia Euclídea se basa en el teorema de Pitágoras, según el cual, la hipotenusa al cuadrado es igual a la suma de catetos al cuadrado.
Esta fórmula funcionará independientemente del número de variables que haya. Partiendo del teorema de Pitágoras, podremos encontrar la distancia en línea recta entre dos puntos, es decir, la distancia Euclídea. En la imagen siguiente podemos ver cómo se calcularía la distancia entre los puntos p y q.
Distancia euclidiana
La distancia euclídea es una de las posibles medidas de distancia que puede usar el algoritmo kNN, vamos a programar la distancia Euclídea desde 0 en R:
= function(a, b){
euclidean_distance # Comprobamos que tienen la misma cantidad de observaciones
if(length(a) == length(b)){
sqrt(sum((a-b)^2))
else{
} stop('Vectors must be of the same length')
}
}euclidean_distance(1:10, 11:20)
## [1] 31.62278
Distancia de Manhattan
La distancia de Manhattan no mide la distancia en línea recta, sino que considera la distancia como la suma de los catetos. Esto, que así dicho parece que no tiene mucho sentido, se entiende mejor con una imagen:
Ejemplo de distancia de Manhattan
Cargar datos
<- read.csv("https://raw.githubusercontent.com/rpizarrog/Industrias-4.0/main/datos/estado%20de%20felicidad%20variables.csv", encoding = "UTF-8")
datos
kable(datos, caption = "Los datos")
genero | esto.civil | edad | satisfaccion.laboral | satisfaccion.profesional | vida.familiar | vida.social | salud | dinero | estado |
---|---|---|---|---|---|---|---|---|---|
MASCULINO | SOLTERO | 25 | 80.0 | 90.0 | 70.0 | 80.00 | BUENO | 90.0 | FELIZ |
FEMENINO | CASADO | 35 | 50.0 | 80.0 | 60.0 | 70.00 | MALO | 30.0 | NO FELIZ |
MASCULINO | DIVORCIADO | 45 | 70.0 | 78.0 | 80.0 | 40.00 | REGULAR | 70.0 | FELIZ |
FEMENINO | VIUDO | 54 | 50.0 | 80.0 | 60.0 | 80.00 | BUENO | 20.0 | NO FELIZ |
MASCULINO | CASADO | 52 | 40.0 | 50.0 | 60.0 | 70.00 | BUENO | 60.0 | NO FELIZ |
FEMENINO | SOLTERO | 28 | 50.0 | 60.0 | 54.0 | 60.00 | MALO | 50.0 | NO FELIZ |
MASCULINO | VIUDO | 56 | 71.5 | 60.8 | 86.9 | 70.60 | MALO | 70.0 | FELIZ |
FEMENINO | DIVORCIADO | 32 | 60.0 | 80.0 | 30.0 | 50.00 | REGULAR | 20.0 | NO FELIZ |
MASCULINO | CASADO | 35 | 70.0 | 60.0 | 72.0 | 60.00 | BUENO | 70.0 | FELIZ |
FEMENINO | SOLTERO | 29 | 80.0 | 80.0 | 90.0 | 60.00 | MALO | 80.0 | FELIZ |
MASCULINO | DIVORCIADO | 45 | 60.0 | 60.0 | 70.0 | 50.00 | REGULAR | 90.0 | FELIZ |
FEMENINO | VIUDO | 48 | 60.0 | 50.0 | 50.0 | 45.50 | MALO | 70.0 | NO FELIZ |
MASCULINO | CASADO | 26 | 50.0 | 45.0 | 80.0 | 60.00 | MALO | 20.0 | NO FELIZ |
FEMENINO | SOLTERO | 34 | 60.0 | 40.0 | 50.0 | 80.00 | BUENO | 65.9 | FELIZ |
MASCULINO | DIVORCIADO | 42 | 50.0 | 65.0 | 56.0 | 62.58 | REGULAR | 33.5 | NO FELIZ |
FEMENINO | VIUDO | 35 | 80.0 | 70.0 | 20.0 | 20.00 | MALO | 20.5 | NO FELIZ |
MASCULINO | CASADO | 48 | 50.0 | 50.0 | 50.0 | 50.00 | BUENO | 49.5 | FELIZ |
FEMENINO | SOLTERO | 34 | 54.0 | 80.0 | 56.0 | 60.00 | REGULAR | 55.0 | FELIZ |
MASCULINO | DIVORCIADO | 34 | 60.0 | 70.0 | 80.0 | 50.00 | MALO | 100.0 | FELIZ |
FEMENINO | SOLTERO | 32 | 40.0 | 50.0 | 80.0 | 90.00 | BUENO | 95.0 | FELIZ |
MASCULINO | SOLTERO | 29 | 50.0 | 60.0 | 60.0 | 80.00 | MALO | 70.0 | FELIZ |
FEMENINO | SOLTERO | 26 | 60.0 | 60.0 | 60.0 | 60.00 | BUENO | 60.0 | FELIZ |
MASCULINO | CASADO | 45 | 60.0 | 60.0 | 60.0 | 60.00 | BUENO | 50.0 | FELIZ |
FEMENINO | VIUDO | 45 | 50.0 | 60.0 | 60.0 | 30.00 | REGULAR | 35.0 | NO FELIZ |
MASCULINO | CASADO | 28 | 50.0 | 40.0 | 80.0 | 30.00 | MALO | 30.0 | NO FELIZ |
FEMENINO | DIVORCIADO | 32 | 80.0 | 70.0 | 40.0 | 40.00 | MALO | 40.0 | NO FELIZ |
MASCULINO | SOLTERO | 36 | 65.0 | 60.0 | 62.0 | 87.00 | REGULAR | 56.5 | FELIZ |
FEMENINO | CASADO | 40 | 45.0 | 50.0 | 40.0 | 90.00 | MALO | 60.0 | NO FELIZ |
MASCULINO | SOLTERO | 41 | 60.0 | 60.0 | 60.0 | 60.00 | BUENO | 49.0 | FELIZ |
FEMENINO | VIUDO | 38 | 80.0 | 70.0 | 30.0 | 40.00 | BUENO | 45.0 | NO FELIZ |
MASCULINO | CASADO | 36 | 85.0 | 80.0 | 90.0 | 50.00 | BUENO | 80.0 | FELIZ |
FEMENINO | CASADO | 38 | 60.0 | 80.0 | 90.0 | 80.00 | BUENO | 60.0 | FELIZ |
FEMENINO | CASADO | 37 | 80.0 | 60.0 | 70.0 | 50.00 | BUENO | 60.0 | FELIZ |
FEMENINO | SOLTERO | 40 | 60.0 | 80.0 | 40.0 | 50.00 | REGULAR | 30.0 | NO FELIZ |
MASCULINO | CASADO | 40 | 60.0 | 70.0 | 50.0 | 30.00 | BUENO | 50.0 | FELIZ |
FEMENINO | CASADO | 43 | 95.0 | 80.0 | 90.0 | 90.00 | BUENO | 80.0 | FELIZ |
MASCULINO | CASADO | 55 | 70.0 | 70.0 | 65.0 | 89.00 | MALO | 75.0 | FELIZ |
MASCULINO | SOLTERO | 45 | 65.0 | 70.0 | 45.0 | 65.00 | BUENO | 45.0 | FELIZ |
FEMENINO | CASADO | 41 | 24.0 | 57.0 | 33.0 | 71.00 | BUENO | 100.0 | NO FELIZ |
FEMENINO | SOLTERO | 40 | 80.0 | 80.0 | 90.0 | 30.00 | REGULAR | 50.0 | FELIZ |
MASCULINO | SOLTERO | 39 | 60.0 | 80.0 | 48.0 | 50.00 | BUENO | 60.0 | FELIZ |
MASCULINO | SOLTERO | 42 | 90.0 | 80.0 | 50.0 | 100.00 | REGULAR | 80.0 | FELIZ |
FEMENINO | SOLTERO | 45 | 90.0 | 95.0 | 90.0 | 100.00 | BUENO | 90.0 | FELIZ |
MASCULINO | VIUDO | 88 | 65.0 | 66.0 | 89.0 | 87.00 | REGULAR | 45.0 | NO FELIZ |
MASCULINO | CASADO | 54 | 90.0 | 90.0 | 90.0 | 100.00 | BUENO | 75.0 | FELIZ |
MASCULINO | SOLTERO | 80 | 80.0 | 80.0 | 90.0 | 90.00 | BUENO | 90.0 | FELIZ |
MASCULINO | SOLTERO | 39 | 50.0 | 80.0 | 90.0 | 80.00 | REGULAR | 90.0 | FELIZ |
FEMENINO | SOLTERO | 40 | 30.0 | 60.0 | 80.0 | 50.00 | REGULAR | 50.0 | NO FELIZ |
FEMENINO | SOLTERO | 49 | 80.0 | 80.0 | 80.0 | 80.00 | BUENO | 70.0 | FELIZ |
MASCULINO | SOLTERO | 39 | 60.0 | 80.0 | 48.0 | 50.00 | REGULAR | 50.0 | NO FELIZ |
FEMENINO | SOLTERO | 30 | 100.0 | 100.0 | 100.0 | 100.00 | BUENO | 100.0 | NO FELIZ |
FEMENINO | SOLTERO | 32 | 70.0 | 80.0 | 80.0 | 80.00 | BUENO | 80.0 | FELIZ |
Preparando los datos
<- select(datos, satisfaccion.laboral, satisfaccion.profesional, vida.familiar, vida.social, dinero, estado )
datos.prep
kable(datos.prep, caption = "Datos preparados. Variables de interés")
satisfaccion.laboral | satisfaccion.profesional | vida.familiar | vida.social | dinero | estado |
---|---|---|---|---|---|
80.0 | 90.0 | 70.0 | 80.00 | 90.0 | FELIZ |
50.0 | 80.0 | 60.0 | 70.00 | 30.0 | NO FELIZ |
70.0 | 78.0 | 80.0 | 40.00 | 70.0 | FELIZ |
50.0 | 80.0 | 60.0 | 80.00 | 20.0 | NO FELIZ |
40.0 | 50.0 | 60.0 | 70.00 | 60.0 | NO FELIZ |
50.0 | 60.0 | 54.0 | 60.00 | 50.0 | NO FELIZ |
71.5 | 60.8 | 86.9 | 70.60 | 70.0 | FELIZ |
60.0 | 80.0 | 30.0 | 50.00 | 20.0 | NO FELIZ |
70.0 | 60.0 | 72.0 | 60.00 | 70.0 | FELIZ |
80.0 | 80.0 | 90.0 | 60.00 | 80.0 | FELIZ |
60.0 | 60.0 | 70.0 | 50.00 | 90.0 | FELIZ |
60.0 | 50.0 | 50.0 | 45.50 | 70.0 | NO FELIZ |
50.0 | 45.0 | 80.0 | 60.00 | 20.0 | NO FELIZ |
60.0 | 40.0 | 50.0 | 80.00 | 65.9 | FELIZ |
50.0 | 65.0 | 56.0 | 62.58 | 33.5 | NO FELIZ |
80.0 | 70.0 | 20.0 | 20.00 | 20.5 | NO FELIZ |
50.0 | 50.0 | 50.0 | 50.00 | 49.5 | FELIZ |
54.0 | 80.0 | 56.0 | 60.00 | 55.0 | FELIZ |
60.0 | 70.0 | 80.0 | 50.00 | 100.0 | FELIZ |
40.0 | 50.0 | 80.0 | 90.00 | 95.0 | FELIZ |
50.0 | 60.0 | 60.0 | 80.00 | 70.0 | FELIZ |
60.0 | 60.0 | 60.0 | 60.00 | 60.0 | FELIZ |
60.0 | 60.0 | 60.0 | 60.00 | 50.0 | FELIZ |
50.0 | 60.0 | 60.0 | 30.00 | 35.0 | NO FELIZ |
50.0 | 40.0 | 80.0 | 30.00 | 30.0 | NO FELIZ |
80.0 | 70.0 | 40.0 | 40.00 | 40.0 | NO FELIZ |
65.0 | 60.0 | 62.0 | 87.00 | 56.5 | FELIZ |
45.0 | 50.0 | 40.0 | 90.00 | 60.0 | NO FELIZ |
60.0 | 60.0 | 60.0 | 60.00 | 49.0 | FELIZ |
80.0 | 70.0 | 30.0 | 40.00 | 45.0 | NO FELIZ |
85.0 | 80.0 | 90.0 | 50.00 | 80.0 | FELIZ |
60.0 | 80.0 | 90.0 | 80.00 | 60.0 | FELIZ |
80.0 | 60.0 | 70.0 | 50.00 | 60.0 | FELIZ |
60.0 | 80.0 | 40.0 | 50.00 | 30.0 | NO FELIZ |
60.0 | 70.0 | 50.0 | 30.00 | 50.0 | FELIZ |
95.0 | 80.0 | 90.0 | 90.00 | 80.0 | FELIZ |
70.0 | 70.0 | 65.0 | 89.00 | 75.0 | FELIZ |
65.0 | 70.0 | 45.0 | 65.00 | 45.0 | FELIZ |
24.0 | 57.0 | 33.0 | 71.00 | 100.0 | NO FELIZ |
80.0 | 80.0 | 90.0 | 30.00 | 50.0 | FELIZ |
60.0 | 80.0 | 48.0 | 50.00 | 60.0 | FELIZ |
90.0 | 80.0 | 50.0 | 100.00 | 80.0 | FELIZ |
90.0 | 95.0 | 90.0 | 100.00 | 90.0 | FELIZ |
65.0 | 66.0 | 89.0 | 87.00 | 45.0 | NO FELIZ |
90.0 | 90.0 | 90.0 | 100.00 | 75.0 | FELIZ |
80.0 | 80.0 | 90.0 | 90.00 | 90.0 | FELIZ |
50.0 | 80.0 | 90.0 | 80.00 | 90.0 | FELIZ |
30.0 | 60.0 | 80.0 | 50.00 | 50.0 | NO FELIZ |
80.0 | 80.0 | 80.0 | 80.00 | 70.0 | FELIZ |
60.0 | 80.0 | 48.0 | 50.00 | 50.0 | NO FELIZ |
100.0 | 100.0 | 100.0 | 100.00 | 100.0 | NO FELIZ |
70.0 | 80.0 | 80.0 | 80.00 | 80.0 | FELIZ |
Construir el modelo KNN
En este ejercicio, el modelo de vecinos mas cercanos (KNN) se construye con los mismos datos preparados y las columnas numéricas [,1:5] para posteriormente evaluar el modelo mediante los criterios de una matriz de confusión.
<- knn(train = datos.prep[,1:5], test = datos.prep[,1:5], k = 4, cl = datos.prep[,6] )
modelo
modelo
## [1] FELIZ NO FELIZ FELIZ NO FELIZ FELIZ FELIZ FELIZ NO FELIZ
## [9] FELIZ FELIZ FELIZ FELIZ NO FELIZ FELIZ NO FELIZ NO FELIZ
## [17] FELIZ FELIZ FELIZ FELIZ FELIZ FELIZ FELIZ NO FELIZ
## [25] NO FELIZ NO FELIZ FELIZ FELIZ FELIZ NO FELIZ FELIZ FELIZ
## [33] FELIZ NO FELIZ NO FELIZ FELIZ FELIZ FELIZ NO FELIZ FELIZ
## [41] FELIZ FELIZ FELIZ FELIZ FELIZ FELIZ FELIZ NO FELIZ
## [49] FELIZ FELIZ FELIZ FELIZ
## Levels: FELIZ NO FELIZ
Resumen del modelo
summary(modelo)
## FELIZ NO FELIZ
## 38 14
Evaluar el modelo
Se construye un conjunto de datos llamado datos.r.p con valores reales y valores predichos a partir de los datos preparados incorporados en el algoritmo KNN
<- data.frame(reales = datos.prep$estado, prediccion = modelo)
datos.r.p datos.r.p
## reales prediccion
## 1 FELIZ FELIZ
## 2 NO FELIZ NO FELIZ
## 3 FELIZ FELIZ
## 4 NO FELIZ NO FELIZ
## 5 NO FELIZ FELIZ
## 6 NO FELIZ FELIZ
## 7 FELIZ FELIZ
## 8 NO FELIZ NO FELIZ
## 9 FELIZ FELIZ
## 10 FELIZ FELIZ
## 11 FELIZ FELIZ
## 12 NO FELIZ FELIZ
## 13 NO FELIZ NO FELIZ
## 14 FELIZ FELIZ
## 15 NO FELIZ NO FELIZ
## 16 NO FELIZ NO FELIZ
## 17 FELIZ FELIZ
## 18 FELIZ FELIZ
## 19 FELIZ FELIZ
## 20 FELIZ FELIZ
## 21 FELIZ FELIZ
## 22 FELIZ FELIZ
## 23 FELIZ FELIZ
## 24 NO FELIZ NO FELIZ
## 25 NO FELIZ NO FELIZ
## 26 NO FELIZ NO FELIZ
## 27 FELIZ FELIZ
## 28 NO FELIZ FELIZ
## 29 FELIZ FELIZ
## 30 NO FELIZ NO FELIZ
## 31 FELIZ FELIZ
## 32 FELIZ FELIZ
## 33 FELIZ FELIZ
## 34 NO FELIZ NO FELIZ
## 35 FELIZ NO FELIZ
## 36 FELIZ FELIZ
## 37 FELIZ FELIZ
## 38 FELIZ FELIZ
## 39 NO FELIZ NO FELIZ
## 40 FELIZ FELIZ
## 41 FELIZ FELIZ
## 42 FELIZ FELIZ
## 43 FELIZ FELIZ
## 44 NO FELIZ FELIZ
## 45 FELIZ FELIZ
## 46 FELIZ FELIZ
## 47 FELIZ FELIZ
## 48 NO FELIZ NO FELIZ
## 49 FELIZ FELIZ
## 50 NO FELIZ FELIZ
## 51 NO FELIZ FELIZ
## 52 FELIZ FELIZ
Ahora se construye la matriz de confusión con la función confusionMatrix() no sin antes categorizar o factorizar los valores de datos.r.p
Categorizar o factorizar
$reales <- as.factor(datos.r.p$reales)
datos.r.p$prediccion <- as.factor(datos.r.p$prediccion) datos.r.p
Matriz de confusión
<- confusionMatrix(datos.r.p$reales, datos.r.p$prediccion)
matriz
matriz
## Confusion Matrix and Statistics
##
## Reference
## Prediction FELIZ NO FELIZ
## FELIZ 31 1
## NO FELIZ 7 13
##
## Accuracy : 0.8462
## 95% CI : (0.7192, 0.9312)
## No Information Rate : 0.7308
## P-Value [Acc > NIR] : 0.03743
##
## Kappa : 0.6556
##
## Mcnemar's Test P-Value : 0.07710
##
## Sensitivity : 0.8158
## Specificity : 0.9286
## Pos Pred Value : 0.9687
## Neg Pred Value : 0.6500
## Prevalence : 0.7308
## Detection Rate : 0.5962
## Detection Prevalence : 0.6154
## Balanced Accuracy : 0.8722
##
## 'Positive' Class : FELIZ
##
Ahora, la función de la matriz de confusión hace de forma automática las métricas de calidad del modelo, sin embargo es importante que sepamos de donde salen dichas métricas y cómo se calculan, a continuación lo veremos:
Calculos para las métricas del modelo
<- round(as.numeric(matriz$overall[1]) * 100,2)
exactitud <- round(as.numeric(matriz$byClass[1]) * 100,2)
sensibilidad <- round(as.numeric(matriz$byClass[2]) * 100,2)
especificidad <- round(as.numeric(matriz$byClass[3]) * 100,2)
precision.FELIZ <- round(as.numeric(matriz$byClass[4]) * 100,2)
precision.NOFELIZ <- round(as.numeric(matriz$overall[2]) * 100,2)
kappa
sensibilidad
## [1] 81.58
Ese 86% de precisión sale de ese cálculo.
Hacer predicciones
#genero <- c('MASCULINO', 'FEMENINO', 'FEMENINO')
#esto.civil <- c('SOLTERO', 'CASADO', 'DIVORCIADO')
#edad <- c(30, 25, 40)
<- c(40, 50, 60)
satisfaccion.laboral <- c(60, 50, 40)
satisfaccion.profesional <- c(80, 70, 60)
vida.familiar <- c(60,50,76)
vida.social #salud <- c('BUENO', 'REGULAR', 'MALO')
<- c(40, 50, 60)
dinero = c('?', '?', '?')
estado
<- data.frame(satisfaccion.laboral, satisfaccion.profesional, vida.familiar, vida.social, dinero, estado )
datos.nuevos
kable(datos.nuevos, caption = "Datos nuevos")
satisfaccion.laboral | satisfaccion.profesional | vida.familiar | vida.social | dinero | estado |
---|---|---|---|---|---|
40 | 60 | 80 | 60 | 40 | ? |
50 | 50 | 70 | 50 | 50 | ? |
60 | 40 | 60 | 76 | 60 | ? |
- Resultados del modelo
<- knn(train = datos.prep[,1:5], test = datos.nuevos[,1:5], k = 4, cl = datos.prep[,6] )
modelo
modelo
## [1] NO FELIZ FELIZ FELIZ
## Levels: FELIZ NO FELIZ
<- mutate(datos.nuevos, prediccion = modelo)
datos.nuevos kable(datos.nuevos, caption = "Predicción de datos nuevos")
satisfaccion.laboral | satisfaccion.profesional | vida.familiar | vida.social | dinero | estado | prediccion |
---|---|---|---|---|---|---|
40 | 60 | 80 | 60 | 40 | ? | NO FELIZ |
50 | 50 | 70 | 50 | 50 | ? | FELIZ |
60 | 40 | 60 | 76 | 60 | ? | FELIZ |