El método nearest neighbours es útil en clasificación
computer vision
recomendaciones algorítmicas
detección de genes
Hay información más detallada en el apartado de generalidades
kNN es un algoritmo sencillo, pero poco sofisticado - \(k\) hace referencia al número de “vecinos” que se utiliza.
Básico
el modelo se construye durante la fase de predicción
menos sensible al ruido
sensible a outliers
peor rendimiento en espacios multidimensionales
La clasificación se realiza midiendo la distancia entre observaciones no categorizadas e infieriendo sus clases por sus vecinos más cercanos
La función knn entrena el modelo y hace las predicciones en un mismo tiempo
knn(train, # el modelo de entrenamiento test, # los datos de prueba cl, # las etiquetas de 'train'k =1) # el número de 'vecinos' que se consideran
k-NN coloca cada elemento utilizando las coordenadas de las características a analizar, y mide la distancia Euclidea entre los distintos elementos. Para los elementos \(p\) y \(q\) con características \(p_{i}\) y \(q_{i}\):
Si utilizamos \(k = 1\), el elemento se clasifica respecto a su vecino más cercano; sin embargo, si utilizamos \(k = 3\), considera los tres vecinos más cercanos y los clasifica según el que sea más numeroso (o el más próximo en caso de que sean distintos).
Valores de \(k\) muy altos tiende a ignorar patrones pequeños - hay un seso de clasificar todo como el elemento más numeroso. Hay estrategias que ponderan el peso de los vecinos en función de otros parámetros, como su distancia.
Valores de \(k\) muy pequeños son más sensibles al ruido, y hacen más fácil una clasificación incorrecta.
Valor de k
Una recomendación habitual es empezar con la raíz cuadrada del número de elementos de entrenamiento, \(\sqrt{n}\).
Preparar los datos
Lo primero que hay que hacer es eliminar las variables de identificación, que no son relevantes para el análisis, y separar las variables que tienen que ver con el diagnóstico (aunque esto debe hacerse una vez separadas las muestras de entrenamiento y prueba)
Los datos deben estar normalizados para que pueda generarse un modelo útil; por ejemplo, si una variable va del 1 al 10 y otra del 1 a 1.000, esta última siempre tendrá más peso al calcular las distancias.
Estrategias de normalización
Min-max
Convierte los valores de un rango en un número entre el 0 y el 1.
Es menos robusta porque las muestras de prueba sobre las que se aplica el modelo pueden tener valores fuera del rango que hemos utilizado durante el entrenamiento.
Puntación escalar o z-score
Es un método más robusto porque asume que los nuevos datos proceden de la misma distribución normal, y por tanto comparte las mismas características.
\[
X_{new} = \frac{X - \mu}{\sigma}
\]
Variables categóricas
Se convierten en \(0\) y \(1\); en caso de que sea una variable con varias categorías, cada una de ellas se convierte en una variable binomial. La versión denominada dummy coding genera menos problemas en modelos lineales, aunque one-hot encoding suele usarse en machine learning.
Dummy coding
Templado
Caliente
Frío
0
0
Templado
1
0
Caliente
0
1
One-hot encoding
Frío
Templado
Caliente
Frío
1
0
0
Templado
0
1
0
Caliente
0
0
1
Lazy learning
Los algoritmos de clasificación se consideran “lazy” porque no existe abstracción ni generalización, y por tanto no pueden considerarse aprendizaje.
El modelo almacena los datos de entrenamiento y después los compara con los datos nuevos. No se construye ningún modelo, no se parametriza, y por tanto se considera machine learning no paramétrico
Datos de entrenamiento
Hay que generar una base de datos de entrenamiento y otra de prueba; lo mejor es separar el data frame utilizando algunas columnas. Para generar los dato de entrenamiento se debería elegir una muestra aleatoria de la muestras original.
En caso de que la muestra ya estuviese aleatorizada, bastaría con seleccionar unporcentaje de casos:
training <- original[1:75]testing <- original[76:100]
En los casos en los que esto no es así, hay otras estrategias como la que ofrece sample.split del paquete caTools.
Acepta un vector factorizado y un porcentaje, y devuelve un vector Booleano con una selección de casos que resepta la proporción original de la muestra.
Por ejemplo, dado una base de datos disease con una variable $diagnosis sobre la cuál queremos clasificar los grupos, haríamos:
index <- caTools::sample.split(disease$diagnosis, 0.75)training_data <- disease[index,] # 75% de la muestratest_data <- disease[!index,] # 25% de la muestra
Entrenamiento del modelo
Hay distintos paquetes que incluyen kNN, pero en este caso utilizaremos el paquete class.
kNN - sintaxis
training_data y testing_datano deberían contener la variable que contiene la clasificación.
training_data_classes es la variable de clasificación de los datos de entrenamiento (es bueno guardar las dos para poder comparar)
library(class)training_data_classes <- training_data$idtraining_data <- training_data[,-1]testing_data_classes <- testing_data$idtesting_data <- testing_data[,-1]modelo <-knn(train = training_data,test = testing_data,clstu = training_data_classes,k = número de vecinos)
class hace referencia al vector factorizado en los que se pretenden clasificar los datos.
library(class) # kNNlibrary(gmodels) # CrossTablelibrary(caTools) # sample.split aleatoriooriginal_data <-read.csv("data/wisc_bc_data.csv")# Eliminamos id o variables irrelevantesoriginal_data <- original_data[-1]# Generamos training y testing datai <- caTools::sample.split(original_data$diagnosis, 0.75)trn_data <- original_data[i,]tst_data <- original_data[-i,]# Eliminamos las clasestrn_labels <- trn_data$diagnosistrn_data <- trn_data[-1]tst_labels <- tst_data$diagnosistst_data <- tst_data[-1]# Aproximamos un valor útil de k k_value =round(sqrt(length(original_data[,1])))# Generamos la predicciontst_predictions <- class::knn(train = trn_data, test = tst_data,cl = trn_labels,k = k_value)# Y evaluamos los resultados del modelogmodels::CrossTable(x = tst_labels,y = tst_predictions,prop.chisq =FALSE)
Cell Contents
|-------------------------|
| N |
| N / Row Total |
| N / Col Total |
| N / Table Total |
|-------------------------|
Total Observations in Table: 568
| tst_predictions
tst_labels | B | M | Row Total |
-------------|-----------|-----------|-----------|
B | 348 | 8 | 356 |
| 0.978 | 0.022 | 0.627 |
| 0.911 | 0.043 | |
| 0.613 | 0.014 | |
-------------|-----------|-----------|-----------|
M | 34 | 178 | 212 |
| 0.160 | 0.840 | 0.373 |
| 0.089 | 0.957 | |
| 0.060 | 0.313 | |
-------------|-----------|-----------|-----------|
Column Total | 382 | 186 | 568 |
| 0.673 | 0.327 | |
-------------|-----------|-----------|-----------|
K-value en este caso era 24.
Con estandarización
Utilizamos scale() para devolver las puntuaciones escalares; lo ideal es hacer con el con junto inicial de datos pero tenemos que eliminar aquellas variables que no sean numéricas:
library(class) # kNNlibrary(gmodels) # CrossTablelibrary(caTools) # sample.split aleatoriooriginal_data <-read.csv("data/wisc_bc_data.csv")# Eliminamos id o variables irrelevantesoriginal_data <- original_data[-1]# Extraemos las etiquetas...original_labels <- original_data$diagnosis# ... y las eliminamos tambiénoriginal_data <- original_data[-1]# Escalamos las variablesoriginal_data <-scale(original_data)# Generamos training y testing datai <- caTools::sample.split(original_labels, 0.75)trn_data <- original_data[i,]trn_labels <- original_labels[i]tst_data <- original_data[-i,]tst_labels <- original_labels[-i]# Aproximamos un valor útil de k k_value =round(sqrt(length(original_data[,1])))# Generamos la predicciontst_predictions <- class::knn(train = trn_data, test = tst_data,cl = trn_labels,k = k_value)# Y evaluamos los resultados del modeloCrossTable(x = tst_labels,y = tst_predictions,prop.chisq =FALSE)
Cell Contents
|-------------------------|
| N |
| N / Row Total |
| N / Col Total |
| N / Table Total |
|-------------------------|
Total Observations in Table: 568
| tst_predictions
tst_labels | B | M | Row Total |
-------------|-----------|-----------|-----------|
B | 355 | 1 | 356 |
| 0.997 | 0.003 | 0.627 |
| 0.932 | 0.005 | |
| 0.625 | 0.002 | |
-------------|-----------|-----------|-----------|
M | 26 | 186 | 212 |
| 0.123 | 0.877 | 0.373 |
| 0.068 | 0.995 | |
| 0.046 | 0.327 | |
-------------|-----------|-----------|-----------|
Column Total | 381 | 187 | 568 |
| 0.671 | 0.329 | |
-------------|-----------|-----------|-----------|
Buscar k-values alternativos
k-values
Siempre hay que redondear el k-value, tiene que ser un número entero de forma explícita.
Lantz B. Machine learning with R: Learn techniques for building and improving machine learning models, from data preparation to model tuning, evaluation, and working with big data, fourth edition. 4th ed. Place of publication not identified: Packt Publishing; 2023.
9.
Carmona Pontaque F. Álgebra Matricial en Estadística. Análisis Multivariante. Fundació Universitat Oberta de Catalunya; 2024.
10.
Carmona Pontaque F. Modelos lineales. Ediciones de la Universidad de Barcelona; 2004.
11.
Faraway JJ. Linear models with R. Second edition. Boca Raton London: CRC Press, Taylor & Francis; 2014. (Texts in statistical science).