Diagnóstico del cáncer de mama

Juan David Velásquez Henao
jdvelasq@unal.edu.co
Universidad Nacional de Colombia, Sede Medellín
Facultad de Minas
Medellín, Colombia


Haga click aquí para acceder a la última versión online.

Haga click aquí para ver la última versión online en nbviewer.


Licencia
Readme

Definición del problema real

Se desea determinar si una masa en la mama es un tumor benigno o maligno, a partir de las medidas obtenidas de imágenes digitalizadas de la aspiración de una masa mamaria con una aguja fina. Los valores representan las características de los núcleos celulares presentes en la imagen digital.

Definición del problema en términos de los datos

Se tiene una muestra de 569 ejemplos de resultados de las biopsias. Cada registro contiene 32 variables, las cuales corresponden a tres medidas (media, desviación estándar, peor caso) de diez características diferentes (radius, texture, ...).

  • Identification number
  • Cancer diagnosis ("M" para maligno y "B" para benigno)
  • Radius
  • Texture
  • Perimeter
  • Area
  • Smoothness
  • Compactness
  • Concavity
  • Concave points
  • Symmetry
  • Fractal dimension

En términos de los datos, se desea pronosticar si una masa es benigna o maligna (clase B o M) a partir de las 30 variables.

Fuente de los datos: https://archive.ics.uci.edu/ml/datasets/Breast+Cancer+Wisconsin+(Diagnostic)

 Exploración


In [1]:
# carga de los datos
wbcd <- read.csv("data/wisc_bc_data.csv", stringsAsFactors = FALSE)

In [2]:
# verificación de los datos cargados
str(wbcd)


'data.frame':	569 obs. of  32 variables:
 $ id                     : int  842302 842517 84300903 84348301 84358402 843786 844359 84458202 844981 84501001 ...
 $ diagnosis              : chr  "M" "M" "M" "M" ...
 $ 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 ...

In [3]:
# se excluye la primera columna ya que no es informativa
wbcd <- wbcd[-1]

In [4]:
# cantidad de casos para cada diagnóstico
table(wbcd$diagnosis)


  B   M 
357 212 

In [5]:
# se convierte la columna diagnosis en factor
wbcd$diagnosis <- 
  factor(wbcd$diagnosis, 
         levels = c("B", "M"),              # las letras B y M se convierten en factores
         labels = c("Benign", "Malignant")) # se dan nuevos nombres a los factores

In [6]:
# cantidad de casos para cada diagnostico
# note que los nombres son más informativos
table(wbcd$diagnosis)


   Benign Malignant 
      357       212 

In [7]:
# se convierte el conteo en probabilidades
round(prop.table(table(wbcd$diagnosis)) * 100, digits = 1)


   Benign Malignant 
     62.7      37.3 

Metodología k-NN

El problema en términos matemáticos se define de la siguiente forma.

  • Se tienen $M$ ejemplos (las 569 observaciones del problema analizado).
  • Cada ejemplo esta definido por un conjunto de variables ($x_1$, $x_2$, ..., $x_N$); es decir, las 30 columnas de datos.
  • Cada ejemplo pertenece a una clase y hay $P$ clases diferentes; en el caso analizado sólo hay dos clases: benigno o maligno.
  • Para un nuevo caso y con base en las 30 mediciones realizadas (variables), se desea pronosticar a que clase pertenece.

El método k-NN asígna una clase (de las $P$ posibles) al nuevo ejemplo en dos pasos. En el primer paso, determina los $k$ ejemplos más cercanos (distancia) al nuevo ejemplo; en el segundo paso, asigna la clase al nuevo punto por mayoría; es decir, asigna la clase con mayor frecuencia entre los $k$ vecinos más cercnos. Por ejemplo, si se consideran 7 vecinos, de los cuales 5 son "benignos" (y 2 "malignos") entonces el nuevo punto es clasificado como "benigno".

La distancia entre dos puntos $p$ y $q$ es:

$$dist(p, q) = \sqrt{\sum_{i=1}^N (p_i - q_i)^2}$$

Ejercicio. ¿Cómo se implementa computacionalmente este algoritmo?

Ya que la escala de las variables numéricas afecta la medición, se pueden realizar dos transformaciones:

Normalización min-max.

$$z_j = \frac{x - \text{min}(x_j)}{\text{max}(x_j) - \text{min}(x_j)}$$

Estandarización z.

$$z_j = \frac{x - \text{mean}(x_j)}{\text{std}(x_j) }$$

Para variables nominales que representan $S$ categorías se crean $S-1$ variables: la primera variable vale 1 si la variable nominal toma el valor de la primera categoría; la segunda variable vale 2 si la variable nominal toma el valor de la segunda categoría, y así sucesivamente. ¿Por qué se requieren $S-1$ variables para $S$ categorías de la variable nominal?.

Preparación de los datos


In [8]:
# se examina el rango de las variables
summary(wbcd[2:31])


  radius_mean      texture_mean   perimeter_mean     area_mean     
 Min.   : 6.981   Min.   : 9.71   Min.   : 43.79   Min.   : 143.5  
 1st Qu.:11.700   1st Qu.:16.17   1st Qu.: 75.17   1st Qu.: 420.3  
 Median :13.370   Median :18.84   Median : 86.24   Median : 551.1  
 Mean   :14.127   Mean   :19.29   Mean   : 91.97   Mean   : 654.9  
 3rd Qu.:15.780   3rd Qu.:21.80   3rd Qu.:104.10   3rd Qu.: 782.7  
 Max.   :28.110   Max.   :39.28   Max.   :188.50   Max.   :2501.0  
 smoothness_mean   compactness_mean  concavity_mean    concave.points_mean
 Min.   :0.05263   Min.   :0.01938   Min.   :0.00000   Min.   :0.00000    
 1st Qu.:0.08637   1st Qu.:0.06492   1st Qu.:0.02956   1st Qu.:0.02031    
 Median :0.09587   Median :0.09263   Median :0.06154   Median :0.03350    
 Mean   :0.09636   Mean   :0.10434   Mean   :0.08880   Mean   :0.04892    
 3rd Qu.:0.10530   3rd Qu.:0.13040   3rd Qu.:0.13070   3rd Qu.:0.07400    
 Max.   :0.16340   Max.   :0.34540   Max.   :0.42680   Max.   :0.20120    
 symmetry_mean    fractal_dimension_mean   radius_se        texture_se    
 Min.   :0.1060   Min.   :0.04996        Min.   :0.1115   Min.   :0.3602  
 1st Qu.:0.1619   1st Qu.:0.05770        1st Qu.:0.2324   1st Qu.:0.8339  
 Median :0.1792   Median :0.06154        Median :0.3242   Median :1.1080  
 Mean   :0.1812   Mean   :0.06280        Mean   :0.4052   Mean   :1.2169  
 3rd Qu.:0.1957   3rd Qu.:0.06612        3rd Qu.:0.4789   3rd Qu.:1.4740  
 Max.   :0.3040   Max.   :0.09744        Max.   :2.8730   Max.   :4.8850  
  perimeter_se       area_se        smoothness_se      compactness_se    
 Min.   : 0.757   Min.   :  6.802   Min.   :0.001713   Min.   :0.002252  
 1st Qu.: 1.606   1st Qu.: 17.850   1st Qu.:0.005169   1st Qu.:0.013080  
 Median : 2.287   Median : 24.530   Median :0.006380   Median :0.020450  
 Mean   : 2.866   Mean   : 40.337   Mean   :0.007041   Mean   :0.025478  
 3rd Qu.: 3.357   3rd Qu.: 45.190   3rd Qu.:0.008146   3rd Qu.:0.032450  
 Max.   :21.980   Max.   :542.200   Max.   :0.031130   Max.   :0.135400  
  concavity_se     concave.points_se   symmetry_se       fractal_dimension_se
 Min.   :0.00000   Min.   :0.000000   Min.   :0.007882   Min.   :0.0008948   
 1st Qu.:0.01509   1st Qu.:0.007638   1st Qu.:0.015160   1st Qu.:0.0022480   
 Median :0.02589   Median :0.010930   Median :0.018730   Median :0.0031870   
 Mean   :0.03189   Mean   :0.011796   Mean   :0.020542   Mean   :0.0037949   
 3rd Qu.:0.04205   3rd Qu.:0.014710   3rd Qu.:0.023480   3rd Qu.:0.0045580   
 Max.   :0.39600   Max.   :0.052790   Max.   :0.078950   Max.   :0.0298400   
  radius_worst   texture_worst   perimeter_worst    area_worst    
 Min.   : 7.93   Min.   :12.02   Min.   : 50.41   Min.   : 185.2  
 1st Qu.:13.01   1st Qu.:21.08   1st Qu.: 84.11   1st Qu.: 515.3  
 Median :14.97   Median :25.41   Median : 97.66   Median : 686.5  
 Mean   :16.27   Mean   :25.68   Mean   :107.26   Mean   : 880.6  
 3rd Qu.:18.79   3rd Qu.:29.72   3rd Qu.:125.40   3rd Qu.:1084.0  
 Max.   :36.04   Max.   :49.54   Max.   :251.20   Max.   :4254.0  
 smoothness_worst  compactness_worst concavity_worst  concave.points_worst
 Min.   :0.07117   Min.   :0.02729   Min.   :0.0000   Min.   :0.00000     
 1st Qu.:0.11660   1st Qu.:0.14720   1st Qu.:0.1145   1st Qu.:0.06493     
 Median :0.13130   Median :0.21190   Median :0.2267   Median :0.09993     
 Mean   :0.13237   Mean   :0.25427   Mean   :0.2722   Mean   :0.11461     
 3rd Qu.:0.14600   3rd Qu.:0.33910   3rd Qu.:0.3829   3rd Qu.:0.16140     
 Max.   :0.22260   Max.   :1.05800   Max.   :1.2520   Max.   :0.29100     
 symmetry_worst   fractal_dimension_worst
 Min.   :0.1565   Min.   :0.05504        
 1st Qu.:0.2504   1st Qu.:0.07146        
 Median :0.2822   Median :0.08004        
 Mean   :0.2901   Mean   :0.08395        
 3rd Qu.:0.3179   3rd Qu.:0.09208        
 Max.   :0.6638   Max.   :0.20750        

Note que la información visualizada muestra que las variables tienen diferentes rangos. Para corregir este problema se normalizan las variables.


In [9]:
# se define la función de normalización
normalize <- 
function(x) {
    return ((x - min(x)) / (max(x) - min(x)))
}

In [10]:
# se aplica la función a los datos
wbcd_n <- as.data.frame(lapply(wbcd[2:31], normalize))

In [11]:
# se verifica la transformación
summary(wbcd_n)


  radius_mean      texture_mean    perimeter_mean     area_mean     
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.2233   1st Qu.:0.2185   1st Qu.:0.2168   1st Qu.:0.1174  
 Median :0.3024   Median :0.3088   Median :0.2933   Median :0.1729  
 Mean   :0.3382   Mean   :0.3240   Mean   :0.3329   Mean   :0.2169  
 3rd Qu.:0.4164   3rd Qu.:0.4089   3rd Qu.:0.4168   3rd Qu.:0.2711  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  
 smoothness_mean  compactness_mean concavity_mean    concave.points_mean
 Min.   :0.0000   Min.   :0.0000   Min.   :0.00000   Min.   :0.0000     
 1st Qu.:0.3046   1st Qu.:0.1397   1st Qu.:0.06926   1st Qu.:0.1009     
 Median :0.3904   Median :0.2247   Median :0.14419   Median :0.1665     
 Mean   :0.3948   Mean   :0.2606   Mean   :0.20806   Mean   :0.2431     
 3rd Qu.:0.4755   3rd Qu.:0.3405   3rd Qu.:0.30623   3rd Qu.:0.3678     
 Max.   :1.0000   Max.   :1.0000   Max.   :1.00000   Max.   :1.0000     
 symmetry_mean    fractal_dimension_mean   radius_se         texture_se    
 Min.   :0.0000   Min.   :0.0000         Min.   :0.00000   Min.   :0.0000  
 1st Qu.:0.2823   1st Qu.:0.1630         1st Qu.:0.04378   1st Qu.:0.1047  
 Median :0.3697   Median :0.2439         Median :0.07702   Median :0.1653  
 Mean   :0.3796   Mean   :0.2704         Mean   :0.10635   Mean   :0.1893  
 3rd Qu.:0.4530   3rd Qu.:0.3404         3rd Qu.:0.13304   3rd Qu.:0.2462  
 Max.   :1.0000   Max.   :1.0000         Max.   :1.00000   Max.   :1.0000  
  perimeter_se        area_se        smoothness_se    compactness_se   
 Min.   :0.00000   Min.   :0.00000   Min.   :0.0000   Min.   :0.00000  
 1st Qu.:0.04000   1st Qu.:0.02064   1st Qu.:0.1175   1st Qu.:0.08132  
 Median :0.07209   Median :0.03311   Median :0.1586   Median :0.13667  
 Mean   :0.09938   Mean   :0.06264   Mean   :0.1811   Mean   :0.17444  
 3rd Qu.:0.12251   3rd Qu.:0.07170   3rd Qu.:0.2187   3rd Qu.:0.22680  
 Max.   :1.00000   Max.   :1.00000   Max.   :1.0000   Max.   :1.00000  
  concavity_se     concave.points_se  symmetry_se     fractal_dimension_se
 Min.   :0.00000   Min.   :0.0000    Min.   :0.0000   Min.   :0.00000     
 1st Qu.:0.03811   1st Qu.:0.1447    1st Qu.:0.1024   1st Qu.:0.04675     
 Median :0.06538   Median :0.2070    Median :0.1526   Median :0.07919     
 Mean   :0.08054   Mean   :0.2235    Mean   :0.1781   Mean   :0.10019     
 3rd Qu.:0.10619   3rd Qu.:0.2787    3rd Qu.:0.2195   3rd Qu.:0.12656     
 Max.   :1.00000   Max.   :1.0000    Max.   :1.0000   Max.   :1.00000     
  radius_worst    texture_worst    perimeter_worst    area_worst     
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.00000  
 1st Qu.:0.1807   1st Qu.:0.2415   1st Qu.:0.1678   1st Qu.:0.08113  
 Median :0.2504   Median :0.3569   Median :0.2353   Median :0.12321  
 Mean   :0.2967   Mean   :0.3640   Mean   :0.2831   Mean   :0.17091  
 3rd Qu.:0.3863   3rd Qu.:0.4717   3rd Qu.:0.3735   3rd Qu.:0.22090  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.00000  
 smoothness_worst compactness_worst concavity_worst   concave.points_worst
 Min.   :0.0000   Min.   :0.0000    Min.   :0.00000   Min.   :0.0000      
 1st Qu.:0.3000   1st Qu.:0.1163    1st Qu.:0.09145   1st Qu.:0.2231      
 Median :0.3971   Median :0.1791    Median :0.18107   Median :0.3434      
 Mean   :0.4041   Mean   :0.2202    Mean   :0.21740   Mean   :0.3938      
 3rd Qu.:0.4942   3rd Qu.:0.3025    3rd Qu.:0.30583   3rd Qu.:0.5546      
 Max.   :1.0000   Max.   :1.0000    Max.   :1.00000   Max.   :1.0000      
 symmetry_worst   fractal_dimension_worst
 Min.   :0.0000   Min.   :0.0000         
 1st Qu.:0.1851   1st Qu.:0.1077         
 Median :0.2478   Median :0.1640         
 Mean   :0.2633   Mean   :0.1896         
 3rd Qu.:0.3182   3rd Qu.:0.2429         
 Max.   :1.0000   Max.   :1.0000         

In [12]:
# se crean los conjuntos de entrenamiento y prueba
wbcd_train <- wbcd_n[1:469, ]
wbcd_test <- wbcd_n[470:569, ]

# clase de cada ejemplo
wbcd_train_labels <- wbcd[1:469, 1]
wbcd_test_labels <- wbcd[470:569, 1]

Entrenamiento del modelo


In [13]:
# carga la librería
# install.packages("class")
library(class)

wbcd_test_pred <- knn(train = wbcd_train,     # conjunto de entrenamiento
                      test = wbcd_test,       # conjutno de prueba
                      cl = wbcd_train_labels, # clases para el conjunto de entrenamiento
                      k = 21)                 # número de vecinos

Evaluación del modelo

Para evaluar el desempeño en problemas de clasificación dicotómicos (dos clases mutuamente excluyentes) se usa la siguiente tabla:

           Pronostico
            P     N
      P     VP    FN          
Real
      N     FP    VN

VP - Verdadero positivo (correcto)
VN - Verdadero negativo (correcto)
FN - Falso negativo
FP - Falso positivo

In [14]:
#install.packages("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 |    Benign | Malignant | Row Total | 
-----------------|-----------|-----------|-----------|
          Benign |        77 |         0 |        77 | 
                 |     1.000 |     0.000 |     0.770 | 
                 |     0.975 |     0.000 |           | 
                 |     0.770 |     0.000 |           | 
-----------------|-----------|-----------|-----------|
       Malignant |         2 |        21 |        23 | 
                 |     0.087 |     0.913 |     0.230 | 
                 |     0.025 |     1.000 |           | 
                 |     0.020 |     0.210 |           | 
-----------------|-----------|-----------|-----------|
    Column Total |        79 |        21 |       100 | 
                 |     0.790 |     0.210 |           | 
-----------------|-----------|-----------|-----------|

 

Mejora del modelo

Ejercicio. Determine si el modelo mejora con $k$ = 21 y se estándarizan las variables. Ayuda: use la función scale.

Ejercicio. Determine el valor óptimo de $k$ cuándo los datos son normalizados. Ayuda: Calcule la cantidad total de ejemplos mal clasificados para $k$ desde 1 hasta 27.

Ejercicio. Los resutados son dependientes de cómo se partieron los datos en entrenamiento y prueba. Cómo podría calcular de una forma más robusta la cantidad de vecinos?

Diagnóstico del cáncer de mama

Juan David Velásquez Henao
jdvelasq@unal.edu.co
Universidad Nacional de Colombia, Sede Medellín
Facultad de Minas
Medellín, Colombia


Haga click aquí para acceder a la última versión online.

Haga click aquí para ver la última versión online en nbviewer.


Licencia
Readme