Objetivo

Este tutorial recoge los pasos básicos para llevar a cabo un clasificador k-NN (k-Nearest Neighbors) haciendo uso del paquete class de R y de su función knn(). En este ejemplo realizaremos un clasificador que actua sobre las biopsias de posibles casos de cancer de pecho.

Fuente de datos

La fuente de datos de este ejemplo la obtendremos de la UCI Machine Learning Repository, concretamente de la siguiente URL que contiene los 569 casos con 32 variables en cada caso.

if(!file.exists('myfile.csv')) # descargamos el archivo sólo si no se encuentra ya en nuestro directorio de trabajo
{
    url <- "http://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data"
    download.file(url, destfile = 'myfile.csv', method = 'curl')
}
data <- read.csv('myfile.csv', header = FALSE, sep=',')

Exploración

Empezamos echando un breve vistazo a los datos descargados y así tener una idea clara las características de los datos con los que estamos trabajando.

head(data)
##         V1 V2    V3    V4     V5     V6      V7      V8     V9     V10
## 1   842302  M 17.99 10.38 122.80 1001.0 0.11840 0.27760 0.3001 0.14710
## 2   842517  M 20.57 17.77 132.90 1326.0 0.08474 0.07864 0.0869 0.07017
## 3 84300903  M 19.69 21.25 130.00 1203.0 0.10960 0.15990 0.1974 0.12790
## 4 84348301  M 11.42 20.38  77.58  386.1 0.14250 0.28390 0.2414 0.10520
## 5 84358402  M 20.29 14.34 135.10 1297.0 0.10030 0.13280 0.1980 0.10430
## 6   843786  M 12.45 15.70  82.57  477.1 0.12780 0.17000 0.1578 0.08089
##      V11     V12    V13    V14   V15    V16      V17     V18     V19
## 1 0.2419 0.07871 1.0950 0.9053 8.589 153.40 0.006399 0.04904 0.05373
## 2 0.1812 0.05667 0.5435 0.7339 3.398  74.08 0.005225 0.01308 0.01860
## 3 0.2069 0.05999 0.7456 0.7869 4.585  94.03 0.006150 0.04006 0.03832
## 4 0.2597 0.09744 0.4956 1.1560 3.445  27.23 0.009110 0.07458 0.05661
## 5 0.1809 0.05883 0.7572 0.7813 5.438  94.44 0.011490 0.02461 0.05688
## 6 0.2087 0.07613 0.3345 0.8902 2.217  27.19 0.007510 0.03345 0.03672
##       V20     V21      V22   V23   V24    V25    V26    V27    V28    V29
## 1 0.01587 0.03003 0.006193 25.38 17.33 184.60 2019.0 0.1622 0.6656 0.7119
## 2 0.01340 0.01389 0.003532 24.99 23.41 158.80 1956.0 0.1238 0.1866 0.2416
## 3 0.02058 0.02250 0.004571 23.57 25.53 152.50 1709.0 0.1444 0.4245 0.4504
## 4 0.01867 0.05963 0.009208 14.91 26.50  98.87  567.7 0.2098 0.8663 0.6869
## 5 0.01885 0.01756 0.005115 22.54 16.67 152.20 1575.0 0.1374 0.2050 0.4000
## 6 0.01137 0.02165 0.005082 15.47 23.75 103.40  741.6 0.1791 0.5249 0.5355
##      V30    V31     V32
## 1 0.2654 0.4601 0.11890
## 2 0.1860 0.2750 0.08902
## 3 0.2430 0.3613 0.08758
## 4 0.2575 0.6638 0.17300
## 5 0.1625 0.2364 0.07678
## 6 0.1741 0.3985 0.12440
str(data)
## 'data.frame':    569 obs. of  32 variables:
##  $ V1 : int  842302 842517 84300903 84348301 84358402 843786 844359 84458202 844981 84501001 ...
##  $ V2 : Factor w/ 2 levels "B","M": 2 2 2 2 2 2 2 2 2 2 ...
##  $ V3 : num  18 20.6 19.7 11.4 20.3 ...
##  $ V4 : num  10.4 17.8 21.2 20.4 14.3 ...
##  $ V5 : num  122.8 132.9 130 77.6 135.1 ...
##  $ V6 : num  1001 1326 1203 386 1297 ...
##  $ V7 : num  0.1184 0.0847 0.1096 0.1425 0.1003 ...
##  $ V8 : num  0.2776 0.0786 0.1599 0.2839 0.1328 ...
##  $ V9 : num  0.3001 0.0869 0.1974 0.2414 0.198 ...
##  $ V10: num  0.1471 0.0702 0.1279 0.1052 0.1043 ...
##  $ V11: num  0.242 0.181 0.207 0.26 0.181 ...
##  $ V12: num  0.0787 0.0567 0.06 0.0974 0.0588 ...
##  $ V13: num  1.095 0.543 0.746 0.496 0.757 ...
##  $ V14: num  0.905 0.734 0.787 1.156 0.781 ...
##  $ V15: num  8.59 3.4 4.58 3.44 5.44 ...
##  $ V16: num  153.4 74.1 94 27.2 94.4 ...
##  $ V17: num  0.0064 0.00522 0.00615 0.00911 0.01149 ...
##  $ V18: num  0.049 0.0131 0.0401 0.0746 0.0246 ...
##  $ V19: num  0.0537 0.0186 0.0383 0.0566 0.0569 ...
##  $ V20: num  0.0159 0.0134 0.0206 0.0187 0.0188 ...
##  $ V21: num  0.03 0.0139 0.0225 0.0596 0.0176 ...
##  $ V22: num  0.00619 0.00353 0.00457 0.00921 0.00511 ...
##  $ V23: num  25.4 25 23.6 14.9 22.5 ...
##  $ V24: num  17.3 23.4 25.5 26.5 16.7 ...
##  $ V25: num  184.6 158.8 152.5 98.9 152.2 ...
##  $ V26: num  2019 1956 1709 568 1575 ...
##  $ V27: num  0.162 0.124 0.144 0.21 0.137 ...
##  $ V28: num  0.666 0.187 0.424 0.866 0.205 ...
##  $ V29: num  0.712 0.242 0.45 0.687 0.4 ...
##  $ V30: num  0.265 0.186 0.243 0.258 0.163 ...
##  $ V31: num  0.46 0.275 0.361 0.664 0.236 ...
##  $ V32: num  0.1189 0.089 0.0876 0.173 0.0768 ...

Nuestro dataframe está compuesto por 569 observaciones de 32 variables. La primera variable representa un código de identificación que en el caso que nos ocupa no tiene ninguna utilidad por lo que podremos eliminarlo más adelante. La segunda variable representa el resultado de la biopsia como “B” en caso de tratarse de un tumor benigno y con “M” en el caso de tumor maligno. Las 30 variables restantes representan diferentes características del núcleo de la célula. Realmente se miden 10 características pero de cada una de ellas se representan con 3 valores: media, error estandar, el mayor valor de:

Dado que el dataframe no contiene cabecera, será necesario incluirla y asi facilitar el trabajo posterior de análisis. Para ayudarnos en la denominación de cada una de las variables es recomendable revisar el documento breast-cancer-wiscosin.names que contiene un breve descripción de todas las variables y como están organizadas en el dataframe.

Vamos a añadir las cabeceras al dataframe original. Conviene resaltar que los nombres de las variables deben ser lo suficientemente explícitos como para poder entender el contenido de las mismas a simple vista. Para ello vamos a crear un vector de nombres con 32 elementos que contendrá el nombre de las variables de forma descriptiva.

Las observaciones están organizadas en el dataframe de manera que de la columna 3 al 12 serán los valores medios de las variables del 13 al 22 serán los errores estandar y del 23 al 32 serán los valores máximos. La columna 1 corresponde al ID de la obserbación y la columna 2 el diagnóstico.

La siguiente secuencia de comandos nos permite crear la cabecera con el nombre de todas las variables y en el orden correcto en el dataframe.

basic_names <- c("Radius","Texture","Perimeter","Area","Smoothness","Compactness","Concavity","Concave_Points","Simmetry","Fractal_Dimension")
basic_names_mean <- paste(basic_names,"Mean",sep="_") 
basic_names_error_st <- paste(basic_names,"ErrorST", sep="_")
basic_names_largest <- paste(basic_names,"Largest",sep="_")
data_names <- c("ID","Diagnosis",basic_names_mean, basic_names_error_st, basic_names_largest)
print(data_names)
##  [1] "ID"                        "Diagnosis"                
##  [3] "Radius_Mean"               "Texture_Mean"             
##  [5] "Perimeter_Mean"            "Area_Mean"                
##  [7] "Smoothness_Mean"           "Compactness_Mean"         
##  [9] "Concavity_Mean"            "Concave_Points_Mean"      
## [11] "Simmetry_Mean"             "Fractal_Dimension_Mean"   
## [13] "Radius_ErrorST"            "Texture_ErrorST"          
## [15] "Perimeter_ErrorST"         "Area_ErrorST"             
## [17] "Smoothness_ErrorST"        "Compactness_ErrorST"      
## [19] "Concavity_ErrorST"         "Concave_Points_ErrorST"   
## [21] "Simmetry_ErrorST"          "Fractal_Dimension_ErrorST"
## [23] "Radius_Largest"            "Texture_Largest"          
## [25] "Perimeter_Largest"         "Area_Largest"             
## [27] "Smoothness_Largest"        "Compactness_Largest"      
## [29] "Concavity_Largest"         "Concave_Points_Largest"   
## [31] "Simmetry_Largest"          "Fractal_Dimension_Largest"

Ahora simplemente tenemos que modificar nuestro dataframe original con los nombres de las variables que hemos obtenido. Para ello crearemos una copia del data frame original y trabajaremos sobre este último hasta darle un formato acorde con los análisis que queremos realizar.

data_ok <- data
names(data_ok)<-data_names
summary(data_ok)
##        ID            Diagnosis  Radius_Mean      Texture_Mean  
##  Min.   :     8670   B:357     Min.   : 6.981   Min.   : 9.71  
##  1st Qu.:   869218   M:212     1st Qu.:11.700   1st Qu.:16.17  
##  Median :   906024             Median :13.370   Median :18.84  
##  Mean   : 30371831             Mean   :14.127   Mean   :19.29  
##  3rd Qu.:  8813129             3rd Qu.:15.780   3rd Qu.:21.80  
##  Max.   :911320502             Max.   :28.110   Max.   :39.28  
##  Perimeter_Mean     Area_Mean      Smoothness_Mean   Compactness_Mean 
##  Min.   : 43.79   Min.   : 143.5   Min.   :0.05263   Min.   :0.01938  
##  1st Qu.: 75.17   1st Qu.: 420.3   1st Qu.:0.08637   1st Qu.:0.06492  
##  Median : 86.24   Median : 551.1   Median :0.09587   Median :0.09263  
##  Mean   : 91.97   Mean   : 654.9   Mean   :0.09636   Mean   :0.10434  
##  3rd Qu.:104.10   3rd Qu.: 782.7   3rd Qu.:0.10530   3rd Qu.:0.13040  
##  Max.   :188.50   Max.   :2501.0   Max.   :0.16340   Max.   :0.34540  
##  Concavity_Mean    Concave_Points_Mean Simmetry_Mean   
##  Min.   :0.00000   Min.   :0.00000     Min.   :0.1060  
##  1st Qu.:0.02956   1st Qu.:0.02031     1st Qu.:0.1619  
##  Median :0.06154   Median :0.03350     Median :0.1792  
##  Mean   :0.08880   Mean   :0.04892     Mean   :0.1812  
##  3rd Qu.:0.13070   3rd Qu.:0.07400     3rd Qu.:0.1957  
##  Max.   :0.42680   Max.   :0.20120     Max.   :0.3040  
##  Fractal_Dimension_Mean Radius_ErrorST   Texture_ErrorST 
##  Min.   :0.04996        Min.   :0.1115   Min.   :0.3602  
##  1st Qu.:0.05770        1st Qu.:0.2324   1st Qu.:0.8339  
##  Median :0.06154        Median :0.3242   Median :1.1080  
##  Mean   :0.06280        Mean   :0.4052   Mean   :1.2169  
##  3rd Qu.:0.06612        3rd Qu.:0.4789   3rd Qu.:1.4740  
##  Max.   :0.09744        Max.   :2.8730   Max.   :4.8850  
##  Perimeter_ErrorST  Area_ErrorST     Smoothness_ErrorST
##  Min.   : 0.757    Min.   :  6.802   Min.   :0.001713  
##  1st Qu.: 1.606    1st Qu.: 17.850   1st Qu.:0.005169  
##  Median : 2.287    Median : 24.530   Median :0.006380  
##  Mean   : 2.866    Mean   : 40.337   Mean   :0.007041  
##  3rd Qu.: 3.357    3rd Qu.: 45.190   3rd Qu.:0.008146  
##  Max.   :21.980    Max.   :542.200   Max.   :0.031130  
##  Compactness_ErrorST Concavity_ErrorST Concave_Points_ErrorST
##  Min.   :0.002252    Min.   :0.00000   Min.   :0.000000      
##  1st Qu.:0.013080    1st Qu.:0.01509   1st Qu.:0.007638      
##  Median :0.020450    Median :0.02589   Median :0.010930      
##  Mean   :0.025478    Mean   :0.03189   Mean   :0.011796      
##  3rd Qu.:0.032450    3rd Qu.:0.04205   3rd Qu.:0.014710      
##  Max.   :0.135400    Max.   :0.39600   Max.   :0.052790      
##  Simmetry_ErrorST   Fractal_Dimension_ErrorST Radius_Largest 
##  Min.   :0.007882   Min.   :0.0008948         Min.   : 7.93  
##  1st Qu.:0.015160   1st Qu.:0.0022480         1st Qu.:13.01  
##  Median :0.018730   Median :0.0031870         Median :14.97  
##  Mean   :0.020542   Mean   :0.0037949         Mean   :16.27  
##  3rd Qu.:0.023480   3rd Qu.:0.0045580         3rd Qu.:18.79  
##  Max.   :0.078950   Max.   :0.0298400         Max.   :36.04  
##  Texture_Largest Perimeter_Largest  Area_Largest    Smoothness_Largest
##  Min.   :12.02   Min.   : 50.41    Min.   : 185.2   Min.   :0.07117   
##  1st Qu.:21.08   1st Qu.: 84.11    1st Qu.: 515.3   1st Qu.:0.11660   
##  Median :25.41   Median : 97.66    Median : 686.5   Median :0.13130   
##  Mean   :25.68   Mean   :107.26    Mean   : 880.6   Mean   :0.13237   
##  3rd Qu.:29.72   3rd Qu.:125.40    3rd Qu.:1084.0   3rd Qu.:0.14600   
##  Max.   :49.54   Max.   :251.20    Max.   :4254.0   Max.   :0.22260   
##  Compactness_Largest Concavity_Largest Concave_Points_Largest
##  Min.   :0.02729     Min.   :0.0000    Min.   :0.00000       
##  1st Qu.:0.14720     1st Qu.:0.1145    1st Qu.:0.06493       
##  Median :0.21190     Median :0.2267    Median :0.09993       
##  Mean   :0.25427     Mean   :0.2722    Mean   :0.11461       
##  3rd Qu.:0.33910     3rd Qu.:0.3829    3rd Qu.:0.16140       
##  Max.   :1.05800     Max.   :1.2520    Max.   :0.29100       
##  Simmetry_Largest Fractal_Dimension_Largest
##  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

Ya tenemos nuestro dataframe con los nombres de las variables suficientemente descriptivos.

La variable ID no tendrá ninguna utilidad en nuestro clasificador por lo que la vamos a eliminar del dataframe.

data_ok$ID <- NULL

A continuación vamos a comprobar si todas las observaciones están completas y no falta ningún valor. Si se diera el caso, tendriamos que decidir si omitir las observaciones incompletas o completar las mismas con valores promedio.

colSums(is.na(data_ok))
##                 Diagnosis               Radius_Mean 
##                         0                         0 
##              Texture_Mean            Perimeter_Mean 
##                         0                         0 
##                 Area_Mean           Smoothness_Mean 
##                         0                         0 
##          Compactness_Mean            Concavity_Mean 
##                         0                         0 
##       Concave_Points_Mean             Simmetry_Mean 
##                         0                         0 
##    Fractal_Dimension_Mean            Radius_ErrorST 
##                         0                         0 
##           Texture_ErrorST         Perimeter_ErrorST 
##                         0                         0 
##              Area_ErrorST        Smoothness_ErrorST 
##                         0                         0 
##       Compactness_ErrorST         Concavity_ErrorST 
##                         0                         0 
##    Concave_Points_ErrorST          Simmetry_ErrorST 
##                         0                         0 
## Fractal_Dimension_ErrorST            Radius_Largest 
##                         0                         0 
##           Texture_Largest         Perimeter_Largest 
##                         0                         0 
##              Area_Largest        Smoothness_Largest 
##                         0                         0 
##       Compactness_Largest         Concavity_Largest 
##                         0                         0 
##    Concave_Points_Largest          Simmetry_Largest 
##                         0                         0 
## Fractal_Dimension_Largest 
##                         0

Podemos comprobar como en nuestro dataframe todas las observaciones están completas y por tanto continuar con el análisis.

Observamos ahora los rangos de valores que toman cada una de las variables. En algunos casos hay grandes variaciones en magnitud por lo que será recomendable normalizar los mismos entre 0 y 1 en todos los casos.

summary(data_ok)
##  Diagnosis  Radius_Mean      Texture_Mean   Perimeter_Mean  
##  B:357     Min.   : 6.981   Min.   : 9.71   Min.   : 43.79  
##  M:212     1st Qu.:11.700   1st Qu.:16.17   1st Qu.: 75.17  
##            Median :13.370   Median :18.84   Median : 86.24  
##            Mean   :14.127   Mean   :19.29   Mean   : 91.97  
##            3rd Qu.:15.780   3rd Qu.:21.80   3rd Qu.:104.10  
##            Max.   :28.110   Max.   :39.28   Max.   :188.50  
##    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 Simmetry_Mean    Fractal_Dimension_Mean
##  Min.   :0.00000     Min.   :0.1060   Min.   :0.04996       
##  1st Qu.:0.02031     1st Qu.:0.1619   1st Qu.:0.05770       
##  Median :0.03350     Median :0.1792   Median :0.06154       
##  Mean   :0.04892     Mean   :0.1812   Mean   :0.06280       
##  3rd Qu.:0.07400     3rd Qu.:0.1957   3rd Qu.:0.06612       
##  Max.   :0.20120     Max.   :0.3040   Max.   :0.09744       
##  Radius_ErrorST   Texture_ErrorST  Perimeter_ErrorST  Area_ErrorST    
##  Min.   :0.1115   Min.   :0.3602   Min.   : 0.757    Min.   :  6.802  
##  1st Qu.:0.2324   1st Qu.:0.8339   1st Qu.: 1.606    1st Qu.: 17.850  
##  Median :0.3242   Median :1.1080   Median : 2.287    Median : 24.530  
##  Mean   :0.4052   Mean   :1.2169   Mean   : 2.866    Mean   : 40.337  
##  3rd Qu.:0.4789   3rd Qu.:1.4740   3rd Qu.: 3.357    3rd Qu.: 45.190  
##  Max.   :2.8730   Max.   :4.8850   Max.   :21.980    Max.   :542.200  
##  Smoothness_ErrorST Compactness_ErrorST Concavity_ErrorST
##  Min.   :0.001713   Min.   :0.002252    Min.   :0.00000  
##  1st Qu.:0.005169   1st Qu.:0.013080    1st Qu.:0.01509  
##  Median :0.006380   Median :0.020450    Median :0.02589  
##  Mean   :0.007041   Mean   :0.025478    Mean   :0.03189  
##  3rd Qu.:0.008146   3rd Qu.:0.032450    3rd Qu.:0.04205  
##  Max.   :0.031130   Max.   :0.135400    Max.   :0.39600  
##  Concave_Points_ErrorST Simmetry_ErrorST   Fractal_Dimension_ErrorST
##  Min.   :0.000000       Min.   :0.007882   Min.   :0.0008948        
##  1st Qu.:0.007638       1st Qu.:0.015160   1st Qu.:0.0022480        
##  Median :0.010930       Median :0.018730   Median :0.0031870        
##  Mean   :0.011796       Mean   :0.020542   Mean   :0.0037949        
##  3rd Qu.:0.014710       3rd Qu.:0.023480   3rd Qu.:0.0045580        
##  Max.   :0.052790       Max.   :0.078950   Max.   :0.0298400        
##  Radius_Largest  Texture_Largest Perimeter_Largest  Area_Largest   
##  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_Largest Compactness_Largest Concavity_Largest
##  Min.   :0.07117    Min.   :0.02729     Min.   :0.0000   
##  1st Qu.:0.11660    1st Qu.:0.14720     1st Qu.:0.1145   
##  Median :0.13130    Median :0.21190     Median :0.2267   
##  Mean   :0.13237    Mean   :0.25427     Mean   :0.2722   
##  3rd Qu.:0.14600    3rd Qu.:0.33910     3rd Qu.:0.3829   
##  Max.   :0.22260    Max.   :1.05800     Max.   :1.2520   
##  Concave_Points_Largest Simmetry_Largest Fractal_Dimension_Largest
##  Min.   :0.00000        Min.   :0.1565   Min.   :0.05504          
##  1st Qu.:0.06493        1st Qu.:0.2504   1st Qu.:0.07146          
##  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

También podemos visualizar gráficamente la relación existente entre cada una de las variables y si dicha relación podría ayudarnos a clasificar la tipología del tumor. Dado que el número de variables es elevado no podemos representar en un único gráfico la matriz gráfica de correlaciones. Esta tarea la llevaremos a cabo mediante tres matrices de correlación diferentes aprovechando que las variables ya se encuentran agrupadas en tres grupos dentro del dataframe: Mean, ErrorST y Largest:

panel.cor <- function(x,y) {
  par(usr=c(0,1,0,1))
  r <- as.character(round(cor(x,y,method="pearson"),2)) # por defecto la función cor() calcula el coeficiente de correlación de Pearson como medida de la correlación lineal
  txt <- paste0("R = ", r)
  text(0.5, 0.5, txt, cex = 1)
}
upper.panel<-function(x,y) {
  points(x,y, pch=19, cex=0.5, col =c("green","red")[data_ok$Diagnosis])
}
pairs(data_ok[2:11], main="Mean Char.", lower.panel = panel.cor, upper.panel = upper.panel)

pairs(data_ok[12:21], main="Std Error Char.", lower.panel = panel.cor, upper.panel = upper.panel)

pairs(data_ok[22:31], main="Largest Char.", lower.panel = panel.cor, upper.panel = upper.panel)

A la vista de los resultados, puede resultar interesante hacer un zoom específico sobre alguna de estas relacciones para visualizar con más detalle el agrupamiento que se produce:

library(ggplot2)
qplot(Radius_Mean, Perimeter_Mean, data=data_ok, col =Diagnosis, geom=c("point","smooth"), main = "????")
## `geom_smooth()` using method = 'loess'

En ambos gráficos puede observarse una interesante dependencia de las variables usadas que podrían determinar el tipo de vino. Del mismo modo también sería posible a través de estos análisis previos eliminar alguna variable si consideramos que la misma no colabora positivamente a realizar la clasificación.