Los datos proceden de un estudio sobre diagnóstico del cáncer de mama por imagen. Mediante una punción con aguja fina se extrae una muestra del tejido sospechoso de la paciente. La muestra se tiñe para resaltar los núcleos de las células y se determinan los límites exactos de los núcleos. Las variables consideradas corresponden a distintos aspectos de la forma del núcleo. El fichero contiene un data frame, llamado breast.cancer2, con 2 variables explicativas medidas en pacientes cuyos tumores fueron diagnosticados posteriormente como benignos o malignos y el factor y que toma los valores 0 o 1 en función de si las variables corresponden a un tumor benigno o maligno respectivamente.
En este ejemplo se testearán diferentes algoritmos de aprendizaje para determinar cuál de ellos obtiene mejores resultado en la predicción de los diagnósticos.
if (!require("caret")) { install.packages("caret"); library(caret) }
if (!require("ggplot2")) { install.packages("ggplot2"); library(ggplot2) }
if (!require("lattice")) { install.packages("lattice"); library(lattice) }
load('breastCancer.RData')
dataCancer=breast.cancer2
head(dataCancer)
summary(dataCancer)
x.smoothness x.concavepoints y
Min. :0.05263 Min. :0.00000 0:357
1st Qu.:0.08637 1st Qu.:0.02031 1:212
Median :0.09587 Median :0.03350
Mean :0.09636 Mean :0.04892
3rd Qu.:0.10530 3rd Qu.:0.07400
Max. :0.16340 Max. :0.20120
Realizaremos una representación gráfica de los datos, dibujando en dos colores diferentes aquellos casos en los que el diagnóstico ha sido benigno o maligno.
summary(dataCancer)
x.smoothness x.concavepoints y
Min. :0.05263 Min. :0.00000 0:357
1st Qu.:0.08637 1st Qu.:0.02031 1:212
Median :0.09587 Median :0.03350
Mean :0.09636 Mean :0.04892
3rd Qu.:0.10530 3rd Qu.:0.07400
Max. :0.16340 Max. :0.20120
ggplot(dataCancer, aes(x=dataCancer$x.smoothness, y=dataCancer$x.concavepoints, color=y))+
geom_point()
Si queremos ver cómo está distribuido el dataset en cuanto a tipos de cancer
#Es binario
ggplot(dataCancer, aes(x = y, color = y)) + geom_bar(stat = "count", aes(fill = y))
Para dividir los datos en una muestra de entrenamiento y otra de test se usa el comando createDataPartition. En el código siguiente p representa la proporción de datos en la muestra de entrenamiento. La partición se lleva a cabo para cada nivel de la variable y que aparece como primer argumento. El resultado es un vector con los índices de las filas seleccionadas para formar parte de la muestra de entrenamiento.
Un aspecto importante, sobre todo pensando en la reproducibilidad de nuestro trabajo, es que si iniciamos al generador de números aleatorios con un valor determinado, la secuencia de números pseudo-aleatorios se va a repetir y por lo tanto podemos reproducir exactamente una simulación estocástica.R utiliza la función set.seed(numero entero) para inicializar el generador de números aleatorios.
set.seed(100) # Para reproducir los mismos resultados
IndicesEntrenamiento <- createDataPartition(y = dataCancer$y,
p = 0.75,
list = FALSE)
Entrenamiento <- dataCancer[IndicesEntrenamiento,]
Test <- dataCancer[-IndicesEntrenamiento,]
Es importante verificar que la distribución de la variable respuesta es similar en el conjunto de entrenamiento y en el de test. Por defecto, la función createDataPartition() garantiza una distribución aproximada.
# Porcentajes en el dataset original de cada una de las clases
prop.table(table(dataCancer$y))
0 1
0.6274165 0.3725835
#Numero de elementos de cada clase en el dataset de entrenamiento
table(Entrenamiento$y)
0 1
268 159
prop.table(table(Entrenamiento$y))
0 1
0.6276347 0.3723653
#Numero de elementos de cada clase en el dataset de test
table(Test$y)
0 1
89 53
prop.table(table(Test$y))
0 1
0.6267606 0.3732394
En efecto, vemos que para ambos conjuntos, la relación benigo/maligno se mantiene.
Se puede usar este comando único para aplicar un gran número de métodos de clasificación determinando (en caso necesario) los valores óptimos de sus parámetros mediante validación cruzada u otros métodos de remuestreo. Para usar train en general es necesario:
Elegir el método de clasificación que queremos usar. El catálogo de todos los métodos disponibles se puede consultar en este enlace. Una información técnica detallada de cada método se puede obtener con el comando getModelInfo.
Si el método de clasificación requiere determinar parámetros, es necesario fijar cuáles y en qué rango de valores.
También hay que definir el método de remuestreo que se va a utilizar para determinar estos parámetros.
Vamos a entrenar el modelo con el método KNN. Al visualizar el modelo obtenido, se obtiene una tabla donde se muestran las diferentes k’s utilizadas, de la cual se elegirá aquella cuya precisión sea mayor.
modeloKNN <- train(y ~ ., data = Entrenamiento, method = "knn")
modeloKNN
k-Nearest Neighbors
427 samples
2 predictor
2 classes: '0', '1'
No pre-processing
Resampling: Bootstrapped (25 reps)
Summary of sample sizes: 427, 427, 427, 427, 427, 427, ...
Resampling results across tuning parameters:
k Accuracy Kappa
5 0.8957298 0.777192
7 0.9015849 0.788328
9 0.9064723 0.798766
Accuracy was used to select the optimal model using the largest value.
The final value used for the model was k = 9.
# Predict
predictKNN <- predict(modeloKNN, Test)
# Genera una matriz de confusion
confusionMatrix(predictKNN, Test$y)$table
# Mostrar la precision
confusionMatrix(predictKNN, Test$y)$overall
Revisar el siguiente link (https://rdrr.io/cran/caret/man/confusionMatrix.html) para ver cómo obtener los valores de la precisión de la tabla de confusión.
modeloTrees <- train(y ~ ., data = Entrenamiento, method = "rpart")
modeloTrees
CART
427 samples
2 predictor
2 classes: '0', '1'
No pre-processing
Resampling: Bootstrapped (25 reps)
Summary of sample sizes: 427, 427, 427, 427, 427, 427, ...
Resampling results across tuning parameters:
cp Accuracy Kappa
0.00000000 0.8879192 0.7561404
0.01572327 0.9116285 0.8065149
0.78616352 0.7860269 0.4479170
Accuracy was used to select the optimal model using the largest value.
The final value used for the model was cp = 0.01572327.
#rpart.plot(modeloTrees$finalModel, main="Classification Tree2")
# Predict
predictTrees <- predict(modeloTrees, Test)
# Genera una matriz de confusion
confusionMatrix(predictTrees, Test$y)$table
Reference
Prediction 0 1
0 79 4
1 10 49
# Mostrar la precision
confusionMatrix(predictTrees, Test$y)$overall
Accuracy Kappa AccuracyLower AccuracyUpper AccuracyNull AccuracyPValue
9.014085e-01 7.939896e-01 8.401141e-01 9.450435e-01 6.267606e-01 1.063270e-13
McnemarPValue
1.814492e-01
modelSVM <- train(y ~ ., data = Entrenamiento, method = "svmLinear")
modelSVM
Support Vector Machines with Linear Kernel
427 samples
2 predictor
2 classes: '0', '1'
No pre-processing
Resampling: Bootstrapped (25 reps)
Summary of sample sizes: 427, 427, 427, 427, 427, 427, ...
Resampling results:
Accuracy Kappa
0.9184446 0.8221616
Tuning parameter 'C' was held constant at a value of 1
# Predict
predictSVN <- predict(modelSVM, Test)
# Genera una matriz de confusion
confusionMatrix(predictSVN, Test$y)$table
Reference
Prediction 0 1
0 81 7
1 8 46
# Mostrar la precision
confusionMatrix(predictSVN, Test$y)$overall
Accuracy Kappa AccuracyLower AccuracyUpper AccuracyNull AccuracyPValue
8.943662e-01 7.750792e-01 8.317627e-01 9.396605e-01 6.267606e-01 5.498251e-13
McnemarPValue
1.000000e+00
modeloRForest <- train(y ~ ., data = Entrenamiento, method = "cforest")
note: only 1 unique complexity parameters in default grid. Truncating the grid to 1 .
modeloRForest
Conditional Inference Random Forest
427 samples
2 predictor
2 classes: '0', '1'
No pre-processing
Resampling: Bootstrapped (25 reps)
Summary of sample sizes: 427, 427, 427, 427, 427, 427, ...
Resampling results:
Accuracy Kappa
0.909362 0.8044448
Tuning parameter 'mtry' was held constant at a value of 2
# Predict
predictRF <- predict(modeloRForest, Test)
# Genera una matriz de confusion
confusionMatrix(predictRF, Test$y)$table
Reference
Prediction 0 1
0 80 7
1 9 46
# Mostrar la precision
confusionMatrix(predictRF, Test$y)$overall
Accuracy Kappa AccuracyLower AccuracyUpper AccuracyNull AccuracyPValue
8.873239e-01 7.609931e-01 8.234763e-01 9.342073e-01 6.267606e-01 2.646163e-12
McnemarPValue
8.025873e-01
¿Qué modelo es más preciso? Podemos ver que el metodo SVN tiene precision del 100% y accuracy del 89%, pero como el metodo KNN tiene presicion del 100% y accurary del 90%, eligiriamos el KNN.