Implementar el modelo de vecinos mas cercanos KNN con programación R para resolver la tarea de clasificación de una condición de salud de las personas mediante predicción de anomalías de corazón evaluando la exactitud del modelo mediante la matriz de confusión.
Se cargan librerías y se descargan los datos: https://raw.githubusercontent.com/rpizarrog/Analisis-Inteligente-de-datos/main/datos/heart_2020_cleaned.csv
Los datos están relacionados con aspectos médicos y son valores numéricos de varias variables que caracterizan el estado de salud de 319,795 personas.
Se construye un modelo supervisado basado en el algoritmo de vecinos mas cercanos KNN para resolver la tarea de clasificación binaria e identificar si una persona padece del corazón o no.
Primero se construye un modelo KNN con la función use la función train.kknn() de la librería kknn
Luego se construye un similar modelo pero con la función knn() de la librería class.
Se construyen datos de entrenamiento y validación al 80% y 20% cada uno.
Se desarrollan los modelos de:
Regresión Logística binaria
Árbol de Clasificación tipo class
KNN Vecinos mas cercanos
SVM Lineal
SVM Polinomial
SVM Radial
Los modelo se aceptan si tienen un valor de exactitud por encima del 70%..
El algoritmo vecinos mas cercanos KNN clasifica cada dato nuevo en el grupo que corresponda, según tenga k vecinos más cerca de un grupo o de otro. Es decir, calcula la distancia del elemento nuevo a cada uno de los existentes, y ordena dichas distancias de menor a mayor para ir seleccionando el grupo al que pertenecer.
Este grupo será, por tanto, el de mayor frecuencia con menores distancias.
El KNN es un algoritmo de aprendizaje supervisado, es decir, que a partir de un juego de datos inicial su objetivo será el de clasificar correctamente todas las instancias nuevas. El juego de datos típico de este tipo de algoritmos está formado por varios atributos descriptivos y un solo atributo objetivo (también llamado clase).
El método K-NN es un método importantes de clasificación supervisada. En el proceso de aprendizaje no se hace ninguna suposición acerca de la distribución de las variables predictoras, es por ello que es un método de clasificación no paramétrico, que estima el valor de la función de densidad de probabilidad o directamente la probabilidad posterior de que un elemento xx pertenezca a la clase CjCj a partir de la información proporcionada por el conjunto de entrenamiento.
Es un método bastante sencillo y robusto que simplemente busca en las observaciones más cercanas a la que se está tratando de predecir y clasifica el punto de interés basado en la mayoría de datos que le rodean.
Es un algoritmo muy simple de implementar y de entrenar, pero tienen una carga computacional elevada y no es apropiado cuando se tienen muchos grados de libertad.
library(readr) # Leer datos
library(kknn) # KNN modelo para kknn
library(dplyr) # Procesar filtrar
library(forcats) # para decodificar vars
library(class) # Para knn()
library(caret) # Matriz de confusión entre otros
library(reshape) # Para modificar variables
library(knitr) # Para tablas amigables
Cargar datos de manera local.
datos <- read.csv("https://raw.githubusercontent.com/rpizarrog/Machine-Learning-con-R/main/datos/heart_2020_cleaned.csv", stringsAsFactors = TRUE, encoding = "UTF-8")
# datos <- read.csv("../../datos/heart_2020_cleaned.csv", encoding = "UTF-8", stringsAsFactors = TRUE)
Son 319795 registros y 18 observaciones. El 80% serán datos de entrenamiento y el 20% serán datos de validación.
La variable HeartDisease es de tipo factor y tiene dos niveles “No” y “Yes”.
str(datos)
## 'data.frame': 319795 obs. of 18 variables:
## $ HeartDisease : Factor w/ 2 levels "No","Yes": 1 1 1 1 1 2 1 1 1 1 ...
## $ BMI : num 16.6 20.3 26.6 24.2 23.7 ...
## $ Smoking : Factor w/ 2 levels "No","Yes": 2 1 2 1 1 2 1 2 1 1 ...
## $ AlcoholDrinking : Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1 ...
## $ Stroke : Factor w/ 2 levels "No","Yes": 1 2 1 1 1 1 1 1 1 1 ...
## $ PhysicalHealth : num 3 0 20 0 28 6 15 5 0 0 ...
## $ MentalHealth : num 30 0 30 0 0 0 0 0 0 0 ...
## $ DiffWalking : Factor w/ 2 levels "No","Yes": 1 1 1 1 2 2 1 2 1 2 ...
## $ Sex : Factor w/ 2 levels "Female","Male": 1 1 2 1 1 1 1 1 1 2 ...
## $ AgeCategory : Factor w/ 13 levels "18-24","25-29",..: 8 13 10 12 5 12 11 13 13 10 ...
## $ Race : Factor w/ 6 levels "American Indian/Alaskan Native",..: 6 6 6 6 6 3 6 6 6 6 ...
## $ Diabetic : Factor w/ 4 levels "No","No, borderline diabetes",..: 3 1 3 1 1 1 1 3 2 1 ...
## $ PhysicalActivity: Factor w/ 2 levels "No","Yes": 2 2 2 1 2 1 2 1 1 2 ...
## $ GenHealth : Factor w/ 5 levels "Excellent","Fair",..: 5 5 2 3 5 2 2 3 2 3 ...
## $ SleepTime : num 5 7 8 6 8 12 4 9 5 10 ...
## $ Asthma : Factor w/ 2 levels "No","Yes": 2 1 2 1 1 1 2 2 1 1 ...
## $ KidneyDisease : Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 2 1 ...
## $ SkinCancer : Factor w/ 2 levels "No","Yes": 2 1 1 2 1 1 2 1 1 1 ...
summary(datos)
## HeartDisease BMI Smoking AlcoholDrinking Stroke
## No :292422 Min. :12.02 No :187887 No :298018 No :307726
## Yes: 27373 1st Qu.:24.03 Yes:131908 Yes: 21777 Yes: 12069
## Median :27.34
## Mean :28.33
## 3rd Qu.:31.42
## Max. :94.85
##
## PhysicalHealth MentalHealth DiffWalking Sex
## Min. : 0.000 Min. : 0.000 No :275385 Female:167805
## 1st Qu.: 0.000 1st Qu.: 0.000 Yes: 44410 Male :151990
## Median : 0.000 Median : 0.000
## Mean : 3.372 Mean : 3.898
## 3rd Qu.: 2.000 3rd Qu.: 3.000
## Max. :30.000 Max. :30.000
##
## AgeCategory Race
## 65-69 : 34151 American Indian/Alaskan Native: 5202
## 60-64 : 33686 Asian : 8068
## 70-74 : 31065 Black : 22939
## 55-59 : 29757 Hispanic : 27446
## 50-54 : 25382 Other : 10928
## 80 or older: 24153 White :245212
## (Other) :141601
## Diabetic PhysicalActivity GenHealth
## No :269653 No : 71838 Excellent: 66842
## No, borderline diabetes: 6781 Yes:247957 Fair : 34677
## Yes : 40802 Good : 93129
## Yes (during pregnancy) : 2559 Poor : 11289
## Very good:113858
##
##
## SleepTime Asthma KidneyDisease SkinCancer
## Min. : 1.000 No :276923 No :308016 No :289976
## 1st Qu.: 6.000 Yes: 42872 Yes: 11779 Yes: 29819
## Median : 7.000
## Mean : 7.097
## 3rd Qu.: 8.000
## Max. :24.000
##
No es necesario alguna transformación
Todas las variables son de entrada o variables independientes:
“BMI”: Indice de masa corporal con valores entre 12.02 y 94.85.
“Smoking”: Si la persona es fumadora o no con valores categóritos de ‘Yes’ o ‘No’.
“AlcoholDrinking” : Si consume alcohol o no, con valores categóricos de ‘Yes’ o ‘No’.
“Stroke”: Si padece alguna anomalía cerebrovascular, apoplejia o algo similar, con valores categóricos de ‘Yes’ o ‘No’.
“PhysicalHealth” Estado físico en lo general con valores entre 0 y 30.
“MentalHealth”. Estado mental en lo general con valores entre 0 y 30.
“DiffWalking” . Que si se le dificulta caminar o tiene algún padecimiento al caminar, con valores categóritoc de ‘Yes’ o ‘No’.
“Sex”: Género de la persona, con valores de ‘Female’ y ‘Male’ para distinguir al género femenino y masculino respectivamente.
“AgeCategory”: Una clasificación de la edad de la persona de entre 18 y 80 años. La primera categoría con un rango de edad entre 18-24, a partir de 25 con rangos de 5 en 5 hasta la clase de 75-80 y una última categoría mayores de 80 años.
“Race”. Raza u origen de la persona con valores categóricos de ‘American Indian/Alaskan Native’, ’Asian’,’Black’, ’Hispanic’, ’Other’ y’White’.
“Diabetic”. Si padece o ha padecido de diabetes en cuatro condiciones siendo Yes y No para si o no: ‘No’, ‘borderline diabetes’ condición antes de detectarse diabetes tipo 2, ‘Yes’, y ‘Yes (during pregnancy)’ durante embarazo.
“PhysicalActivity” que si realiza actividad física, con valores categóricos de ‘Yes’ o ‘No’.
“GenHealth”: EStado general de salud de la persona con valores categóricos de ‘Excellent’, ‘Very good’, ’Good’, ’Fair’ y ’Poor’ con significado en español de excelente, muy buena, buena, regular y pobre o deficiente.
“SleepTime”: valor numérico de las horas de sueño u horas que duerme la persona con valores en un rango entre 1 y 24.
“Asthma”: si padece de asma o no, con valores categóricos de ‘Yes’ o ‘No’.
“KidneyDisease”: si tiene algún padecimiento en los riñones, con valores categóricos de ‘Yes’ o ‘No’.
“SkinCancer”: si padece algún tipo de cáncer de piel, con valores categóricos de ‘Yes’ o ‘No’.
La variable de interés como dependiente o variable de salida es la de daño al corazón (HeartDisease), con valores categóricos de ‘Yes’ o ‘No’.
Se parten los datos en en datos de entrenamiento con el 80% y datos de validación con el 20%.
set.seed(2022)
entrena <- createDataPartition(y = datos$HeartDisease,
p = 0.8,
list = FALSE,
times = 1)
# Datos entrenamiento
datos.entrenamiento <- datos[entrena, ] # [renglones, columna]
# Datos validación
datos.validacion <- datos[-entrena, ]
Se muestran los primeros 20 registros datos de entrenamiento
kable(head(datos.entrenamiento, 20), caption = "Primeros 20 registros de datos de entrenamiento")
| HeartDisease | BMI | Smoking | AlcoholDrinking | Stroke | PhysicalHealth | MentalHealth | DiffWalking | Sex | AgeCategory | Race | Diabetic | PhysicalActivity | GenHealth | SleepTime | Asthma | KidneyDisease | SkinCancer | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | No | 16.60 | Yes | No | No | 3 | 30 | No | Female | 55-59 | White | Yes | Yes | Very good | 5 | Yes | No | Yes |
| 2 | No | 20.34 | No | No | Yes | 0 | 0 | No | Female | 80 or older | White | No | Yes | Very good | 7 | No | No | No |
| 3 | No | 26.58 | Yes | No | No | 20 | 30 | No | Male | 65-69 | White | Yes | Yes | Fair | 8 | Yes | No | No |
| 4 | No | 24.21 | No | No | No | 0 | 0 | No | Female | 75-79 | White | No | No | Good | 6 | No | No | Yes |
| 5 | No | 23.71 | No | No | No | 28 | 0 | Yes | Female | 40-44 | White | No | Yes | Very good | 8 | No | No | No |
| 6 | Yes | 28.87 | Yes | No | No | 6 | 0 | Yes | Female | 75-79 | Black | No | No | Fair | 12 | No | No | No |
| 7 | No | 21.63 | No | No | No | 15 | 0 | No | Female | 70-74 | White | No | Yes | Fair | 4 | Yes | No | Yes |
| 8 | No | 31.64 | Yes | No | No | 5 | 0 | Yes | Female | 80 or older | White | Yes | No | Good | 9 | Yes | No | No |
| 9 | No | 26.45 | No | No | No | 0 | 0 | No | Female | 80 or older | White | No, borderline diabetes | No | Fair | 5 | No | Yes | No |
| 10 | No | 40.69 | No | No | No | 0 | 0 | Yes | Male | 65-69 | White | No | Yes | Good | 10 | No | No | No |
| 11 | Yes | 34.30 | Yes | No | No | 30 | 0 | Yes | Male | 60-64 | White | Yes | No | Poor | 15 | Yes | No | No |
| 12 | No | 28.71 | Yes | No | No | 0 | 0 | No | Female | 55-59 | White | No | Yes | Very good | 5 | No | No | No |
| 13 | No | 28.37 | Yes | No | No | 0 | 0 | Yes | Male | 75-79 | White | Yes | Yes | Very good | 8 | No | No | No |
| 14 | No | 28.15 | No | No | No | 7 | 0 | Yes | Female | 80 or older | White | No | No | Good | 7 | No | No | No |
| 15 | No | 29.29 | Yes | No | No | 0 | 30 | Yes | Female | 60-64 | White | No | No | Good | 5 | No | No | No |
| 16 | No | 29.18 | No | No | No | 1 | 0 | No | Female | 50-54 | White | No | Yes | Very good | 6 | No | No | No |
| 17 | No | 26.26 | No | No | No | 5 | 2 | No | Female | 70-74 | White | No | No | Very good | 10 | No | No | No |
| 18 | No | 22.59 | Yes | No | No | 0 | 30 | Yes | Male | 70-74 | White | No, borderline diabetes | Yes | Good | 8 | No | No | No |
| 20 | No | 18.13 | No | No | No | 0 | 0 | No | Male | 80 or older | White | No | Yes | Excellent | 8 | No | No | Yes |
| 21 | No | 21.16 | No | No | No | 0 | 0 | No | Female | 80 or older | Black | No, borderline diabetes | No | Good | 8 | No | No | No |
Se muestran los primeros 20 registros de datos de validación .
kable(head(datos.validacion, 20), caption = "Primeros 20 registros de datos de validación")
| HeartDisease | BMI | Smoking | AlcoholDrinking | Stroke | PhysicalHealth | MentalHealth | DiffWalking | Sex | AgeCategory | Race | Diabetic | PhysicalActivity | GenHealth | SleepTime | Asthma | KidneyDisease | SkinCancer | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 19 | No | 29.86 | Yes | No | No | 0 | 0 | Yes | Female | 75-79 | Black | Yes | No | Fair | 5 | No | Yes | No |
| 25 | No | 25.75 | No | No | No | 0 | 0 | No | Female | 80 or older | White | No | Yes | Very good | 6 | No | No | Yes |
| 27 | No | 34.34 | Yes | No | No | 21 | 8 | Yes | Female | 65-69 | White | No | Yes | Fair | 9 | No | No | No |
| 30 | No | 36.58 | No | No | No | 0 | 0 | No | Female | 60-64 | White | Yes | No | Good | 5 | No | No | Yes |
| 43 | Yes | 25.06 | No | No | No | 0 | 0 | Yes | Female | 80 or older | White | Yes | No | Good | 7 | No | No | Yes |
| 47 | No | 33.23 | No | No | No | 0 | 0 | No | Male | 65-69 | White | Yes | Yes | Very good | 8 | No | No | No |
| 48 | No | 25.11 | No | No | No | 5 | 5 | No | Female | 65-69 | Black | No | Yes | Good | 7 | No | No | No |
| 55 | No | 32.10 | No | No | No | 14 | 0 | No | Male | 65-69 | White | Yes | Yes | Very good | 9 | No | No | No |
| 60 | No | 27.20 | Yes | No | Yes | 0 | 0 | No | Male | 80 or older | White | No | No | Very good | 8 | No | No | Yes |
| 61 | No | 28.94 | Yes | No | No | 0 | 0 | No | Female | 70-74 | White | Yes | Yes | Good | 5 | Yes | No | No |
| 62 | No | 21.03 | No | No | No | 1 | 0 | No | Female | 80 or older | White | No | Yes | Excellent | 8 | No | No | No |
| 64 | No | 31.46 | Yes | No | No | 0 | 0 | No | Male | 75-79 | White | No | Yes | Very good | 8 | No | No | No |
| 72 | No | 27.76 | Yes | No | No | 15 | 0 | Yes | Female | 80 or older | White | No | No | Good | 8 | Yes | No | No |
| 74 | No | 30.23 | No | No | No | 0 | 5 | No | Female | 65-69 | White | No | Yes | Good | 6 | No | No | No |
| 79 | Yes | 28.29 | Yes | No | No | 30 | 30 | No | Female | 70-74 | White | Yes | Yes | Poor | 9 | No | Yes | No |
| 89 | No | 32.81 | Yes | No | No | 0 | 0 | Yes | Female | 70-74 | White | Yes | Yes | Good | 5 | No | No | No |
| 91 | No | 44.29 | No | No | No | 30 | 10 | Yes | Female | 70-74 | White | No | No | Fair | 7 | No | No | Yes |
| 93 | No | 21.80 | Yes | No | No | 0 | 0 | No | Female | 75-79 | White | No | Yes | Very good | 8 | No | No | Yes |
| 99 | No | 24.37 | No | No | No | 0 | 0 | No | Female | 55-59 | White | No | Yes | Very good | 7 | Yes | No | No |
| 111 | No | 26.63 | No | No | No | 0 | 0 | No | Female | 75-79 | Black | Yes | Yes | Good | 8 | No | No | No |
Se crea el modelo de vecinos mas cercanos con la función train.kknn().
Se construye una muestra de 10000 (diezmil) registros a partir de los datos de entrenamiento con lo cual precisamente se construye el modelo KNN, Esto se hace aquí en R, dado que la limitante es la gran cantidad de observaciones como desventaja del modelo., El modelo sería para pequeños conjunto de datos.
muestra <- sample(x = 1:nrow(datos.entrenamiento), size = 10000, replace = FALSE)
modelo.knnn <- train.kknn(data = datos.entrenamiento[muestra, ], formula = HeartDisease ~ ., ks = 12, kmax = 30)
Se hacen predicciones con los datos de validación usando el modelo que se construyó. en la variable modelo.knnn.
predicciones <- predict(object = modelo.knnn, newdata = datos.validacion)
Construir matriz par comparar las predicciones con los valores reales de los datos de validación de la variable HeartDisease contrastada con las predicciones.
datos.comparar <- data.frame("real" = datos.validacion$HeartDisease, "predicho" = predicciones)
kable(head(datos.comparar, 20), caption = "Datos a comparar previo a matriz de confusión" )
| real | predicho |
|---|---|
| No | No |
| No | No |
| No | No |
| No | No |
| Yes | No |
| No | No |
| No | No |
| No | No |
| No | Yes |
| No | No |
| No | No |
| No | No |
| No | No |
| No | No |
| Yes | Yes |
| No | No |
| No | No |
| No | No |
| No | No |
| No | No |
matriz <- confusionMatrix(datos.comparar$real, datos.comparar$predicho)
matriz
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 57359 1125
## Yes 4935 539
##
## Accuracy : 0.9053
## 95% CI : (0.903, 0.9075)
## No Information Rate : 0.974
## P-Value [Acc > NIR] : 1
##
## Kappa : 0.1157
##
## Mcnemar's Test P-Value : <2e-16
##
## Sensitivity : 0.92078
## Specificity : 0.32392
## Pos Pred Value : 0.98076
## Neg Pred Value : 0.09847
## Prevalence : 0.97398
## Detection Rate : 0.89682
## Detection Prevalence : 0.91441
## Balanced Accuracy : 0.62235
##
## 'Positive' Class : No
##
Se tiene un valor de accuracy = exactitud de 0.9053 o de $90.53%$ que significa que el modelo le atina en la predicción o clasificación aproximadamente al 90% de cada 100 casos procesados.
Se crea un registro de una persona con ciertas condiciones de salud.
BMI <- 38
Smoking <- 'Yes'
AlcoholDrinking = 'Yes'
Stroke <- 'Yes'
PhysicalHealth <- 2
MentalHealth = 5
DiffWalking = 'Yes'
Sex = 'Male'
AgeCategory = '70-74'
Race = 'Black'
Diabetic <- 'Yes'
PhysicalActivity = "No"
GenHealth = "Fair"
SleepTime = 12
Asthma = "Yes"
KidneyDisease = "Yes"
SkinCancer = 'No'
persona <- data.frame(BMI,Smoking, AlcoholDrinking, Stroke, PhysicalHealth, MentalHealth, DiffWalking, Sex, AgeCategory, Race, Diabetic, PhysicalActivity, GenHealth, SleepTime, Asthma, KidneyDisease, SkinCancer)
persona
## BMI Smoking AlcoholDrinking Stroke PhysicalHealth MentalHealth DiffWalking
## 1 38 Yes Yes Yes 2 5 Yes
## Sex AgeCategory Race Diabetic PhysicalActivity GenHealth SleepTime Asthma
## 1 Male 70-74 Black Yes No Fair 12 Yes
## KidneyDisease SkinCancer
## 1 Yes No
Convertir a factores las variables tipo char par que el modelo entienda que precisamente son de tipo actor y tienen sus niveles. Se convierte al mismo tipo que los datos de validación para cada variable de tipo char de la persona.
persona$Smoking <- factor(persona$Smoking, levels = levels(datos.validacion$Smoking))
persona$AlcoholDrinking <- factor(persona$AlcoholDrinking, levels = levels(datos.validacion$AlcoholDrinking))
persona$Stroke <- factor(persona$Stroke, levels = levels(datos.validacion$Stroke))
persona$DiffWalking <- factor(persona$DiffWalking, levels = levels(datos.validacion$DiffWalking))
persona$Sex <- factor(persona$Sex, levels = levels(datos.validacion$Sex))
persona$AgeCategory <- factor(persona$AgeCategory, levels = levels(datos.validacion$AgeCategory))
persona$Race <- factor(persona$Race, levels = levels(datos.validacion$Race))
persona$Diabetic <- factor(persona$Diabetic, levels = levels(datos.validacion$Diabetic))
persona$PhysicalActivity <- factor(persona$PhysicalActivity, levels = levels(datos.validacion$PhysicalActivity))
persona$GenHealth <- factor(persona$GenHealth, levels = levels(datos.validacion$GenHealth))
persona$Asthma <- factor(persona$Asthma, levels = levels(datos.validacion$Asthma))
persona$KidneyDisease <- factor(persona$KidneyDisease, levels = levels(datos.validacion$KidneyDisease))
persona$SkinCancer <- factor(persona$SkinCancer, levels = levels(datos.validacion$SkinCancer))
Se hace la predicción con estos valores:
Primero con el modelo de clasificación 1 modelo.knnn:
prediccion <- predict(object = modelo.knnn, newdata = persona)
prediccion
## [1] Yes
## Levels: No Yes
La predicción es que LA PERSONA SI se clasifica con daño al corazón con el modelo modelo.knnn.
Se construye un segundo modelo. Ahora, se hace la construcción del modelo usando otra función pero que también tiene que ver con el algoritmo de vecinos mas cercanos. Se usa la función knn() de la librería class.
Se reconstruyen los mismos datos de entrenamiento y validación, sin embargo, se hace una limpieza de las variables que son categóricas transformadas a valores numéricos.
Esto se hace dado que la librería class y la función knn() así lo pide.
El proceso de limpieza es transformar variables
Se construye un data.frame similar pero llamado datos2 con variables numéricas en lugar de factores; esto se hace para el modelo se construya con la función knn().
Primero se transforman las variables dicotómicas que serían: Smoking, AlcoholDrinking, Stroke, DiffWalking, Sex PhysicalActivity, Asthma, KidneyDisease, SkinCancer
datos2 <- datos %>%
mutate(Smoking = if_else(Smoking == 'Yes', 1, 2), AlcoholDrinking = if_else(AlcoholDrinking == 'Yes', 1, 2), Stroke = if_else(Stroke == 'Yes', 1, 2), DiffWalking = if_else(DiffWalking == 'Yes', 1, 2), Sex = if_else(Sex == 'Female', 1, 2), PhysicalActivity = if_else(PhysicalActivity == 'Yes', 1, 2), Asthma = if_else(Asthma == 'Yes', 1, 2), KidneyDisease = if_else(KidneyDisease == 'Yes', 1, 2), SkinCancer = if_else(SkinCancer == 'Yes', 1, 2))
Luego la variable AgeCategory que transforma las categóricas de edades a variable numéricas pero en jerarquía o nveles del 1 al 12, un nivel para cada categoría de edad.
datos2 <- datos2 %>%
mutate(AgeCategory = ifelse (AgeCategory == '18-24', 1, ifelse(AgeCategory == '25-29', 2, ifelse(AgeCategory == '30-34', 3, ifelse(AgeCategory == '35-39', 4, ifelse(AgeCategory == '40-44', 5, ifelse(AgeCategory == '45-49', 6, ifelse(AgeCategory == '50-54', 7, ifelse(AgeCategory == '55-59', 8, ifelse(AgeCategory == '60-64', 9, ifelse(AgeCategory == '65-69', 10, ifelse(AgeCategory == '70-74', 11, ifelse(AgeCategory == '75-79', 12, 13)))))))))))))
Luego la variable Race secategoriza con valores numéricos del 1 al 6, uno por cada raza.
datos2 <- datos2 %>%
mutate(Race = ifelse (Race == 'White', 1, ifelse(Race == 'Black', 2, ifelse(Race == 'Asian', 3, ifelse(Race == 'American Indian/Alaskan Native', 4, ifelse(Race == 'Other', 5, 6 ))))))
La variable Diabetic se categoriza con niveles del 1 al 4
datos2 <- datos2 %>%
mutate(Diabetic = ifelse (Diabetic == 'Yes', 1, ifelse(Diabetic == 'No', 2, ifelse(Diabetic == 'No, borderline diabetes', 3, 4))))
La variable GenHealth se transforma a valores entre 1 y 5
datos2 <- datos2 %>%
mutate(GenHealth = ifelse (Race == 'Fair', 1, ifelse(GenHealth == 'Poor', 2, ifelse(GenHealth == 'Good', 3, ifelse(GenHealth == 'Very good', 4, 5 )))))
Se construyen los datos de entrenamiento y validación pero a partir de datos2
set.seed(2022)
entrena <- createDataPartition(y = datos2$HeartDisease,
p = 0.8,
list = FALSE,
times = 1)
# Datos entrenamiento
datos.entrenamiento <- datos2[entrena, ] # [renglones, columna]
# Datos validación
datos.validacion <- datos2[-entrena, ]
Nuevamente una muestra de 10000 (diezmil) registros de los datos de entrenamiento.
muestra <- sample(x = 1:nrow(datos.entrenamiento), size = 10000, replace = FALSE)
El modelo automáticamente se construye con los datos de entrenamiento y datos de validación indicando en los parámetros train y test respectivamente sin incluir la primera columna [, -1] o sea HeartDisease que es la variable dependiente u objetivo. Luego con el parámetro cl se le indica la variable factor o de clasificación que este caso es HeartDeisease o la primer columna [, 1], el parámetro k= 12 e el número de vecinos a considerar que puede cambiar a discreción del científico de datos.
predicciones.2 <- knn(train = datos.entrenamiento[muestra, -1], test = datos.validacion[, -1], cl = datos.entrenamiento[muestra,1], k = 12)
Habiendo construido y entrenado el modelo se hace una matriz de comparación al igual que en el primer modelo knn de este caso que servirá para construir la matriz de confusión.
Construir matriz par comparar las predicciones con los valores reales de los datos de validación de la variable HeartDisease contrastada con las predicciones.
datos.comparar <- data.frame("real" = datos.validacion$HeartDisease, "predicho" = predicciones.2)
kable(head(datos.comparar, 20), caption = "Datos a comparar previo a matriz de confusión" )
| real | predicho |
|---|---|
| No | No |
| No | No |
| No | No |
| No | No |
| Yes | No |
| No | No |
| No | No |
| No | No |
| No | No |
| No | No |
| No | No |
| No | No |
| No | No |
| No | No |
| Yes | No |
| No | No |
| No | No |
| No | No |
| No | No |
| No | No |
matriz <- confusionMatrix(datos.comparar$real, datos.comparar$predicho)
matriz
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 58398 86
## Yes 5431 43
##
## Accuracy : 0.9137
## 95% CI : (0.9115, 0.9159)
## No Information Rate : 0.998
## P-Value [Acc > NIR] : 1
##
## Kappa : 0.0115
##
## Mcnemar's Test P-Value : <2e-16
##
## Sensitivity : 0.914913
## Specificity : 0.333333
## Pos Pred Value : 0.998530
## Neg Pred Value : 0.007855
## Prevalence : 0.997983
## Detection Rate : 0.913068
## Detection Prevalence : 0.914413
## Balanced Accuracy : 0.624123
##
## 'Positive' Class : No
##
Se tiene un valor de accuracy = exactitud de 0.9137 o de \(91.37\%\) que significa que el modelo le atina en la predicción o clasificación aproximadamente al 91% de cada 100 casos procesados.
Se crea un registro de una persona con ciertas condiciones de salud.
HeartDisease = 'No'
BMI <- 38
Smoking <- 1 # 'Yes'
AlcoholDrinking = 1 # 'Yes'
Stroke <- 1 # 'Yes'
PhysicalHealth <- 2
MentalHealth <- 5
DiffWalking <- 1 # 'Yes'
Sex = 2 # 'Male
AgeCategory = 11 # '70-74'
Race = 2 # 'Black'
Diabetic <- 1 # 'Yes'
PhysicalActivity = 2 # 'No'
GenHealth = 1 # "Fair"
SleepTime = 12
Asthma = 1 # 'Yes'
KidneyDisease = 1 # 'Yes'
SkinCancer = 2 # 'No'
persona2 <- data.frame(HeartDisease, BMI,Smoking, AlcoholDrinking, Stroke, PhysicalHealth, MentalHealth, DiffWalking, Sex, AgeCategory, Race, Diabetic, PhysicalActivity, GenHealth, SleepTime, Asthma, KidneyDisease, SkinCancer)
persona2
## HeartDisease BMI Smoking AlcoholDrinking Stroke PhysicalHealth MentalHealth
## 1 No 38 1 1 1 2 5
## DiffWalking Sex AgeCategory Race Diabetic PhysicalActivity GenHealth
## 1 1 2 11 2 1 2 1
## SleepTime Asthma KidneyDisease SkinCancer
## 1 12 1 1 2
Aquí no se requiere convertir las variables del registro persona2 a variables tipo categóricas tipo factor ya que son valores numéricos y el modelo así fue construido.
Se hace la predicción con estos valores:
Ahora con el modelo de clasificación 2 knn:
predicciones.2 <- knn(train = datos.entrenamiento[muestra, -1], test = persona2[, -1], cl = datos.entrenamiento[muestra,1], k = 12)
predicciones.2
## [1] No
## Levels: No Yes
La predicción es que LA PERSONA NO se clasifica con daño al corazón con el modelo knn.
extraño es que un modelo dice SI y otro dice NO; los valores a probar son similares de la misma persona … mmm …
¿que predicciones se generaron en los otros modelos?. Habiendo construido modelos de basados en los algoritmos de regresión logística binaria y árbol de regresión, en estos las predicciones fueron de que ‘YES’ si tiene daño al corazón.
Pendiente