Ejemplo KNN

Equipo 1

3/29/2022

Ejemplo de K-Nearest Neighbor utilizando iris dataset

Pre-procesamiento de datos

data("iris")
head(iris)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa
pairs(iris[,1:4],col=iris[,5],oma=c(4,4,6,12))
par(xpd=TRUE)
legend(0.85,0.6, as.vector(unique(iris$Species)),fill=c(1,2,3))

Resumen de los datos

str(iris)
## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

Se observa que hay 150 objetos de muestra (flores), y 5 parámetros que se utilizan para clasificarlos.

En este ejemplo se busca construir un modelo KNN que pueda predecir la especie de la flor, basandose en el previo conocimiento del largo de sépalo, ancho del sépalo, largo del pétalo y ancho del petalo.

Se crean variables para obtener número aleatorios

set.seed(9850) #Se "desorganizan" los datos 
grupos <- runif(nrow(iris)) #Se obtiene un número aleatorio del 1 al 150

La base de datos está ordenadamente acomodada por especies, lo cual puede ser un inconveniente para “entrenar” al modelo, por lo cual se va a reacomodar la tabla en una nueva base de datos de forma que setosa, versicolor y virginica aparezcan de forma aleatoria.

iris2 <- iris[order(grupos),]
head(iris2)
##     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
## 103          7.1         3.0          5.9         2.1  virginica
## 20           5.1         3.8          1.5         0.3     setosa
## 63           6.0         2.2          4.0         1.0 versicolor
## 17           5.4         3.9          1.3         0.4     setosa
## 83           5.8         2.7          3.9         1.2 versicolor
## 53           6.9         3.1          4.9         1.5 versicolor

Normalización de valores

Se debe hacer una escala de los valores numéricos, para lo cual se tomará en cuenta los mínimos y los máximos de una muestra de los datos

summary(iris[,c(1,2,3,4)])
##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
##  1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
##  Median :5.800   Median :3.000   Median :4.350   Median :1.300  
##  Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
##  3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
##  Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500

Sepal.Lenght = 4.300 - 7.900 Sepal.Width = 2.000 - 4.400 Petal.Lenght = 1.000 - 6.900 Petal.Width = 0.100 - 2.500

Debido a que KNN utiliza funciones de distancia, se busca cierta escala para los valores

normalize <-function(x){
  + return( (x-min(x))/(max(x)-min(x)))
}

Ejemplo de la escala:

normalize(c(1,2,3,4,5))
## [1] 0.00 0.25 0.50 0.75 1.00

Ahora se hace otra base de iris con datos normalizados

irisnuevo <- as.data.frame(lapply(iris2[,c(1,2,3,4)], normalize))

summary(irisnuevo)
##   Sepal.Length     Sepal.Width      Petal.Length     Petal.Width     
##  Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.00000  
##  1st Qu.:0.2222   1st Qu.:0.3333   1st Qu.:0.1017   1st Qu.:0.08333  
##  Median :0.4167   Median :0.4167   Median :0.5678   Median :0.50000  
##  Mean   :0.4287   Mean   :0.4406   Mean   :0.4675   Mean   :0.45806  
##  3rd Qu.:0.5833   3rd Qu.:0.5417   3rd Qu.:0.6949   3rd Qu.:0.70833  
##  Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.00000

Así se ve la nueva base de datos:

head(irisnuevo)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1    0.7777778  0.41666667   0.83050847  0.83333333
## 2    0.2222222  0.75000000   0.08474576  0.08333333
## 3    0.4722222  0.08333333   0.50847458  0.37500000
## 4    0.3055556  0.79166667   0.05084746  0.12500000
## 5    0.4166667  0.29166667   0.49152542  0.45833333
## 6    0.7222222  0.45833333   0.66101695  0.58333333

Creación de train y test dataset

iris_train <- irisnuevo[1:129, ] #Entrenar el modelo
iris_test <- irisnuevo[130:150, ] #Probar el modelo

iris_train_target <- iris2[1:129, 5] #isolar las clases
iris_test_target <- iris2[130:150, 5]

require(class)
## Loading required package: class

Escoger k

Se escoge la cantidad de vecinos cercanos que se tomarán en cuenta

sqrt(150) #150 número de objetos
## [1] 12.24745

Se redondea el resultado a 13, además de tener un número exacto, es conveniente debido a que es un número impar

Aplicar KNN

Se declara una variable que funciona como “predicción”

m1 <- knn(train=iris_train, test=iris_test, cl=iris_train_target, k=13)

m1
##  [1] versicolor setosa     virginica  virginica  virginica  setosa    
##  [7] virginica  versicolor virginica  setosa     setosa     virginica 
## [13] setosa     virginica  virginica  virginica  setosa     virginica 
## [19] virginica  versicolor setosa    
## Levels: setosa versicolor virginica

Se comparan los resultados de los datos reales con los datos obtenidos por medio del modelo, a través de una confusion matrix

matrix <- table(iris_test_target, m1)
matrix
##                 m1
## iris_test_target setosa versicolor virginica
##       setosa          7          0         0
##       versicolor      0          3         2
##       virginica       0          0         9

Verificar que tan preciso es el modelo

La siguiente función va a dividir el número de predicciones correctas entre el número total de predicciones realizadas.

 accuracy <- function(x){sum(diag(x)/(sum(rowSums(x)))) * 100}
 accuracy(matrix)
## [1] 90.47619

Se obtuvo un valor del 90.47%, indicando que el modelo funciona de forma precisa.

Descarga este código

xfun::embed_file("Ejemplo KNN con Iris.Rmd")

Download Ejemplo KNN con Iris.Rmd

Fuente del ejemplo “R-kNN vecino más cercano parte 1”