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 150La 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”