Los k vecinos más cercanos, se tarata de un algoritmo no paramétrico que se utiliza para clasificación pero, a su vez para regresión. En ambos casos, se basa en elegir de entre un conjunto de k elementos, los que se encuentran más cerca para catalogar o para clasificar el objeto en sí mismo o bien hacer una regresión.
Por ende, la salida va a depender de si se utiliza para clasificar o para regresión. En este caso, lo usaremos para la clasificación, por lo tanto la salida tiene que ser un miembro de la clase a clasificar, deberá ser una variable categórica de modo que el objeto se va a clasificar por mayoría, el voto de mayoría por sus vecinos.
Cuantos más vecinos tenga cerca el objeto, la votación indicará precisamente que pertenece a dicha categoría. k <- indica cuántas familias o cuántos vecinos existen dentro de la clasificación.
Este paso se detalla en el primer documento: https://rpubs.com/Moki-chan/rpart-parcial-breast-mama
2.1. Información inicial de la data
data <- read.csv("https://raw.githubusercontent.com/cnahuina/data-mineria/master/breast-cancer.csv")
De acuerdo a ello se visualiza lo siguiente:
Se tiene 569 datos de 33 variables.
En el cual se rescatar que el identificador es de tipo int, el cual debe cambiar a factor, por lo mismo que es un identificador, también se puede rescatar la columna “X” con valores de “NA”
str(data)
## 'data.frame': 569 obs. of 33 variables:
## $ id : int 842302 842517 84300903 84348301 84358402 843786 844359 84458202 844981 84501001 ...
## $ diagnosis : Factor w/ 2 levels "B","M": 2 2 2 2 2 2 2 2 2 2 ...
## $ radius_mean : num 18 20.6 19.7 11.4 20.3 ...
## $ texture_mean : num 10.4 17.8 21.2 20.4 14.3 ...
## $ perimeter_mean : num 122.8 132.9 130 77.6 135.1 ...
## $ area_mean : num 1001 1326 1203 386 1297 ...
## $ smoothness_mean : num 0.1184 0.0847 0.1096 0.1425 0.1003 ...
## $ compactness_mean : num 0.2776 0.0786 0.1599 0.2839 0.1328 ...
## $ concavity_mean : num 0.3001 0.0869 0.1974 0.2414 0.198 ...
## $ concave.points_mean : num 0.1471 0.0702 0.1279 0.1052 0.1043 ...
## $ symmetry_mean : num 0.242 0.181 0.207 0.26 0.181 ...
## $ fractal_dimension_mean : num 0.0787 0.0567 0.06 0.0974 0.0588 ...
## $ radius_se : num 1.095 0.543 0.746 0.496 0.757 ...
## $ texture_se : num 0.905 0.734 0.787 1.156 0.781 ...
## $ perimeter_se : num 8.59 3.4 4.58 3.44 5.44 ...
## $ area_se : num 153.4 74.1 94 27.2 94.4 ...
## $ smoothness_se : num 0.0064 0.00522 0.00615 0.00911 0.01149 ...
## $ compactness_se : num 0.049 0.0131 0.0401 0.0746 0.0246 ...
## $ concavity_se : num 0.0537 0.0186 0.0383 0.0566 0.0569 ...
## $ concave.points_se : num 0.0159 0.0134 0.0206 0.0187 0.0188 ...
## $ symmetry_se : num 0.03 0.0139 0.0225 0.0596 0.0176 ...
## $ fractal_dimension_se : num 0.00619 0.00353 0.00457 0.00921 0.00511 ...
## $ radius_worst : num 25.4 25 23.6 14.9 22.5 ...
## $ texture_worst : num 17.3 23.4 25.5 26.5 16.7 ...
## $ perimeter_worst : num 184.6 158.8 152.5 98.9 152.2 ...
## $ area_worst : num 2019 1956 1709 568 1575 ...
## $ smoothness_worst : num 0.162 0.124 0.144 0.21 0.137 ...
## $ compactness_worst : num 0.666 0.187 0.424 0.866 0.205 ...
## $ concavity_worst : num 0.712 0.242 0.45 0.687 0.4 ...
## $ concave.points_worst : num 0.265 0.186 0.243 0.258 0.163 ...
## $ symmetry_worst : num 0.46 0.275 0.361 0.664 0.236 ...
## $ fractal_dimension_worst: num 0.1189 0.089 0.0876 0.173 0.0768 ...
## $ X : logi NA NA NA NA NA NA ...
data$id <- as.factor(data$id)
2.2. Información inicial de la data
En el cual podemos visualizar lo siguiente:
Variables:
Esto se visualiza en el primer documento: https://rpubs.com/Moki-chan/rpart-parcial-breast-mama
summary(data)
## id diagnosis radius_mean texture_mean perimeter_mean
## 8670 : 1 B:357 Min. : 6.981 Min. : 9.71 Min. : 43.79
## 8913 : 1 M:212 1st Qu.:11.700 1st Qu.:16.17 1st Qu.: 75.17
## 8915 : 1 Median :13.370 Median :18.84 Median : 86.24
## 9047 : 1 Mean :14.127 Mean :19.29 Mean : 91.97
## 85715 : 1 3rd Qu.:15.780 3rd Qu.:21.80 3rd Qu.:104.10
## 86208 : 1 Max. :28.110 Max. :39.28 Max. :188.50
## (Other):563
## area_mean smoothness_mean compactness_mean concavity_mean
## Min. : 143.5 Min. :0.05263 Min. :0.01938 Min. :0.00000
## 1st Qu.: 420.3 1st Qu.:0.08637 1st Qu.:0.06492 1st Qu.:0.02956
## Median : 551.1 Median :0.09587 Median :0.09263 Median :0.06154
## Mean : 654.9 Mean :0.09636 Mean :0.10434 Mean :0.08880
## 3rd Qu.: 782.7 3rd Qu.:0.10530 3rd Qu.:0.13040 3rd Qu.:0.13070
## Max. :2501.0 Max. :0.16340 Max. :0.34540 Max. :0.42680
##
## concave.points_mean symmetry_mean fractal_dimension_mean radius_se
## Min. :0.00000 Min. :0.1060 Min. :0.04996 Min. :0.1115
## 1st Qu.:0.02031 1st Qu.:0.1619 1st Qu.:0.05770 1st Qu.:0.2324
## Median :0.03350 Median :0.1792 Median :0.06154 Median :0.3242
## Mean :0.04892 Mean :0.1812 Mean :0.06280 Mean :0.4052
## 3rd Qu.:0.07400 3rd Qu.:0.1957 3rd Qu.:0.06612 3rd Qu.:0.4789
## Max. :0.20120 Max. :0.3040 Max. :0.09744 Max. :2.8730
##
## texture_se perimeter_se area_se smoothness_se
## Min. :0.3602 Min. : 0.757 Min. : 6.802 Min. :0.001713
## 1st Qu.:0.8339 1st Qu.: 1.606 1st Qu.: 17.850 1st Qu.:0.005169
## Median :1.1080 Median : 2.287 Median : 24.530 Median :0.006380
## Mean :1.2169 Mean : 2.866 Mean : 40.337 Mean :0.007041
## 3rd Qu.:1.4740 3rd Qu.: 3.357 3rd Qu.: 45.190 3rd Qu.:0.008146
## Max. :4.8850 Max. :21.980 Max. :542.200 Max. :0.031130
##
## compactness_se concavity_se concave.points_se symmetry_se
## Min. :0.002252 Min. :0.00000 Min. :0.000000 Min. :0.007882
## 1st Qu.:0.013080 1st Qu.:0.01509 1st Qu.:0.007638 1st Qu.:0.015160
## Median :0.020450 Median :0.02589 Median :0.010930 Median :0.018730
## Mean :0.025478 Mean :0.03189 Mean :0.011796 Mean :0.020542
## 3rd Qu.:0.032450 3rd Qu.:0.04205 3rd Qu.:0.014710 3rd Qu.:0.023480
## Max. :0.135400 Max. :0.39600 Max. :0.052790 Max. :0.078950
##
## fractal_dimension_se radius_worst texture_worst perimeter_worst
## Min. :0.0008948 Min. : 7.93 Min. :12.02 Min. : 50.41
## 1st Qu.:0.0022480 1st Qu.:13.01 1st Qu.:21.08 1st Qu.: 84.11
## Median :0.0031870 Median :14.97 Median :25.41 Median : 97.66
## Mean :0.0037949 Mean :16.27 Mean :25.68 Mean :107.26
## 3rd Qu.:0.0045580 3rd Qu.:18.79 3rd Qu.:29.72 3rd Qu.:125.40
## Max. :0.0298400 Max. :36.04 Max. :49.54 Max. :251.20
##
## area_worst smoothness_worst compactness_worst concavity_worst
## Min. : 185.2 Min. :0.07117 Min. :0.02729 Min. :0.0000
## 1st Qu.: 515.3 1st Qu.:0.11660 1st Qu.:0.14720 1st Qu.:0.1145
## Median : 686.5 Median :0.13130 Median :0.21190 Median :0.2267
## Mean : 880.6 Mean :0.13237 Mean :0.25427 Mean :0.2722
## 3rd Qu.:1084.0 3rd Qu.:0.14600 3rd Qu.:0.33910 3rd Qu.:0.3829
## Max. :4254.0 Max. :0.22260 Max. :1.05800 Max. :1.2520
##
## concave.points_worst symmetry_worst fractal_dimension_worst X
## Min. :0.00000 Min. :0.1565 Min. :0.05504 Mode:logical
## 1st Qu.:0.06493 1st Qu.:0.2504 1st Qu.:0.07146 NA's:569
## Median :0.09993 Median :0.2822 Median :0.08004
## Mean :0.11461 Mean :0.2901 Mean :0.08395
## 3rd Qu.:0.16140 3rd Qu.:0.3179 3rd Qu.:0.09208
## Max. :0.29100 Max. :0.6638 Max. :0.20750
##
2.3. Exploración de la data
Se analizan los valores outliers de la data en general.
Se refleja los outliers en la mayoría de las variables.
boxplot(data)
2.4 Verificación de la calidad de la data
Se realiza un gráfico en el cual nos permita visualizar el patrón de comportamiento de los NA’s
#install.packages("VIM")
library(VIM)
## Warning: package 'VIM' was built under R version 3.6.3
## Loading required package: colorspace
## Loading required package: grid
## Loading required package: data.table
## VIM is ready to use.
## Since version 4.0.0 the GUI is in its own package VIMGUI.
##
## Please use the package to use the new (and old) GUI.
## Suggestions and bug-reports can be submitted at: https://github.com/alexkowa/VIM/issues
##
## Attaching package: 'VIM'
## The following object is masked from 'package:datasets':
##
## sleep
miss <- aggr(data, col=c('green', 'red'),
ylab = c("Histograma de NAs", "Patrón"))
En el cuadro de proporcion de missings podemos observar que la variable X pasa del 5% , en consecuencia podría no tomarse en cuenta como variable de uso
summary(miss)
##
## Missings per variable:
## Variable Count
## id 0
## diagnosis 0
## radius_mean 0
## texture_mean 0
## perimeter_mean 0
## area_mean 0
## smoothness_mean 0
## compactness_mean 0
## concavity_mean 0
## concave.points_mean 0
## symmetry_mean 0
## fractal_dimension_mean 0
## radius_se 0
## texture_se 0
## perimeter_se 0
## area_se 0
## smoothness_se 0
## compactness_se 0
## concavity_se 0
## concave.points_se 0
## symmetry_se 0
## fractal_dimension_se 0
## radius_worst 0
## texture_worst 0
## perimeter_worst 0
## area_worst 0
## smoothness_worst 0
## compactness_worst 0
## concavity_worst 0
## concave.points_worst 0
## symmetry_worst 0
## fractal_dimension_worst 0
## X 569
##
## Missings in combinations of variables:
## Combinations Count
## 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:1 569
## Percent
## 100
3.1. Seleccionar la data
Como se mostró anteriormente, la última columna no se toma en cuenta y la otra variable a no tomar en cuenta es el identificador.
data <- data[,2:32]
3.2. Limpiar la data
Capar los valores extremos, es decir, localizar todo lo que cayera fuera del bigote más arriba o más abajo de 1,5 veces de el rango intercuartilico. Y decidir capar dichas obsevaciones sustituyendolas con el percentil número 5. En el caso de los que están debajo del bigote inferior y con el percentil 95 con los que están por encima del bigote superior.
replace_outliers <- function(x, removeNA = TRUE){
qrts <- quantile(x, probs = c(0.25, 0.75), na.rm = removeNA)
caps <- quantile(x, probs = c(.05, 0.95), na.rm = removeNA)
iqr <- qrts[2]-qrts[1]
h <- 1.5*iqr
x[x<qrts[1]-h] <- caps[1]
x[x>qrts[2]+h] <- caps[2]
x
}
data$radius_mean <- replace_outliers(data$radius_mean)
data$texture_mean <- replace_outliers(data$texture_mean)
data$perimeter_mean <- replace_outliers(data$perimeter_mean)
data$area_mean <- replace_outliers(data$area_mean)
data$smoothness_mean <- replace_outliers(data$smoothness_mean )
data$compactness_mean <- replace_outliers(data$compactness_mean)
data$concavity_mean <- replace_outliers(data$concavity_mean)
data$concave.points_mean <- replace_outliers(data$concave.points_mean)
data$symmetry_mean <- replace_outliers(data$symmetry_mean)
data$fractal_dimension_mean <- replace_outliers(data$fractal_dimension_mean)
data$radius_se <- replace_outliers(data$radius_se)
data$texture_se <- replace_outliers(data$texture_se )
data$perimeter_se <- replace_outliers(data$perimeter_se)
data$area_se <- replace_outliers(data$area_se)
data$smoothness_se <- replace_outliers(data$smoothness_se)
data$compactness_se <- replace_outliers(data$compactness_se)
data$concavity_se <- replace_outliers(data$concavity_se)
data$concave.points_se <- replace_outliers(data$concave.points_se)
data$symmetry_se <- replace_outliers(data$symmetry_se)
data$fractal_dimension_se <- replace_outliers(data$fractal_dimension_s)
data$radius_worst <- replace_outliers(data$radius_worst)
data$texture_worst <- replace_outliers(data$texture_worst )
data$perimeter_worst <- replace_outliers(data$perimeter_worst)
data$area_worst <- replace_outliers(data$area_worst)
data$smoothness_worst <- replace_outliers(data$smoothness_worst)
data$compactness_worst <- replace_outliers(data$compactness_worst)
data$concavity_worst <- replace_outliers(data$concavity_worst)
data$concave.points_worst <- replace_outliers(data$concave.points_worst)
data$symmetry_worst <- replace_outliers(data$symmetry_worst)
boxplot.stats(data$texture_mean)
## $stats
## [1] 9.71 16.17 18.84 21.80 29.97
##
## $n
## [1] 569
##
## $conf
## [1] 18.46709 19.21291
##
## $out
## numeric(0)
boxplot.stats(data$texture_mean)
## $stats
## [1] 9.71 16.17 18.84 21.80 29.97
##
## $n
## [1] 569
##
## $conf
## [1] 18.46709 19.21291
##
## $out
## numeric(0)
Se tienen variables que muestran mucha discrepancia, cuando se tiene ello en los datos, recordar que en esto suele haber una tendencia a que los números grandes dominen sobre los pequeños, a menos que se normalicen.
Normalización de las variables
– Explicación pendiente –
scale.many = function(dataframe, cols){
names <- names(dataframe)
for(col in cols){
name <- paste(names[col], "z", sep = ".")
dataframe[name] <- scale(dataframe[,col])
}
cat(paste("Hemos normalizado ", length(cols), " variable(s)"))
dataframe
}
data_new <- scale.many(data, c(2:31))
## Hemos normalizado 30 variable(s)
data_new <- data_new[,c(1,32:61)]
3.3. Construir data
Detallamos las librerías que haremos uso
# install.packages("caret")
library(caret)
## Warning: package 'caret' was built under R version 3.6.3
## Loading required package: lattice
## Loading required package: ggplot2
# install.packages("scales")
library(scales)
## Warning: package 'scales' was built under R version 3.6.3
# install.packages("class")
library(class)
## Warning: package 'class' was built under R version 3.6.3
set.seed(2018)
Se hacen 3 particiones:
t.id <- createDataPartition(data_new$diagnosis, p=0.6, list = F)
tr <- data_new[t.id, ]
temp <- data_new[-t.id, ]
v.id <- createDataPartition(temp$diagnosis, p=0.5, list = F)
val <- temp[v.id,]
dim(val <- temp[v.id,])
## [1] 113 31
test <- temp[-v.id,]
Haciendo uso de la función knn
Creamos una funicón el la cual evalue y genere de manera automática valores de k, en los cuales k, toma varios valores.
Creamos una función que automatice el proceso, que verifique una cierta cantidad de k’s y que nos muestre cual es la mejor elección que podemos hacer para la clasificación.
Tiene como parámetros de entrada, los tr_predictors, val_predictors, tr_target, val_target, start_k y end_k. Entre start_k y end_k, se elabora un modelo de knn, donde en base a los predictores y al tr_target de categortía, se cataloga al validor, es decir, al val_predictor para luego pasar a catalogar el target que quiero predecir.
knn.automate <- function(tr_predictors, val_predictors, tr_target,
val_target, start_k, end_k){
for (k in start_k:end_k) {
pred <- knn(tr_predictors, val_predictors, tr_target, k)
tab <- table(val_target, pred, dnn = c("Actual", "Predichos") )
cat(paste("Matriz de confusión para k = ",k,"\n"))
cat("==============================\n")
print(tab)
cat("------------------------------\n")
}
}
En el resultado se puede apreciar matrices de confusión, en el cual permiten ver la variación de valores predichos según el valor que se le de al k.
knn.automate(tr[,2:31], val[,2:31], tr[,1], val[,1], 1,12)
## Matriz de confusión para k = 1
## ==============================
## Predichos
## Actual B M
## B 68 3
## M 2 40
## ------------------------------
## Matriz de confusión para k = 2
## ==============================
## Predichos
## Actual B M
## B 69 2
## M 3 39
## ------------------------------
## Matriz de confusión para k = 3
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 2 40
## ------------------------------
## Matriz de confusión para k = 4
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 3 39
## ------------------------------
## Matriz de confusión para k = 5
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 3 39
## ------------------------------
## Matriz de confusión para k = 6
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 3 39
## ------------------------------
## Matriz de confusión para k = 7
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 3 39
## ------------------------------
## Matriz de confusión para k = 8
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 3 39
## ------------------------------
## Matriz de confusión para k = 9
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 3 39
## ------------------------------
## Matriz de confusión para k = 10
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 3 39
## ------------------------------
## Matriz de confusión para k = 11
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 3 39
## ------------------------------
## Matriz de confusión para k = 12
## ==============================
## Predichos
## Actual B M
## B 70 1
## M 4 38
## ------------------------------
De acuerdo a este resultado del uso de la función knn.automate se puede observar que el mejor valor para k es de 3.
mod <- knn(tr[,2:31], val[,2:31], tr[,1], 3)
mod
## [1] M M M M M M M M B M M M B B B M B M M B M B B B B B M M B M B B M B B B M
## [38] M B B B M B B M B B M B B M M M B B B B B B B B B B M B B B B B M M B M B
## [75] B M B M B B B B M B B B B B B B B M B M B B B B B B M B M B B M B B B B B
## [112] M M
## Levels: B M
5.1. Comprobación de la data
table <- table(val[,1], mod, dnn = c("Actual", "Predichos"))
table
## Predichos
## Actual B M
## B 70 1
## M 2 40
medida <- confusionMatrix(mod, val$diagnosis)
medida
## Confusion Matrix and Statistics
##
## Reference
## Prediction B M
## B 70 2
## M 1 40
##
## Accuracy : 0.9735
## 95% CI : (0.9244, 0.9945)
## No Information Rate : 0.6283
## P-Value [Acc > NIR] : <2e-16
##
## Kappa : 0.9429
##
## Mcnemar's Test P-Value : 1
##
## Sensitivity : 0.9859
## Specificity : 0.9524
## Pos Pred Value : 0.9722
## Neg Pred Value : 0.9756
## Prevalence : 0.6283
## Detection Rate : 0.6195
## Detection Prevalence : 0.6372
## Balanced Accuracy : 0.9691
##
## 'Positive' Class : B
##
Evaluamos que tan bueno es el modelo. En el caso de que el árbol no haya sido podado.
acc1 <- (70+40)/113
acc1
## [1] 0.9734513
error_rate1 <- 1 - acc1
error_rate1
## [1] 0.02654867
Tenemos entonces una precisión de predicción del 95.45% y un error de predicción del 2.65%.
A continuación se muestran los links con las demás herramientas que se usan para clasificar:
[1] Árboles-rpart: https://rpubs.com/Moki-chan/rpart-parcial-breast-mama
[2] randomForest: https://rpubs.com/Moki-chan/randomForest-parcial-cancer-breast
[3] Neural Network: https://rpubs.com/Moki-chan/neuronal-network-parcial-breast-mama
[4] Naive-bayes: https://rpubs.com/Moki-chan/naive-bayes-parcial-breast-mama
[5] Regresión Logística: https://rpubs.com/Moki-chan/log-reg-parcial-breast-mama