Aprendizaje de maquinas -- R -- Clasificación usando k-Vecinos Cercanos (k-Nearest Neighbors).

Notas de clase sobre aprendizaje de maquinas usando R

Juan David Velásquez Henao
jdvelasq@unal.edu.co
Universidad Nacional de Colombia, Sede Medellín
Facultad de Minas
Medellín, Colombia

[Licencia]

[Readme]

Software utilizado.

Este es un documento interactivo escrito como un notebook de Jupyter, en el cual se presenta un tutorial sobre regresión logistica usando R en el contexto de aprendizaje de maquinas. Los notebooks de Jupyter permiten incoporar simultáneamente código, texto, gráficos y ecuaciones. El código presentado en este notebook puede ejecutarse en los sistemas operativos Linux y OS X.

Haga click aquí para obtener instrucciones detalladas sobre como instalar Jupyter en Windows y Mac OS X.

Haga clic [aquí] para ver la última versión de este documento en nbviewer.

Descargue la última versión de este documento a su disco duro; luego, carguelo y ejecutelo en línea en Try Jupyter!

Haga clic aquí para ver el tutorial de visualización y gráficas.

Contenido

Bibliografía.

Material complementario.

Webinar RStudio Getting your data into R


Introducción

Contenido

El problema de clasificación consiste en predecir una clase desconocida a la que pertenece una observación a través de un algoritmo clasificador construido utilizando un conjunto de datos en donde la clase se conoce de antemano.

Por ejemplo, suponga que ha recolectado datos acerca de los hábitos de salud en la ciudad de Medellín para una polación homogenea, donde para la mitad de la muestra se sabe sí han desarrollado cierto tipo de enfermedad en una ventana de tiempo. Para la otra mitad la cual no se tiene información se busca predecir si presentarán dicha enfermedad a partir de sus características y similitudes con la población que sí presentó dicha enferemedad. Una de las técnicas que se pueden utilizar para este tipo de problemas es k-Nearest Neighbors (k-NN)

k-Vecinos más cercanos k-NN

Utilizando el mismo concepto de matriz de distancias que se introdujo en el Notebook de Métodos de Clustering, usado por el método k-Means, k-NN selecciona un número pre-definido de observaciones cercanas a otras (vecinos) para clasificar.

En este método, tanto los atributos como la variable respuesta pueden ser categóricos o numéricos.

El método predice la clasificación de una observación desconocida como la mayoría de los votos de los vecinos, es decir, la clase más frecuente entre las k observaciones más cercanas. Esto quiere decir que la clasificación dependerán del número de vecinos que se escoge a través de la matriz de distancias.

Dentro de este cápitulo, siempre asuma medidas euclidianas a no ser que se especifique lo contario.

Aplicación Iris

Contenido

En este ejemplo realice la clasificación de la base de datos iris a través de este métodos. Los datos contienen 3 clases con 50 diferentes observaciones donde cada una se refiere a una clase diferente de planta iris. El objetivo es predicir la clase de tipo de planta.

Para esto primero calcule la matriz de distancias de los atributos de la data de iris.


In [1]:
## Cargue las librerías necesarias
library(reshape2)

In [2]:
## Cargue los datos  
data(iris)                                   # Cargue la data pre-definida en R

## Calcule las distancias euclidianas
distances   <- dist(iris[1:4],               # Datos sin la variable respuesta
                 upper = T,                  # Calcular la diagonal superior de la matriz de distancias
                 diag = T)                   # Calcular la diagonal de la matriz de distancias

distances.df <- melt(as.matrix(distances))   # Melt: Convierte la matriz en columnas con identificador de filas

head(distances.df)                           # Observe la data


Var1Var2value
1 1 0.0000000
2 1 0.5385165
3 1 0.5099020
4 1 0.6480741
5 1 0.1414214
6 1 0.6164414

Calcule las k observaciones más cercanas a cada observación y asigne un valor a cada observación sin clasificar a partir de la mayoría de votos.


In [3]:
## Establezca los parámetros del k-NN

k             <- 5                                               # Número de vecinos
N             <- length(levels(as.factor(distances.df$Var2)))    # Longitud de las observaciones
Nearest       <- matrix(nrow= N, ncol = k)                       # Matriz N por k
level_count   <- length(levels(as.factor(iris[[5]])))            # Longitud del número de clases
classif       <- rep(0,N)                                        # Vector de clasificación final

## Ciclos para calcular los k-NN

for (i in 1:N) {
    # Subset de la observación i
    temp <- subset(distances.df,                                 # Extrae subconjunto de datos
                  Var2 == i)                                     # Observacion i
    
    # Extraccion de los k vecinos más cercanos
    nearest <- unlist(head(temp[order(temp$Var2,temp$value),],   # Ordena los de mayor cercanía con i
                          k)[1])                                 # Extrae los k con mayor cercanía
    # Obtención de los votos
    votes   <- iris[0,5]                                         # Extrae las clasificaciones de todas las observaciones
    
    for (j in 1:length(nearest)) {
        
        votes[j]   <- iris[5][nearest[j],]                       # Extrae las clasficaciones de las k más cercanas
        
        classif[i] <- which.max(table(votes))                    # Obtiene la clase de mayor votos
    }
}

head(as.data.frame(classif))                                         
tail(as.data.frame(classif))


classif
1
1
1
1
1
1
classif
1453
1463
1473
1483
1493
1503

A continuación se procede a probar el desempeño del modelo. Puede observar que únicamente 5 observaciones fueron mal clasificadas de 150. Por lo tanto, es indicio que el modelo tiene un buen desemepeño.


In [4]:
## Convierta las clases 1,2,3 a tipo de planta iris

iris$Species_class[classif == 1] = "setosa"
iris$Species_class[classif == 2] = "versicolor"
iris$Species_class[classif == 3] = "virginica"

## Matriz de confusión

table(iris$Species,iris$Species_class)

## Observaciones mal clasificadas

rownames(iris)[iris$Species != iris$Species_class]


            
             setosa versicolor virginica
  setosa         50          0         0
  versicolor      0         47         3
  virginica       0          2        48
  1. '71'
  2. '73'
  3. '84'
  4. '107'
  5. '120'

Aplicación Ozone

Contenido

En este ejemplo, utilizará el método de validación cruzada dejando uno afuera. Para esto, llame a la función knn.cv() incluida en el paquete class donde iterativamente se dejará una observación afuera para evaluación y el resto para entrenamiento.

En este ejemplo, se utilizarán los datos de Ozone el cual contiene 13 atributos y 366 observaciones de mediciones diarias de calidad de aire.


In [5]:
## Instale y cargue las librerías necesarias
library(mlbench)           
library(class)

In [6]:
## Cargue y prepare los datos

data(Ozone)                 # Datos Ozone
Oz <- na.omit(Ozone)        # Quite los datos con NA

head(Oz)


V1V2V3V4V5V6V7V8V9V10V11V12V13
51 5 1 5 5760 3 51 54 45.321450 25 57.02 60
61 6 2 6 5720 4 69 35 49.641568 15 53.78 60
71 7 3 4 5790 6 19 45 46.402631 -33 54.14100
81 8 4 4 5790 3 25 55 52.70 554 -28 64.76250
91 9 5 6 5700 3 73 41 48.022083 23 52.52120
121 12 1 6 5720 3 44 51 54.32 111 9 63.14150

Para propositos del estudio, codifique aquellas obseraciones que se calcularon entre Abril y Septiembre como 1 y el resto 0. Existen 92 observaciones entre Abril y Septiembre.


In [7]:
## Recodificación de Mes de Captura

Oz$AprilToSeptember <- rep(0,length(Oz[,1]))                                 # Crea columna nueva rellena con 0

Oz$AprilToSeptember[as.numeric(Oz[[1]])>=4 & as.numeric(Oz[[1]])<=9] = 1    # Si el mes se encuentra entre 4 y 9, coloque 1

Para observar la importancia de la validación cruzada, estime primero el modelo sin mejoramiento y luego estimelo con cross validation.


In [8]:
## Clasificacion con modelo knn sin CV
Oz$classif <- knn(Oz[2:13],     # Features de la data
                 Oz[2:13],      # Features de la data
                 Oz[[14]],      # Target de la data
                 4)             # k=4

## Matriz de Confusión
table(Oz$classif,               # Predicciones por knn
      Oz[[14]])                 # Valores reales


   
     0  1
  0 93 20
  1 18 72

Ahora se estima con leave-one-out cross validation.


In [9]:
## Modelo knn con validación cruzada.

Oz$classif2 <- knn.cv(Oz[2:13],# Features de la data
                     Oz[[14]], # Target de la data
                     4)        # k=4

## Matriz de Confusión
table(Oz$classif2,             # Predicciones por knn
      Oz[[14]])                # Valores reales


   
     0  1
  0 79 28
  1 32 64

Note que aunque se realizó la validación cruzada dejando uno afuera, el porcentaje de clasificaciones erroeneas aumentó. Para mejorar esto, se utiliza un algoritmo que seleccione de forma óptima el k.

Una forma simple de estimar k es la raíz cuadrada del número de observaciones, no obstante, no siempre arroja los mejores resultados. Para esto, se escoge k de tal forma que maximice cierta medida de desempeño a través de una búsqueda iterativa. En este ejemplo, se busca máximar la precisión.


In [10]:
## Vector de precisiones
Accur <- rep(0,20)                                     # Incialice el vector

## Ciclo para calcular la precisión
for (i in 1:20) {
    classification = knn.cv(Oz[2:13],Oz[[14]], i)      # Modelo knn.cv con k=i
    Accur[i] = sum(classification == Oz[[14]])/203     # Precisión del modelo con k=i
}

## Calcule el máximo k
which.max(Accur)


3

Por lo tanto, el k de vecinos cercanos que maximiza la precisión es 3.


In [11]:
# Modelo knn = 3
Oz$classif3 <- knn(Oz[2:13],     # Features de la data
                 Oz[2:13],       # Features de la data
                 Oz[[14]],       # Target de la data
                 3)              # k=4

# Matriz de Confusión
table(Oz$classif3,               # Predicciones por knn
      Oz[[14]])                  # Valores reales


   
     0  1
  0 92 12
  1 19 80

Ejercicio.-- Utilice la base de datos de carros que provee UCI Machine Learning data sets para realizar un modelo de k-Vecinos más Cercanos para predecir la aceptabilidad del carro. Recuerde realizar medidas de desempeño y determinar el k óptimo dependidendo de la medida que considere más importante.

Datos


In [ ]:


Ejercicio.-- Se cuentan con los datos de los crimenes de la ciudad de San Francisco y se busca realizar un modelo de clasificación para la categoría del incidente crimen a partir de las variables dadas.

El modelo de k-Vecinos más Cercanos se ajusta a lo que necesita. Por lo tanto, realice el ajuste del modelo con una validación cruzada para mejorar la precisión, encontrar el k óptimo y medidas de evaluación para tomar una decisión mas acertada.

Datos


In [ ]: