# 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