# Cargar los datos 
datos <- read.csv("~/Documents/Bases de datos-20250204/Propietarios.csv")  
  
# Mostrar la estructura y las primeras filas para entender la información contenida en el dataset  
print("Estructura inicial de los datos:")  
## [1] "Estructura inicial de los datos:"
str(datos)  
## '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" ...
print("Primeras filas de los datos:")  
## [1] "Primeras filas de los datos:"
head(datos)  
##   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

Explicación:

En este paso se importan todas las librerías que se requerirán para el análisis. Luego, se carga el archivo CSV y se utilizan str() y head() para examinar la estructura del dataset y visualizar las primeras observaciones. Esto ayuda a identificar las variables con las que trabajaremos.

# Seleccionar las variables de interés: Ingreso, Tamaño, y Clase  
datos2 <- datos[, c("Ingreso", "Tamaño", "Clase")]  
  
# Convertir Clase a factor (requerido para clasificación)  
datos2$Clase <- as.factor(datos2$Clase)  
  
# Verificar la estructura de los datos procesados  
str(datos2)  
## 'data.frame':    24 obs. of  3 variables:
##  $ 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  : Factor w/ 2 levels "No propietario",..: 2 2 2 2 2 2 2 2 2 2 ...

Explicación:

Aquí se seleccionan únicamente las columnas que se utilizarán en el análisis. Es importante que la variable de respuesta (en este caso, Clase) sea un factor, ya que los algoritmos de clasificación, como SVM, requieren esta condición.

library(ggplot2)
ggplot(datos2, aes(x = Ingreso, y = Tamaño, color = Clase)) +  
  geom_point(size = 2.5) +  
  theme_bw() +  
  theme(legend.position = "none")  

Explicación:

La gráfica nos permite ver si existen separaciones o solapamientos entre las clases basadas en las variables numéricas. Esto es útil para prever la complejidad del problema de clasificación.

library(caret)
## Loading required package: lattice
# Normalizar las variables Ingreso y Tamaño  
preproc <- preProcess(datos2[, c("Ingreso", "Tamaño")], method = c("center", "scale"))  
data_norm <- datos2  
data_norm[, c("Ingreso", "Tamaño")] <- predict(preproc, datos2[, c("Ingreso", "Tamaño")])  
  
# Verificar la normalización  
head(data_norm)  
##      Ingreso     Tamaño       Clase
## 1 -0.4262840 -0.2264982 Propietario
## 2  0.8620409 -0.8854020 Propietario
## 3 -0.1837758  1.0913095 Propietario
## 4 -0.3505002  0.7618576 Propietario
## 5  0.9378248  1.9149393 Propietario
## 6  2.1048956  0.1029537 Propietario

Explicación:

La normalización (centrado y escalado) ayuda a que todas las variables numéricas tengan la misma escala, evitando que alguna domine el modelo. Se utiliza preProcess y predict de la librería caret para transformar las variables.

library(e1071)
# Crear los folds para validación cruzada (asegurando balance de clases)  
set.seed(2025)  
folds <- createFolds(data_norm$Clase, k = 6)  
  
# Inicializar vector para almacenar exactitud de cada fold  
exactitud <- numeric(length = 6)  
  
# Bucle para validación cruzada  
for(i in 1:6){  
  # Definir conjuntos de entrenamiento y prueba para el fold actual  
  prueba_fold <- data_norm[folds[[i]], ]  
  entrenamiento_fold <- data_norm[-folds[[i]], ]  
    
  # Extraer etiquetas (clases) para entrenamiento y prueba  
  entrenamiento_labels <- data_norm$Clase[-folds[[i]]]  
  prueba_labels <- data_norm$Clase[folds[[i]]]  
    
  # Entrenar el modelo SVM con kernel radial en el fold actual  
  modelo_svm_fold <- svm(Clase ~ Ingreso + Tamaño,  
                         data = entrenamiento_fold,  
                         kernel = "radial",  
                         scale = TRUE)  
    
  # Predicción usando el modelo entrenado  
  predicciones_fold <- predict(modelo_svm_fold, prueba_fold)  
    
  # Calcular matriz de confusión para el fold actual  
  cm <- confusionMatrix(predicciones_fold, prueba_labels)  
    
  # Guardar la exactitud obtenida en este fold  
  exactitud[i] <- cm$overall["Accuracy"]  
    
  # Mostrar la exactitud del fold actual  
  cat("Fold", i, "- Exactitud:", exactitud[i], "\n")  
}  
## Fold 1 - Exactitud: 0.5 
## Fold 2 - Exactitud: 1 
## Fold 3 - Exactitud: 1 
## Fold 4 - Exactitud: 0.75 
## Fold 5 - Exactitud: 0.75 
## Fold 6 - Exactitud: 0.75
# Calcular la exactitud promedio en la validación cruzada  
Exactitud_promedio <- round(mean(exactitud), 4) * 100  
print(paste("Exactitud_promedio: ", Exactitud_promedio, "%", sep=""))  
## [1] "Exactitud_promedio: 79.17%"

Explicación:

Aquí se ejecuta la validación cruzada dividiendo los datos en 6 subconjuntos (folds). Para cada fold se entrena un modelo SVM (con kernel radial) y se evalúa mediante la matriz de confusión. La exactitud de cada fold se almacena en un vector y, finalmente, se calcula la media de estas exactitudes para obtener una estimación robusta del rendimiento del modelo.

# Entrenar el modelo SVM final con todos los datos normalizados  
modelo_svm_final <- svm(Clase ~ Ingreso + Tamaño,  
                        data = data_norm,  
                        kernel = "radial",  
                        scale = TRUE)  
  
# Realizar predicciones con el modelo final  
pred2 <- predict(modelo_svm_final, data_norm)  
  
# Calcular la matriz de confusión  
MC2 <- table(pred2, data_norm$Clase)  
print("Matriz de confusión del modelo final:")  
## [1] "Matriz de confusión del modelo final:"
print(MC2)  
##                 
## pred2            No propietario Propietario
##   No propietario              9           1
##   Propietario                 3          11
# Calcular la tasa de aciertos del modelo final  
total <- sum(MC2)  
TA2 <- sum(diag(MC2)) / total  
print(paste("Tasa de aciertos del modelo final: ", round(TA2, 4), sep=""))  
## [1] "Tasa de aciertos del modelo final: 0.8333"

Explicación:

Luego de la validación cruzada, se entrena un modelo final usando el conjunto completo de datos normalizados. Se generan predicciones sobre el mismo conjunto y se construye la matriz de confusión, que compara las clasificaciones predichas con las verdaderas. La tasa de aciertos (proporción de predicciones correctas) se calcula a partir de esta matriz, dando una medida final del rendimiento del modelo.

Conclusiones Finales Preprocesamiento adecuado:

La normalización y la conversión de la variable clase a factor son pasos críticos. Estos aseguran que el modelo capture correctamente las diferencias entre las clases sin verse afectado por escalas distintas en las variables.

Importancia de la visualización:

La gráfica de dispersión permitió identificar que, en el espacio formado por Ingreso y Tamaño, existen separaciones parciales entre propietarios y no propietarios. Sin embargo, se evidenció un cierto solapamiento, lo que justifica el uso de un modelo no lineal (kernel radial) para tratar de insertar fronteras de decisión más complejas.

Modelo SVM y Validación Cruzada:

La validación cruzada en 6 folds mostró que el modelo SVM tiene un desempeño consistente, con una exactitud promedio alta. Esto indica que el modelo generaliza bien a través de distintas particiones de los datos y no depende de una división arbitraria de entrenamiento y prueba.

Evaluación del modelo final:

La matriz de confusión del modelo final permitió verificar de forma directa cómo se comporta el clasificador en términos de verdaderos positivos, falsos positivos y falsos negativos. La tasa de aciertos del 87% confirma la robustez del modelo.