En este paso, cargamos los datos, revisamos si existen datos
faltantes, eliminamos la variable Hogar
, convertimos en
factor la variable objetivo y estandarizamos las varibles
predictoras.
1. Cargar datos
# Cargar datos:
propietarios_data <- read.csv("Propietarios.csv")
2. Explorar datos
# Visualizar datos
head(propietarios_data)
## Hogar Ingreso Tamaño Clase
## 1 1 60.0 18.4 Propietario
## 2 2 85.5 16.8 Propietario
## 3 3 64.8 21.6 Propietario
## 4 4 61.5 20.8 Propietario
## 5 5 87.0 23.6 Propietario
## 6 6 110.1 19.2 Propietario
# Observar características de las variables
str(propietarios_data)
## 'data.frame': 24 obs. of 4 variables:
## $ Hogar : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Ingreso: num 60 85.5 64.8 61.5 87 ...
## $ Tamaño : num 18.4 16.8 21.6 20.8 23.6 19.2 17.6 22.4 20 20.8 ...
## $ Clase : chr "Propietario" "Propietario" "Propietario" "Propietario" ...
# Revisar los datos detalladamente
library(skimr)
skimr::skim(propietarios_data)
Name | propietarios_data |
Number of rows | 24 |
Number of columns | 4 |
_______________________ | |
Column type frequency: | |
character | 1 |
numeric | 3 |
________________________ | |
Group variables | None |
Variable type: character
skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
---|---|---|---|---|---|---|---|
Clase | 0 | 1 | 11 | 14 | 0 | 2 | 0 |
Variable type: numeric
skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
---|---|---|---|---|---|---|---|---|---|---|
Hogar | 0 | 1 | 12.50 | 7.07 | 1 | 6.75 | 12.5 | 18.25 | 24.0 | ▇▇▆▇▇ |
Ingreso | 0 | 1 | 68.44 | 19.79 | 33 | 52.35 | 64.8 | 83.10 | 110.1 | ▃▇▅▆▂ |
Tamaño | 0 | 1 | 18.95 | 2.43 | 14 | 17.50 | 19.0 | 20.80 | 23.6 | ▂▇▆▇▃ |
3. Eliminar variable Hogar
Hogar
parece ser un indentificador y actúa como un
número de casa nada más. Para reducir el ruido, la eliminamos del
modelo.
library(dplyr)
propietarios_data <- propietarios_data %>%
select(-Hogar)
4. Convertir en factor la variable objetivo
propietarios_data$Clase <- as.factor(propietarios_data$Clase)
5. Estandarizar variables predictoras
Este modelo es sensible a escalas, así que es beneficioso que las variables predictoras contribuyan de manera equilibrada al modelo.
# Estandarizar
propietarios_data <- propietarios_data %>%
mutate(
Ingreso = scale(Ingreso),
Tamaño = scale(Tamaño)
)
Dividimos los datos en conjuntos aleatorios de de entrenamiento y prueba. Como tenemos pocos datos, entendemos que k = 3 es suficiente. Separaremos los datos en 3 grupos, 2 de entrenamiento y 1 de prueba. De esta forma, nos aseguramos que el conjunto de entrenamiento tenga alrededor de un 75% de los datos y el conjunto de prueba un 25%.
# Crear conjuntos
set.seed(2025)
library(caret)
k <- 3 # Guardar el valor de k
folds <- createFolds(propietarios_data$Clase, k = k)
entrenamiento <- propietarios_data[-folds[[k]],]
prueba <- propietarios_data[folds[[k]],]
# Crear etiquetas
entrenamiento_etiquetas <- propietarios_data$Clase[folds[[k]]]
prueba_etiquetas <- propietarios_data$Clase[folds[[k]]]
Ver cantidad de conjuntos
dim(entrenamiento)[1]
## [1] 16
dim(prueba)[1]
## [1] 8
A continuación, aplicamos el modelo SVM con kernel radial y realizamos un ajuste de parámetros usando validación cruzada para encontrar los mejores valores de cost y gamma.
library(e1071)
set.seed(2025)
svm_vc <- tune("svm", Clase ~ ., data = entrenamiento, kernel = "radial", scale = FALSE,
ranges = list(cost = c(0.001, 0.01, 0.1, 1, 5, 10, 20),
gamma = c(0.5, 1, 2, 3, 4, 5, 10)))
# Mejores parámetros
svm_vc$best.parameters
## cost gamma
## 6 10 0.5
Podemos observar que de todos los rangos estudiados, el modelo con el menor error es con los hiperparámetros de cost = 10 y gamma = 0.5. A continuación, guardaremos estos resultados del mejor modelo.
mejor_modelo <- svm_vc$best.model
mejor_modelo
##
## Call:
## best.tune(METHOD = "svm", train.x = Clase ~ ., data = entrenamiento,
## ranges = list(cost = c(0.001, 0.01, 0.1, 1, 5, 10, 20), gamma = c(0.5,
## 1, 2, 3, 4, 5, 10)), kernel = "radial", scale = FALSE)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: radial
## cost: 10
##
## Number of Support Vectors: 13
Adicionalmente en el siguiente paso, aplicamos la validación cruzada manual para SVM y validar la estabilidad del modelo. En cada iteración, se entrenó el modelo con dos folds y se probó con el otro fold. Se calculó la exactitud de clasificación para cada fold y luego se obtuvo el promedio de exactitud.
# Guardar la excatitud de cada fold
exactitud <- numeric(length = k)
# Validación cruzada manual
for(i in 1:k){
# Dividir los datos en conjunto y prueba
entrenamiento <- propietarios_data[-folds[[i]],]
prueba <- propietarios_data[folds[[i]],]
# Crear etiquetas
entrenamiento_etiquetas <- propietarios_data$Clase[folds[[i]]]
prueba_etiquetas <- propietarios_data$Clase[folds[[i]]]
# Entrenar modelo SVM con parámetros óptimos
modelo_svm <- svm(Clase ~ ., data = entrenamiento, kernel = "radial",
cost = 10, gamma = 0.5)
# Predecir
pred_svm <- predict(modelo_svm, newdata = prueba)
# Evaluar la exactitud del modelo en cada fold
cm <- confusionMatrix(pred_svm, prueba$Clase)
exactitud[i] <- cm$overall["Accuracy"]
# Mostrar resultado del fold
cat("Fold", i, "- Exactitud:", exactitud[i], "\n")
}
## Fold 1 - Exactitud: 0.625
## Fold 2 - Exactitud: 0.75
## Fold 3 - Exactitud: 0.875
Esto nos permite ver lo consistente que es nuestro modelo en distintas particiones. Cabe destacar que el proceso se intentó con k = 4, y la exactitud del modelo empeoró, lo cual pudimos concluir que el modelo pueda ser muy sensible a particiones.
# Exactitud promedio de validación cruzada
Exactitud_promedio <- round(mean(exactitud),4)*100
paste("Exactitud_promedio: ",Exactitud_promedio,"%",sep="")
## [1] "Exactitud_promedio: 75%"
En promedio, el modelo acierta el 75% de las veces en los conjuntos de prueba de cada fold, lo cual mostró un rendimiento aceptable.
En el siguiente paso, vemos las predicciones obtenidas de este modelo. Utlizamos el mejor modelo para predecir las clases de todo el conjunto de datos. Después generamos una matriz de confusión para comparar las predicciones con las etiquetas reales.
# Hacer prediccion con el mejor modelo
pred_svm1 <- predict(mejor_modelo, newdata = propietarios_data)
# Matriz de confusión
MC1 <- table(pred_svm1, propietarios_data$Clase)
Matriz de confusión
# Tasa de aciertos
total <- sum(MC1)
TA1 <- sum(MC1[1,1]+MC1[2,2])/total
TA1
## [1] 0.875
Tasa de aciertos
La tasa de aciertos fue de 83% en el conjunto de prueba.
Interpretación de Resultados
Notamos que la validación cruzada en el paso 4 nos dio una exactitud más baja (75%) en comparación con la tasa de aciertos final del modelo (83%). Esto se debe a que la validación cruzada se realiza sobre distintos subconjuntos de los datos y simula cómo se comportaría el modelo con diferentes particiones de datos.