# Clasificacion tipo Lazy Learning
# Utilizando el algoritmo Nearest Neighbors
# Ejemplo – diagnostico de cancer de seno con
# el algoritmo k-NN
# Paso 1 – obtencion de la data
# Utilizaremos la data Wisconsin Breast Cancer Diagnostic
# proveniente de UCI Machine Learning Repository
# ubicado en la web.
# donada por investigadores de la University of Wisconsin
# Esta data incluye ejemplos de 569
# de biopsias de cancer, cada una
# con 32 caracteristicas. Una caracteristica es un numero
# de identificacion,
# y otro contiene el diagnostico,
# ademas de 30 variables numericas que son las medidas
# obtenidas en el laboratorio.
# El diagnostico esta codificado como
# "M" para indicar maligno o "B" para indicar benigno.
# Paso 2 – explorando y preparando la data
# Establecemos nuestro directorio de trabajo
# usamos el comando de RStudio para importar
# la data desde un archivo local
wbcd <- read.table(file.choose(),header=TRUE,
stringsAsFactors = FALSE,sep = ",")
head(wbcd)#Nos da una indicacio de como esta
## id diagnosis radius_mean texture_mean perimeter_mean area_mean
## 1 87139402 B 12.32 12.39 78.85 464.1
## 2 8910251 B 10.60 18.95 69.28 346.4
## 3 905520 B 11.04 16.83 70.92 373.2
## 4 868871 B 11.28 13.39 73.00 384.8
## 5 9012568 B 15.19 13.21 97.65 711.8
## 6 906539 B 11.57 19.04 74.20 409.7
## smoothness_mean compactness_mean concavity_mean points_mean
## 1 0.10280 0.06981 0.03987 0.03700
## 2 0.09688 0.11470 0.06387 0.02642
## 3 0.10770 0.07804 0.03046 0.02480
## 4 0.11640 0.11360 0.04635 0.04796
## 5 0.07963 0.06934 0.03393 0.02657
## 6 0.08546 0.07722 0.05485 0.01428
## symmetry_mean dimension_mean radius_se texture_se perimeter_se area_se
## 1 0.1959 0.05955 0.2360 0.6656 1.670 17.43
## 2 0.1922 0.06491 0.4505 1.1970 3.430 27.10
## 3 0.1714 0.06340 0.1967 1.3870 1.342 13.54
## 4 0.1771 0.06072 0.3384 1.3430 1.851 26.33
## 5 0.1721 0.05544 0.1783 0.4125 1.338 17.72
## 6 0.2031 0.06267 0.2864 1.4400 2.206 20.30
## smoothness_se compactness_se concavity_se points_se symmetry_se
## 1 0.008045 0.011800 0.01683 0.012410 0.01924
## 2 0.007470 0.035810 0.03354 0.013650 0.03504
## 3 0.005158 0.009355 0.01056 0.007483 0.01718
## 4 0.011270 0.034980 0.02187 0.019650 0.01580
## 5 0.005012 0.014850 0.01551 0.009155 0.01647
## 6 0.007278 0.020470 0.04447 0.008799 0.01868
## dimension_se radius_worst texture_worst perimeter_worst area_worst
## 1 0.002248 13.50 15.64 86.97 549.1
## 2 0.003318 11.88 22.94 78.28 424.8
## 3 0.002198 12.41 26.44 79.93 471.4
## 4 0.003442 11.92 15.77 76.53 434.0
## 5 0.001767 16.20 15.73 104.50 819.1
## 6 0.003339 13.07 26.98 86.43 520.5
## smoothness_worst compactness_worst concavity_worst points_worst
## 1 0.1385 0.1266 0.12420 0.09391
## 2 0.1213 0.2515 0.19160 0.07926
## 3 0.1369 0.1482 0.10670 0.07431
## 4 0.1367 0.1822 0.08669 0.08611
## 5 0.1126 0.1737 0.13620 0.08178
## 6 0.1249 0.1937 0.25600 0.06664
## symmetry_worst dimension_worst
## 1 0.2827 0.06771
## 2 0.2940 0.07587
## 3 0.2998 0.07881
## 4 0.2102 0.06784
## 5 0.2487 0.06766
## 6 0.3035 0.08284
# organizada la data en el archivo
str(wbcd)# este comando tambien nos ayuda a
## 'data.frame': 569 obs. of 32 variables:
## $ id : int 87139402 8910251 905520 868871 9012568 906539 925291 87880 862989 89827 ...
## $ diagnosis : chr "B" "B" "B" "B" ...
## $ radius_mean : num 12.3 10.6 11 11.3 15.2 ...
## $ texture_mean : num 12.4 18.9 16.8 13.4 13.2 ...
## $ perimeter_mean : num 78.8 69.3 70.9 73 97.7 ...
## $ area_mean : num 464 346 373 385 712 ...
## $ smoothness_mean : num 0.1028 0.0969 0.1077 0.1164 0.0796 ...
## $ compactness_mean : num 0.0698 0.1147 0.078 0.1136 0.0693 ...
## $ concavity_mean : num 0.0399 0.0639 0.0305 0.0464 0.0339 ...
## $ points_mean : num 0.037 0.0264 0.0248 0.048 0.0266 ...
## $ symmetry_mean : num 0.196 0.192 0.171 0.177 0.172 ...
## $ dimension_mean : num 0.0595 0.0649 0.0634 0.0607 0.0554 ...
## $ radius_se : num 0.236 0.451 0.197 0.338 0.178 ...
## $ texture_se : num 0.666 1.197 1.387 1.343 0.412 ...
## $ perimeter_se : num 1.67 3.43 1.34 1.85 1.34 ...
## $ area_se : num 17.4 27.1 13.5 26.3 17.7 ...
## $ smoothness_se : num 0.00805 0.00747 0.00516 0.01127 0.00501 ...
## $ compactness_se : num 0.0118 0.03581 0.00936 0.03498 0.01485 ...
## $ concavity_se : num 0.0168 0.0335 0.0106 0.0219 0.0155 ...
## $ points_se : num 0.01241 0.01365 0.00748 0.01965 0.00915 ...
## $ symmetry_se : num 0.0192 0.035 0.0172 0.0158 0.0165 ...
## $ dimension_se : num 0.00225 0.00332 0.0022 0.00344 0.00177 ...
## $ radius_worst : num 13.5 11.9 12.4 11.9 16.2 ...
## $ texture_worst : num 15.6 22.9 26.4 15.8 15.7 ...
## $ perimeter_worst : num 87 78.3 79.9 76.5 104.5 ...
## $ area_worst : num 549 425 471 434 819 ...
## $ smoothness_worst : num 0.139 0.121 0.137 0.137 0.113 ...
## $ compactness_worst: num 0.127 0.252 0.148 0.182 0.174 ...
## $ concavity_worst : num 0.1242 0.1916 0.1067 0.0867 0.1362 ...
## $ points_worst : num 0.0939 0.0793 0.0743 0.0861 0.0818 ...
## $ symmetry_worst : num 0.283 0.294 0.3 0.21 0.249 ...
## $ dimension_worst : num 0.0677 0.0759 0.0788 0.0678 0.0677 ...
# explorar la data
# Eliminamos el id, siempre hay que hacerlo
# pues no aporta nada al modelo
wbcd <- wbcd[-1]
# La siguiente variable diagnosis es de
# particular interes ya que contiene los
# resultados que esperamos predecir.
# Esta variable indica si el ejemplo
# proviene de una masa maligna o benigna
table(wbcd$diagnosis)
##
## B M
## 357 212
# Muchos clasificadores de machine learning
# requieren que la variable que deseamos
# utilizar como objetivo (target) este
# codificada como un factor, es por ello
# que recodificaremos la variable y le daremos
# nombres mas informativos
wbcd$diagnosis <- factor(wbcd$diagnosis,levels = c("B","M"),
labels = c("Benigno","Maligno"))
table(wbcd$diagnosis)# verificamos nuestr cambio
##
## Benigno Maligno
## 357 212
# Para ver las proporciones usamos
round(prop.table(table(wbcd$diagnosis))*100,digits = 1)
##
## Benigno Maligno
## 62.7 37.3
str(wbcd$diagnosis)#verificamos el cambio a factor
## Factor w/ 2 levels "Benigno","Maligno": 1 1 1 1 1 1 1 2 1 1 ...
# Las otras 30 variables son todas numerica
# pero ahora examinamos 3 de ellas que
# merecen atencion particular
summary(wbcd[c("radius_mean","area_mean","smoothness_mean")])
## radius_mean area_mean smoothness_mean
## Min. : 6.981 Min. : 143.5 Min. :0.05263
## 1st Qu.:11.700 1st Qu.: 420.3 1st Qu.:0.08637
## Median :13.370 Median : 551.1 Median :0.09587
## Mean :14.127 Mean : 654.9 Mean :0.09636
## 3rd Qu.:15.780 3rd Qu.: 782.7 3rd Qu.:0.10530
## Max. :28.110 Max. :2501.0 Max. :0.16340
# Los calculos del algoritmo k-NN dependen en la escala
# de la distancia en las caracteristicas de las variables.
# Debido a que smoothness tiene un rango desde 0.05 a 0.16
# y los rangos del area estan entre 143.5 y 2501, el impacto
# del area sera mucho mayor. Esto puede ocasionar problemas
# para nuestro clasificador, es por ello que aplicaremos
# normalizacion para re-escalar las variables a un rango
# de valores estandarizados
str(wbcd)
## 'data.frame': 569 obs. of 31 variables:
## $ diagnosis : Factor w/ 2 levels "Benigno","Maligno": 1 1 1 1 1 1 1 2 1 1 ...
## $ radius_mean : num 12.3 10.6 11 11.3 15.2 ...
## $ texture_mean : num 12.4 18.9 16.8 13.4 13.2 ...
## $ perimeter_mean : num 78.8 69.3 70.9 73 97.7 ...
## $ area_mean : num 464 346 373 385 712 ...
## $ smoothness_mean : num 0.1028 0.0969 0.1077 0.1164 0.0796 ...
## $ compactness_mean : num 0.0698 0.1147 0.078 0.1136 0.0693 ...
## $ concavity_mean : num 0.0399 0.0639 0.0305 0.0464 0.0339 ...
## $ points_mean : num 0.037 0.0264 0.0248 0.048 0.0266 ...
## $ symmetry_mean : num 0.196 0.192 0.171 0.177 0.172 ...
## $ dimension_mean : num 0.0595 0.0649 0.0634 0.0607 0.0554 ...
## $ radius_se : num 0.236 0.451 0.197 0.338 0.178 ...
## $ texture_se : num 0.666 1.197 1.387 1.343 0.412 ...
## $ perimeter_se : num 1.67 3.43 1.34 1.85 1.34 ...
## $ area_se : num 17.4 27.1 13.5 26.3 17.7 ...
## $ smoothness_se : num 0.00805 0.00747 0.00516 0.01127 0.00501 ...
## $ compactness_se : num 0.0118 0.03581 0.00936 0.03498 0.01485 ...
## $ concavity_se : num 0.0168 0.0335 0.0106 0.0219 0.0155 ...
## $ points_se : num 0.01241 0.01365 0.00748 0.01965 0.00915 ...
## $ symmetry_se : num 0.0192 0.035 0.0172 0.0158 0.0165 ...
## $ dimension_se : num 0.00225 0.00332 0.0022 0.00344 0.00177 ...
## $ radius_worst : num 13.5 11.9 12.4 11.9 16.2 ...
## $ texture_worst : num 15.6 22.9 26.4 15.8 15.7 ...
## $ perimeter_worst : num 87 78.3 79.9 76.5 104.5 ...
## $ area_worst : num 549 425 471 434 819 ...
## $ smoothness_worst : num 0.139 0.121 0.137 0.137 0.113 ...
## $ compactness_worst: num 0.127 0.252 0.148 0.182 0.174 ...
## $ concavity_worst : num 0.1242 0.1916 0.1067 0.0867 0.1362 ...
## $ points_worst : num 0.0939 0.0793 0.0743 0.0861 0.0818 ...
## $ symmetry_worst : num 0.283 0.294 0.3 0.21 0.249 ...
## $ dimension_worst : num 0.0677 0.0759 0.0788 0.0678 0.0677 ...
# Transformacion: Normalizacion de la data
# La funcion para normalizar la data es creada:
normalize <- function(x){
return ((x-min(x))/(max(x)-min(x)))
}
#probamos la funcion recien creada
normalize(c(1,2,3,4,5))
## [1] 0.00 0.25 0.50 0.75 1.00
normalize(c(10,20,30,40,100))
## [1] 0.0000000 0.1111111 0.2222222 0.3333333 1.0000000
#Para aplicar la funcion a las 30 variables
# utilizamos la funcion lapply()
wbcd_n <- as.data.frame(lapply(wbcd[2:31], normalize))
summary(wbcd_n$area_mean)#verificamos los resultados
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0000 0.1174 0.1729 0.2169 0.2711 1.0000
# de la funcion normalize aplicada
# Preparacion de la data, creacion de la data
# de entrenamiento y de la data de prueba
wbcd_train <- wbcd_n[1:469,]
wbcd_test <- wbcd_n[470:569,]
str(wbcd_train)# verificamos la data
## 'data.frame': 469 obs. of 30 variables:
## $ radius_mean : num 0.253 0.171 0.192 0.203 0.389 ...
## $ texture_mean : num 0.0906 0.3125 0.2408 0.1245 0.1184 ...
## $ perimeter_mean : num 0.242 0.176 0.187 0.202 0.372 ...
## $ area_mean : num 0.136 0.0861 0.0974 0.1024 0.2411 ...
## $ smoothness_mean : num 0.453 0.399 0.497 0.576 0.244 ...
## $ compactness_mean : num 0.155 0.292 0.18 0.289 0.153 ...
## $ concavity_mean : num 0.0934 0.1496 0.0714 0.1086 0.0795 ...
## $ points_mean : num 0.184 0.131 0.123 0.238 0.132 ...
## $ symmetry_mean : num 0.454 0.435 0.33 0.359 0.334 ...
## $ dimension_mean : num 0.202 0.315 0.283 0.227 0.115 ...
## $ radius_se : num 0.0451 0.1228 0.0309 0.0822 0.0242 ...
## $ texture_se : num 0.0675 0.1849 0.2269 0.2172 0.0116 ...
## $ perimeter_se : num 0.043 0.1259 0.0276 0.0515 0.0274 ...
## $ area_se : num 0.0199 0.0379 0.0126 0.0365 0.0204 ...
## $ smoothness_se : num 0.215 0.196 0.117 0.325 0.112 ...
## $ compactness_se : num 0.0717 0.252 0.0533 0.2458 0.0946 ...
## $ concavity_se : num 0.0425 0.0847 0.0267 0.0552 0.0392 ...
## $ points_se : num 0.235 0.259 0.142 0.372 0.173 ...
## $ symmetry_se : num 0.16 0.382 0.131 0.111 0.121 ...
## $ dimension_se : num 0.0468 0.0837 0.045 0.088 0.0301 ...
## $ radius_worst : num 0.198 0.141 0.159 0.142 0.294 ...
## $ texture_worst : num 0.0965 0.291 0.3843 0.0999 0.0989 ...
## $ perimeter_worst : num 0.182 0.139 0.147 0.13 0.269 ...
## $ area_worst : num 0.0894 0.0589 0.0703 0.0611 0.1558 ...
## $ smoothness_worst : num 0.445 0.331 0.434 0.433 0.274 ...
## $ compactness_worst: num 0.0964 0.2175 0.1173 0.1503 0.142 ...
## $ concavity_worst : num 0.0992 0.153 0.0852 0.0692 0.1088 ...
## $ points_worst : num 0.323 0.272 0.255 0.296 0.281 ...
## $ symmetry_worst : num 0.249 0.271 0.282 0.106 0.182 ...
## $ dimension_worst : num 0.0831 0.1366 0.1559 0.084 0.0828 ...
# cuando normalizamos la data, eliminamos
# la variable objetivo (target) diagnosis
# para entrenar el model k-NN, necesitaremos
# guardar esas etiquetas de clase en vectores
# de factores, divididas en entrenamiento y
# prueba
wbcd_train_labels <- wbcd[1:469,1]#este codigo
# toma la variable (factor) diagnosis de la
# primera columna de la data frame wbcd y
# crea los vectores de etiquetas
wbcd_test_labels <- wbcd[470:569,1]#igual para
# el set de prueba
head(wbcd_train_labels)#probamos la transformacion
## [1] Benigno Benigno Benigno Benigno Benigno Benigno
## Levels: Benigno Maligno
#Paso 3 entrenando el modelo en la data
# para clasificar las instancias creadas
# usaremos la implementacion de k-NN
# contenida en el paquete o libreria class
library(class)
#la funcion k-NN en el paquete class
#provee una implementacion clasica y standar
#de algoritmo k-NN. Para cada instancia en
# la data, la funcion identificara los vecinos
# mas cercanos, usando la distancia Euclidiana
# donde k es un numero especificado por el usuario
# usaremos la raiz cuadrada de 469 para fijar k
wbcd_test_pred <- knn(train = wbcd_train,test = wbcd_test,
cl=wbcd_train_labels,k=21)
# la funcion knn() da como resultado un vector
# de factores con las etiquetas de las predicciones
# para cada ejemplo en la data de prueba
# a la cual le hemos fijado el nombre wbcd_test_pred
# Paso 4
# Evaluando el rendimiento del modelo
# el proximo paso en el proceso es evaluar
# que tan bien las clases de las predicciones
# obtenidas en el vector wbcd_test_pred
# igualan a las etiquetas de los valores
# conocidos y contenidos en los vectores
# wbcd_test_labels- Para ello utilizaremos
# la funcion CrossTable() contenida en el
# paquete o libreria gmodels
library(gmodels)
CrossTable(x=wbcd_test_labels,y=wbcd_test_pred,
prop.chisq = FALSE)
##
##
## Cell Contents
## |-------------------------|
## | N |
## | N / Row Total |
## | N / Col Total |
## | N / Table Total |
## |-------------------------|
##
##
## Total Observations in Table: 100
##
##
## | wbcd_test_pred
## wbcd_test_labels | Benigno | Maligno | Row Total |
## -----------------|-----------|-----------|-----------|
## Benigno | 61 | 0 | 61 |
## | 1.000 | 0.000 | 0.610 |
## | 0.968 | 0.000 | |
## | 0.610 | 0.000 | |
## -----------------|-----------|-----------|-----------|
## Maligno | 2 | 37 | 39 |
## | 0.051 | 0.949 | 0.390 |
## | 0.032 | 1.000 | |
## | 0.020 | 0.370 | |
## -----------------|-----------|-----------|-----------|
## Column Total | 63 | 37 | 100 |
## | 0.630 | 0.370 | |
## -----------------|-----------|-----------|-----------|
##
##
# 61 casos de 100 determinados como
# benignos en la diagonal (verdaderos negativos)
# 37 casos de 100 determinados como
# malignos en la diagonal (verdaderos positivos)
# 2 casos en la otra diagonal, abajo a la izquierda
# son falsos negativos, diagnostico dado por
# el modelo indicaba benigno cuando de hecho
# era maligno-Errores en esta direccion son
# extremadamente serios pues se le indica al
# paciente que esta libre de cancer cuando de
# hecho no lo esta-En la celda de arriba a la
# derecha contiene los falsos positivos
# casos en que el modelo indica maligno, cuando
# de hecho es benigno