La Suppor Vector Machine (SVM, por sus siglas en inglés) es un algoritmo de aprendizaje automático supervisado, usado fundamentalmente para clasificación, aunque es posible su aplicación para regresión.
En SVM, los datos se representan como puntos en un espacio n-dimensional donde cada dimensión representa una variable. La idea básica de este algoritmo es encontrar un hiperplano que divida de la mejor manera posible un conjunto de datos en clases.
En las imágenes anteriores, la Figura 16.1(a) y la Figura 16.1(b) representan malas decisiones porque están separando las dos clases con márgenes desiguales, lo que aumenta las probabilidades de una clasificación errónea. No obstante, la Figura 16.1(c) clasifica correctamente las dos clases con un hiperplano que tiene márgenes iguales.
Por lo tanto, el proceso de hallar el hiperplano correcto para la clasificación con la ayuda de los vectores de soporte —es decir, los puntos de cada clase situados en el margen— es el principio básico de este algorítmo.
La Figura 16.2 muestra todos los componentes de una Máquina de Vectores de Soporte (SVM).
Para llevar a cabo un proceso de clasificación basado en SVM, se requieren los paquetes caret y kernlab, además de otros paquetes para el análisis ráster, el procesamiento en paralelo y la visualización de rásteres. Paquetes necesarios
library(tidyverse) # Para el manejo de bases de datos
## Warning: package 'tidyverse' was built under R version 4.3.2
## Warning: package 'readr' was built under R version 4.3.2
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.2.0 ✔ readr 2.1.5
## ✔ forcats 1.0.1 ✔ stringr 1.6.0
## ✔ ggplot2 4.0.2 ✔ tibble 3.3.1
## ✔ lubridate 1.9.5 ✔ tidyr 1.3.2
## ✔ purrr 1.2.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(terra) # Para el procesamiento de imágenes en formato ráster
## terra 1.8.93
##
## Attaching package: 'terra'
##
## The following object is masked from 'package:tidyr':
##
## extract
library(RStoolbox) # Para la visualización de imágenes en formato ráster, con ggplot2
## This is version 1.0.2.2 of RStoolbox
library(ggplot2) # Para la visualización de imágenes en formato ráster
library(doParallel) # Para el procesamiento en paralelo
## Loading required package: foreach
##
## Attaching package: 'foreach'
##
## The following objects are masked from 'package:purrr':
##
## accumulate, when
##
## Loading required package: iterators
## Loading required package: parallel
library(caret) # Para la clasificación
## Warning: package 'caret' was built under R version 4.3.3
## Loading required package: lattice
## Warning: package 'lattice' was built under R version 4.3.2
##
## Attaching package: 'caret'
##
## The following object is masked from 'package:purrr':
##
## lift
library(kernlab) # Para implementar SVM
## Warning: package 'kernlab' was built under R version 4.3.3
##
## Attaching package: 'kernlab'
##
## The following objects are masked from 'package:terra':
##
## buffer, size
##
## The following object is masked from 'package:purrr':
##
## cross
##
## The following object is masked from 'package:ggplot2':
##
## alpha
En este ejercicio se utiliza la imagen multibanda y el archivo en
formato *.csv que contiene los mismos datos de muestra (valores de
reflectividad según coberturas de suelo) utilizados en la sección
anterior. Este conjunto también será dividido en un conjunto de prueba y
otro de entrenamiento. Recuérdese que se importa con la función
read.csv2, a la que se añade el argumento
rownames = 1 para convertir la primera columna en nombres
de fila.
df_muestra <- read.csv2("D:/G174_2026/LABORATORIO_7_Clasificacion_imagenes_PIXEL/datos/supervisada/df_muestra.csv", row.names = 1)
Puede verficarse su contenido así:
df_muestra
A continuación, el dataframe df_muestra se dividirá en
dos subconjuntos, uno de entrenamiento (con el 70 % de los casos) y otro
de verificación (con el 30% restante).
# Crear el set de entrenamiento (70%)
df_entrenamiento <- df_muestra %>%
sample_frac(0.7)
# Crear el set de verificación con el resto (30%). Usamos anti_join para asegurar que no se repitan filas
df_verificacion <- df_muestra %>%
anti_join(df_entrenamiento)
## Joining with `by = join_by(categoria, blue, green, red, NIR, SWIR1, SWIR2)`
También se importará la escena Landsat.
imagen <- rast("D:/G174_2026/LABORATORIO_7_Clasificacion_imagenes_PIXEL/datos/supervisada/imagen.tif")
imagen
## class : SpatRaster
## size : 1245, 1497, 7 (nrow, ncol, nlyr)
## resolution : 30, 30 (x, y)
## extent : 594090, 639000, 4190190, 4227540 (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 10N (EPSG:32610)
## source : imagen.tif
## names : coast~rosol, blue, green, red, NIR, SWIR1, ...
## min values : 0.09641791, 0.0748399, 0.04259216, 0.02084067, 0.0008457669, -0.007872183, ...
## max values : 0.73462820, 0.7177562, 0.69246972, 0.78617686, 1.0124315023, 1.043204546, ...
Tras la partición de los datos de muestra, se aplicará el algoritmo SVM sobre los datos de entrenamiento. Todo el proceso se ejecutará en modo de procesamiento en paralelo. Esta última es una técnica de computación que consiste en dividir una tarea grande y pesada en partes más pequeñas para que se ejecuten al mismo tiempo utilizando varios procesadores o núcleos del ordenador. En lugar de hacer las tareas secuencialmente, el modo paralelo abre “varias ventanillas” para trabajar simultáneamente. Para ello aplicamos las siguientes funciones:
mc <- makeCluster(detectCores()) # Pregunta al sistema operativo el número de núcleos y crea "copias" que se ejecutan en segundo plano.
registerDoParallel(mc) # "conecta" el equipo que acabas de crear con las funciones que van a realizar el trabajo pesado
Para obtener los parámetros utilizados para el entrenamiento del
modelo se aplica la función caret::trainControl() del
paquete caret. La función se acompaña de los siguientes argumentos:
method: argumento que asigna el método de
remuestreo, en este caso “repeatedcv”, que divide repetidamente los
datos de entrenamiento en k-particiones (k-folds) para validación
cruzada.
number: número de particiones.
repeats: número de iteraciones.
allowParallel: TRUE señala que se está ejecutando el
código mediante procesamiento en paralelo.
tune_par <- trainControl(method = "repeatedcv",
number = 10,
repeats = 5,
allowParallel=TRUE )
El entrenamiento del modelo SVM utiliza función
caret::train con los siguientes argumentos:
method: asigna el algoritmo específico para SVM, que
en este caso es la función de Núcleo de Base Radial (Radial Basis
Kernel). Existen otras funciones como la lineal, mínimos cuadrados,
exponencial, polinómica, etc. La lista de estas funciones, junto con sus
respectivos nombres de cadena de texto para el argumento method, están
disponibles en el sitio web: https://topepo.github.io/caret/train-models-by-tag.html#Support_Vector_Machines.
metric: métrica de resumen que se utilizará para la
selección del modelo óptimo, en este caso se utiliza el método
“Accuracy” (Precisión).
trControl: parámetros de ajuste.
svm_model <- train(categoria~.,
data=df_entrenamiento,
method = "svmRadial",
metric = "Accuracy",
trControl = tune_par)
svm_model
## Support Vector Machines with Radial Basis Function Kernel
##
## 140 samples
## 6 predictor
## 5 classes: 'abierto', 'agua', 'barbecho', 'cultivos', 'urbano'
##
## No pre-processing
## Resampling: Cross-Validated (10 fold, repeated 5 times)
## Summary of sample sizes: 126, 125, 125, 127, 125, 125, ...
## Resampling results across tuning parameters:
##
## C Accuracy Kappa
## 0.25 0.9602903 0.9442498
## 0.50 0.9832326 0.9767028
## 1.00 0.9845659 0.9786830
##
## Tuning parameter 'sigma' was held constant at a value of 1.248511
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were sigma = 1.248511 and C = 1.
Tras el entrenamiento del modelo, el procesamiento en paralelo puede detenerse utilizando la función stopCluster.
stopCluster(mc)
Los atributos del modelo SVM obtenido muestran el resumen del modelo y los valores de los parámetros de coste (C) y sigma.
El parámetro de coste (C) indica el coste por la
violación de las restricciones (el equilibrio entre el error y el
margen). Si es muy alto, el modelo intentará no cometer errores en el
entrenamiento, pero podría no generalizar bien (overfitting).
El parámetro Sigma indica la inversa del ancho del
núcleo (kernel) para la función de base radial. Define cuánto alcance
tiene un solo punto de entrenamiento; valores grandes significan que el
punto tiene poca influencia a larga distancia
Una vez obtenido el modelo sobre el conjunto de datos de entrenamiento, se procede a la predicción de los valores del conjunto de datos de entrenamiento para la evaluación de la precisión.
Ahora, predeciremos los valores clasificados utilizando el modelo desarrollado sobre el conjunto de datos de entrenamiento para la evaluación de la precisión.
predicciones_entrenamiento <- predict(svm_model,
df_entrenamiento)
Para la evaluación de la precisión (rendimiento del modelo SVM) se
utiliza la función caret::confusionMatrix(), que
proporciona la matriz de confusión, estadísticas globales y estadísticas
por clase.
# Asegurar que la referencia sea factor
df_entrenamiento$categoria <- as.factor(df_entrenamiento$categoria)
# Forzar a las predicciones a ser factor con los MISMOS niveles que la referencia
predicciones_entrenamiento <- factor(predicciones_entrenamiento,
levels = levels(df_entrenamiento$categoria))
confusionMatrix(predicciones_entrenamiento, df_entrenamiento$categoria)
## Confusion Matrix and Statistics
##
## Reference
## Prediction abierto agua barbecho cultivos urbano
## abierto 36 0 0 0 0
## agua 0 59 0 0 0
## barbecho 0 0 12 0 0
## cultivos 0 0 0 13 0
## urbano 0 0 0 0 20
##
## Overall Statistics
##
## Accuracy : 1
## 95% CI : (0.974, 1)
## No Information Rate : 0.4214
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 1
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: abierto Class: agua Class: barbecho Class: cultivos
## Sensitivity 1.0000 1.0000 1.00000 1.00000
## Specificity 1.0000 1.0000 1.00000 1.00000
## Pos Pred Value 1.0000 1.0000 1.00000 1.00000
## Neg Pred Value 1.0000 1.0000 1.00000 1.00000
## Prevalence 0.2571 0.4214 0.08571 0.09286
## Detection Rate 0.2571 0.4214 0.08571 0.09286
## Detection Prevalence 0.2571 0.4214 0.08571 0.09286
## Balanced Accuracy 1.0000 1.0000 1.00000 1.00000
## Class: urbano
## Sensitivity 1.0000
## Specificity 1.0000
## Pos Pred Value 1.0000
## Neg Pred Value 1.0000
## Prevalence 0.1429
## Detection Rate 0.1429
## Detection Prevalence 0.1429
## Balanced Accuracy 1.0000
Ahorase valida el modelo SVM en el conjunto de datos de verificación
predicciones_verificacion <- predict(svm_model,
df_verificacion)
Para la evaluación de la precisión en el conjunto de datos de verificación
# Asegurar que la referencia sea factor
df_verificacion$categoria <- as.factor(df_verificacion$categoria)
# Forzar a las predicciones a ser factor con los MISMOS niveles que la referencia
predicciones_verificacion <- factor(predicciones_verificacion,
levels = levels(df_verificacion$categoria))
confusionMatrix(predicciones_verificacion, df_verificacion$categoria)
## Confusion Matrix and Statistics
##
## Reference
## Prediction abierto agua barbecho cultivos urbano
## abierto 21 0 0 0 0
## agua 0 19 0 0 0
## barbecho 0 0 9 0 0
## cultivos 0 0 0 6 0
## urbano 0 0 0 0 5
##
## Overall Statistics
##
## Accuracy : 1
## 95% CI : (0.9404, 1)
## No Information Rate : 0.35
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 1
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: abierto Class: agua Class: barbecho Class: cultivos
## Sensitivity 1.00 1.0000 1.00 1.0
## Specificity 1.00 1.0000 1.00 1.0
## Pos Pred Value 1.00 1.0000 1.00 1.0
## Neg Pred Value 1.00 1.0000 1.00 1.0
## Prevalence 0.35 0.3167 0.15 0.1
## Detection Rate 0.35 0.3167 0.15 0.1
## Detection Prevalence 0.35 0.3167 0.15 0.1
## Balanced Accuracy 1.00 1.0000 1.00 1.0
## Class: urbano
## Sensitivity 1.00000
## Specificity 1.00000
## Pos Pred Value 1.00000
## Neg Pred Value 1.00000
## Prevalence 0.08333
## Detection Rate 0.08333
## Detection Prevalence 0.08333
## Balanced Accuracy 1.00000
El resultado muestra que la precisión del modelo SVM es bastante buena. Por lo tanto, este modelo se utiliza para la clasificación de la imagen de satélite
raster_svm <- predict(imagen, svm_model)
raster_svm # Muestra los atributos
## class : SpatRaster
## size : 1245, 1497, 1 (nrow, ncol, nlyr)
## resolution : 30, 30 (x, y)
## extent : 594090, 639000, 4190190, 4227540 (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 10N (EPSG:32610)
## source(s) : memory
## categories : class
## name : class
## min value : abierto
## max value : urbano
Para que ggR funcione correctamente con categorías (caracteres) y respete los nombres de las clases en la leyenda, primero debemos convertir los valores del ráster en factores.
Conversión del ráster en factor para que reconozca las etiquetas
(asumiendo que los niveles están en el mismo orden en
df_entrenamiento.
clases_nombres <- levels(as.factor(df_entrenamiento$categoria))
levels(raster_svm) <- data.frame(ID = 1:length(clases_nombres), categoria = clases_nombres)
Representación con ggR
ggR(raster_svm, geom_raster = TRUE) +
ggtitle("Ejemplo de clasificación con SVM") +
labs(x = "Longitud", y = "Latitud") +
theme(plot.title = element_text(hjust = 0.5, size = 24),
axis.title = element_text(size = 20),
legend.key.size = unit(1, "cm"),
legend.title = element_text(size = 20),
legend.text = element_text(size = 15)) +
# Usamos scale_fill_manual para asignar colores fijos a categorías de texto
scale_fill_manual(values = c("grey", "blue", "wheat", "darkgreen", "red", "skyblue"),
name = "Clase",
labels = clases_nombres)