Carga de librerias
library(neuralnet) # Para el algoritmo redes neuronales
library(randomForest) # Para el algoritmo Bosque Aleatorio
## randomForest 4.7-1.1
## Type rfNews() to see new features/changes/bug fixes.
library(readxl)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:randomForest':
##
## combine
## The following object is masked from 'package:neuralnet':
##
## compute
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
##
## Attaching package: 'ggplot2'
## The following object is masked from 'package:randomForest':
##
## margin
library(corrplot)
## corrplot 0.92 loaded
library(ggcorrplot)
BreastFinal <- read_excel("E:/U-MAQUINAS DE APRENDIZAJE/EXAMEN FINAL/BreastFinal.xlsx")
BreastFinal$Class<-as.factor(BreastFinal$Class)
Variable target: clases de tejido
- car: carcinoma
- fad: fibroadenoma
- mas: Mastopatía
- gla: Glandular
- con: Conectivo
- adi: Adiposo
Variables predictoras: - Impedancia (ohm) a frecuencia cero
(I0)
- Ángulo de fase a 500 KHz (PA500)
- Pendiente de alta frecuencia del ángulo de fase (HFS)
- Distancia de impedancia entre extremos espectrales (DA)
- Área bajo el espectro (AREA)
- Área normalizada por DA (A.DA)
- Máximo del espectro (Max.IP)
- Distancia entre I0 y parte real del punto de máxima frecuencia
(DR)
- Longitud de la curva espectral (P)
Renombramos las siguientes 2 columnas para no usar caracteres especiales:
BreastFinal<-BreastFinal %>% rename (A.DA = `A/DA`, Max.IP = `Max IP`)
head(BreastFinal)
dim(BreastFinal)
## [1] 106 11
summary(BreastFinal)
## Case # Class I0 PA500
## Min. : 1.00 adi:22 Min. : 103.0 Min. :0.01239
## 1st Qu.: 27.25 car:21 1st Qu.: 250.0 1st Qu.:0.06741
## Median : 53.50 con:14 Median : 384.9 Median :0.10542
## Mean : 53.50 fad:15 Mean : 784.3 Mean :0.12013
## 3rd Qu.: 79.75 gla:16 3rd Qu.:1488.0 3rd Qu.:0.16960
## Max. :106.00 mas:18 Max. :2800.0 Max. :0.35832
## HFS DA Area A.DA
## Min. :-0.06632 Min. : 19.65 Min. : 70.43 Min. : 1.596
## 1st Qu.: 0.04398 1st Qu.: 53.85 1st Qu.: 409.65 1st Qu.: 8.180
## Median : 0.08657 Median : 120.78 Median : 2219.58 Median : 16.134
## Mean : 0.11469 Mean : 190.57 Mean : 7335.16 Mean : 23.474
## 3rd Qu.: 0.16650 3rd Qu.: 255.33 3rd Qu.: 7615.20 3rd Qu.: 30.953
## Max. : 0.46775 Max. :1063.44 Max. :174480.48 Max. :164.072
## Max.IP DR P
## Min. : 7.969 Min. : -9.258 Min. : 125.0
## 1st Qu.: 26.894 1st Qu.: 41.781 1st Qu.: 270.2
## Median : 44.216 Median : 97.833 Median : 454.1
## Mean : 75.381 Mean :166.711 Mean : 810.6
## 3rd Qu.: 83.672 3rd Qu.:232.990 3rd Qu.:1301.6
## Max. :436.100 Max. :977.552 Max. :2896.6
I0: El valor medio de esta variable es mayor que su mediana. Esto
indica una distribución asimétrica a la derecha. La distribución de la
variable tiene una diferencia bastante grande entre sus valores mínimo y
máximo.
PA500: La mediana de esta variable es inferior a su valor medio. Esto
indica una distribución asimétrica a la izquierda. La distribución de la
variable tiene una diferencia bastante grande entre sus valores mínimo y
máximo.
HFS: La mediana de esta variable es ligeramente inferior a su valor
medio. Esto indica una distribución ligeramente sesgada hacia la
izquierda. La distribución de la variable tiene una menor diferencia
entre sus valores mínimo y máximo.
DA: El valor medio de esta variable es mayor que su mediana. Esto indica
una distribución asimétrica a la derecha. La distribución de la variable
tiene una diferencia bastante grande entre sus valores mínimo y
máximo.
Área: El valor medio de esta variable es mucho mayor que su mediana.
Esto indica una distribución asimétrica a la derecha. La distribución de
la variable tiene una diferencia bastante grande entre sus valores
mínimo y máximo.
A.DA: El valor medio de esta variable es mayor que su mediana. Esto
indica una distribución asimétrica a la derecha. La distribución de la
variable tiene una diferencia bastante grande entre sus valores mínimo y
máximo.
Max.IP: La mediana de esta variable es ligeramente inferior a su valor
medio. Esto indica una distribución ligeramente sesgada hacia la
izquierda. La distribución de la variable tiene una diferencia bastante
grande entre sus valores mínimo y máximo.
DR: La mediana de esta variable es menor que su valor medio. Esto indica
una distribución asimétrica a la izquierda. La distribución de la
variable tiene una diferencia bastante grande entre sus valores mínimo y
máximo.
P: El valor medio de esta variable es mucho mayor que su mediana. Esto
indica una distribución asimétrica a la derecha. La distribución de la
variable tiene una diferencia bastante grande entre sus valores mínimo y
máximo.
sum(is.na(BreastFinal))
## [1] 0
No existen valores perdidos en la data.
Tabla_class <- BreastFinal%>% group_by(Class) %>% summarise(Total=n()) %>% mutate(Porcentaje = round(Total/sum(Total)*100, 1))
ggplot(Tabla_class, aes(x = Class, y=Total,fill=Class) ) +
geom_bar(width = 0.9, stat="identity", position = position_dodge())+
ylim(c(0,100))+
labs(x="Clase de tejido", y= "Frecuencia \n (Porcentajes)") +
labs(fill = "")+
geom_text(aes(label=paste0(Total," ", "", "(", Porcentaje, "%",")")), vjust=-0.9, color="black", hjust=0.5,position = position_dodge(0.9), angle=0, size=4.0) +
scale_fill_discrete(name = "Clase", labels = c("adi", "car", "con", "fat", "gla", "mas")) +
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) +
facet_wrap(~"Variable Class")
Se observa que la data esta balanceada, ya que los porcentajes de cada clase son superiores al 10%.
ggplot(BreastFinal, aes(x = DA, y = I0)) +
geom_point(aes(color = factor(Class))) +
labs(x = "Distancia de impedancia entre extremos espectrales \n DA",
y = "Impedancia (ohm) a frecuencia cero \n I0",
title = "Grafico de dispersion")
Se observa que en la dispersión que las variables DA y I0, están separando bien a las clases diferenciados por los colores.
ggplot(BreastFinal, aes(x=PA500, y=HFS)) +
geom_point(aes(color = Class)) +
geom_smooth(method = "lm", col = "#C42126", se = FALSE, size = 1)+
labs(x = "Ángulo de fase a 500 KHz \n PA500",
y = "Pendiente de alta frecuencia del ángulo de fase \n HFS",
title = "Grafico de dispersion")
## `geom_smooth()` using formula = 'y ~ x'
Se observa que en la dispersión que las variables PA500 y HFS se pueden ajustar a un modelo de regresión lineal.
ggplot(BreastFinal, aes(x = DA, y = A.DA)) +
geom_point(aes(color = Class)) +
geom_smooth(method = "lm", col = "#C42126", se = FALSE, size = 1) +
labs(x = "Distancia de impedancia entre extremos espectrales",
y = "Área normalizada por DA ",
title = "Grafico de dispersion")
## `geom_smooth()` using formula = 'y ~ x'
Se observa que en la dispersión que las variables DA y A.DA, están separando bien a las clases diferenciados por los colores.
par(mfrow= c(2,5))
for ( i in 3 : ncol ( BreastFinal ) ) {
boxplot ( BreastFinal [ , i ] , main = names(BreastFinal) [ i ] ,
col = rainbow(ncol(BreastFinal)-2),
notch = T)
}
par(mfrow= c(3,3))
boxplot(formula = I0 ~ Class, data = BreastFinal)
boxplot(formula = PA500 ~ Class, data = BreastFinal)
boxplot(formula = HFS ~ Class, data = BreastFinal)
boxplot(formula = DA ~ Class, data = BreastFinal)
boxplot(formula = Area ~ Class, data = BreastFinal)
boxplot(formula = A.DA ~ Class, data = BreastFinal)
boxplot(formula = Max.IP ~ Class, data = BreastFinal)
boxplot(formula = DR ~ Class, data = BreastFinal)
boxplot(formula = P ~ Class, data = BreastFinal)
Cuando se analiza el box plot de cada una de las variables, se observa que existe una diferencia significativa entre las escalas. Por esta razón, el conjunto de datos debe estandarizarse. También por el elevado número de observaciones atípicas que se observan en algunas variables.
ggplot(BreastFinal, aes(x=DR, y=P, fill=Class)) +geom_area() +
labs(x="Distancia entre I0 y parte real del punto de máxima frecuencia \n DR",
y="Longitud de la curva espectral \n P",
title= "Grafico de Area")
Se observa en el gráfico de áreas que las variables DR y P, están separando bien a las clases diferenciandolos por los colores.
corr=cor_pmat(BreastFinal[3:11])
head(corr)
## I0 PA500 HFS DA Area
## I0 0.000000e+00 2.984613e-05 7.721654e-01 6.593602e-27 4.305070e-10
## PA500 2.984613e-05 0.000000e+00 2.524054e-08 3.598703e-01 3.945145e-01
## HFS 7.721654e-01 2.524054e-08 0.000000e+00 2.750666e-01 3.407799e-02
## DA 6.593602e-27 3.598703e-01 2.750666e-01 0.000000e+00 5.676282e-19
## Area 4.305070e-10 3.945145e-01 3.407799e-02 5.676282e-19 0.000000e+00
## A.DA 3.148793e-12 1.778436e-02 1.799832e-04 5.757673e-14 3.814249e-28
## A.DA Max.IP DR P
## I0 3.148793e-12 2.254868e-27 3.996944e-19 1.542477e-87
## PA500 1.778436e-02 6.078945e-01 4.324086e-01 2.837045e-04
## HFS 1.799832e-04 9.111752e-05 9.061169e-01 2.964251e-01
## DA 5.757673e-14 1.234475e-20 4.634323e-69 2.278755e-22
## Area 3.814249e-28 2.859278e-19 1.901359e-15 1.247825e-10
## A.DA 0.000000e+00 3.739071e-26 2.190473e-09 1.190821e-15
ggcorrplot(corr) + labs(title = "CORELLOGRAM")
En esta matriz el mayor coeficiente de correlación se observa entre DR y HSF con 0.9061. Esto indica una fuerte relación lineal positiva entre DR y HSF. El segundo coeficiente de correlación más alto se observa entre entre I0 y HSF con 0.772. Esto indica una fuerte relación lineal positiva entre I0 y HSF.
Los coeficiente de correlación cercanos a cero se observan en los cruces de la variables donde los cuadros no están coloreados.
Como la variable DR y HFS, I0 y HFS, DR y PA500, DA y PA500, tienen buena correlación entonces eliminamos a la variable HFS, DR y PA500, ya que las 6 variables que queden podrian representar un mejor modelo, ademas de los análisis graficos tambien podemos corroborar ello.
BreastFinal<-BreastFinal[,c(-1,-4,-5,-10)]
70% Data de entrenamiento y 30% de evaluación
set.seed(888)
BreastFinal.train.idx <- sample(x = nrow(BreastFinal), size = nrow(BreastFinal)*0.70)
BreastFinal.train <- BreastFinal[BreastFinal.train.idx,]
BreastFinal.test <- BreastFinal[-BreastFinal.train.idx,]
Para la red neuroral realizaremos escalamiento dado que se corroboro en el diagrama de cajas ya que existe una diferencia significativa entre las escalas. Para ello creamos la función normalize que realiza un escalado de la variables en un rango [0,1]
normalize <- function(x) {
return ((x - min(x)) / (max(x) - min(x)))
}
BreastFinal1<-BreastFinal
BreastFinal1.train<-BreastFinal.train
BreastFinal1.test<-BreastFinal.test
BreastFinal1$I0<-normalize(BreastFinal1$I0)
BreastFinal1$DA<-normalize(BreastFinal1$DA)
BreastFinal1$Area<-normalize(BreastFinal1$Area)
BreastFinal1$A.DA<-normalize(BreastFinal1$A.DA)
BreastFinal1$Max.IP<-normalize(BreastFinal1$Max.IP)
BreastFinal1$P<-normalize(BreastFinal1$P)
BreastFinal1.train$I0<-normalize(BreastFinal1.train$I0)
BreastFinal1.train$DA<-normalize(BreastFinal1.train$DA)
BreastFinal1.train$Area<-normalize(BreastFinal1.train$Area)
BreastFinal1.train$A.DA<-normalize(BreastFinal1.train$A.DA)
BreastFinal1.train$Max.IP<-normalize(BreastFinal1.train$Max.IP)
BreastFinal1.train$P<-normalize(BreastFinal1.train$P)
BreastFinal1.test$I0<-normalize(BreastFinal1.test$I0)
BreastFinal1.test$DA<-normalize(BreastFinal1.test$DA)
BreastFinal1.test$Area<-normalize(BreastFinal1.test$Area)
BreastFinal1.test$A.DA<-normalize(BreastFinal1.test$A.DA)
BreastFinal1.test$Max.IP<-normalize(BreastFinal1.test$Max.IP)
BreastFinal1.test$P<-normalize(BreastFinal1.test$P)
Agregamos las clases
BreastFinal1$car <- BreastFinal1$Class=="car"
BreastFinal1$fad <- BreastFinal1$Class=="fad"
BreastFinal1$mas <- BreastFinal1$Class=="mas"
BreastFinal1$gla <- BreastFinal1$Class=="gla"
BreastFinal1$con <- BreastFinal1$Class=="con"
BreastFinal1$adi <- BreastFinal1$Class=="adi"
BreastFinal1.train$car <- BreastFinal1.train$Class=="car"
BreastFinal1.train$fad <- BreastFinal1.train$Class=="fad"
BreastFinal1.train$mas <- BreastFinal1.train$Class=="mas"
BreastFinal1.train$gla <- BreastFinal1.train$Class=="gla"
BreastFinal1.train$con <- BreastFinal1.train$Class=="con"
BreastFinal1.train$adi <- BreastFinal1.train$Class=="adi"
BreastFinal1.test$car <- BreastFinal1.test$Class=="car"
BreastFinal1.test$fad <- BreastFinal1.test$Class=="fad"
BreastFinal1.test$mas <- BreastFinal1.test$Class=="mas"
BreastFinal1.test$gla <- BreastFinal1.test$Class=="gla"
BreastFinal1.test$con <- BreastFinal1.test$Class=="con"
BreastFinal1.test$adi <- BreastFinal1.test$Class=="adi"
Para el random forest es un modelo basado en árboles y, por lo tanto no requiere escalado.
BreastFinal2<-BreastFinal
BreastFinal2.train<-BreastFinal.train
BreastFinal2.test<-BreastFinal.test
set.seed(111)
BreastFinal1.net <- neuralnet(car+fad+mas+gla+con+adi ~
I0+DA+Area+A.DA+Max.IP+P,
data=BreastFinal1.train,
hidden=c(10,10,10),
act.fct = 'tanh',
threshold = 0.001)
par(mfrow = c(1,1))
plot(BreastFinal1.net, rep="best")
El modelo lo generamos con 3 capas ocultas cada uno con 10, 10, 10 neuronas respectivamente usamos la función de activacion “tanh” y la red neuronal continuará iterando hasta que la mejora en el error de entrenamiento sea menor o igual a 0.001.
BreastFinal1.prediccion <- predict(BreastFinal1.net, BreastFinal1.test[,-c(8:13)])
idx <- apply(BreastFinal1.prediccion, 1, which.max)
predicted <- c('car', 'fad', 'mas','gla', 'con', 'adi')[idx]
tab<-table(predicted, BreastFinal1.test$Class)
tab
##
## predicted adi car con fad gla mas
## adi 11 0 2 0 0 0
## car 0 3 0 0 0 0
## con 0 0 4 0 0 0
## fad 0 0 0 2 0 0
## gla 0 0 0 3 1 3
## mas 0 0 0 1 2 0
sum(diag(tab)/sum(tab))
## [1] 0.65625
Se tiene una tasa de correcta clasificación del 65.625%.
Bosque aleatorio con 500 arboles y las 6 variables
set.seed(888)
modelo_bosque<-randomForest(Class~.,data=BreastFinal2.train,ntree=500,mtry=6)
modelo_bosque
##
## Call:
## randomForest(formula = Class ~ ., data = BreastFinal2.train, ntree = 500, mtry = 6)
## Type of random forest: classification
## Number of trees: 500
## No. of variables tried at each split: 6
##
## OOB estimate of error rate: 28.38%
## Confusion matrix:
## adi car con fad gla mas class.error
## adi 10 0 1 0 0 0 0.09090909
## car 0 15 0 0 0 3 0.16666667
## con 1 0 6 0 0 1 0.25000000
## fad 0 0 0 5 2 2 0.44444444
## gla 0 0 0 2 11 0 0.15384615
## mas 0 4 0 2 3 6 0.60000000
plot(modelo_bosque,main="Tasa de error Bosque Aleatorio")
legend(350,0.5,legend=colnames(modelo_bosque$err.rate),fill=1:9)
Se puede obervar como el error se mantiene constante a partir de los 500 arboles. Por lo que el uso de 500 árboles son suficientes para una óptima clasificación.
obb.values<-vector(length=(ncol(BreastFinal2)-1))
mtry<-vector(length=(ncol(BreastFinal2)-1))
for(i in 1:(ncol(BreastFinal2)-1)){
variablesmod<-randomForest(Class~.,data=BreastFinal2.train,ntree=500,mtry=i)
obb.values[i]<-variablesmod$err.rate[nrow(variablesmod$err.rate),1]
mtry[i]<-i
}
data.frame(mtry,obb.values)
Se observa que con 4 variables se obtiene el mínimo error 0.2837838 Por lo que usar 3 variables es óptimo para el modelo.
importance(modelo_bosque)
## MeanDecreaseGini
## I0 12.978606
## DA 12.028147
## Area 6.342615
## A.DA 9.177859
## Max.IP 9.984883
## P 9.421946
varImpPlot(modelo_bosque,col="violetred4",n.var=(ncol(BreastFinal2)-1),main="Variables Importantes")
Se observa que las variables mas importantes según el coeficiente de Gini son I0, DA y Max.IP .Mientras que las otras 3 variables no serian tan importantes.
table(predict(modelo_bosque,BreastFinal2.test),BreastFinal2.test$Class)
##
## adi car con fad gla mas
## adi 10 0 1 0 0 0
## car 0 2 0 0 1 0
## con 1 0 5 0 0 0
## fad 0 0 0 3 0 0
## gla 0 0 0 2 1 2
## mas 0 1 0 1 1 1
sum(predict(modelo_bosque,BreastFinal2.test)==BreastFinal2.test$Class)/ length(BreastFinal2.test$Class)*100
## [1] 68.75
De los 32 datos de la data de evaluación, fueron predichos correctamente 22 datos. El porcentaje de aciertos que obtuvo el modelo es de 68.75%, el cual es un porcentaje muy bueno.
Para analizar el modelo de red neuronal tuvimos que escalar los datos debido a la amplitud de las variables, para el modelo random forest no fue necesario ya que es robusto ante estas situaciones.
El modelo de red neuronal lo generamos con 3 capas ocultas cada una con 10, 10, 10 neuronas respectivamente usamos la función de activación “tanh” y la red neuronal continuará iterando hasta que la mejora en el error de entrenamiento sea menor o igual a 0.001. Con ello se obtuvo una tasa de correcta clasificación del 65.625%.
El modelo óptimo de bosque aleatorio tiene 500 árboles y 3 variables y con ello obtenemos una tasa de correcta clasificación del 68.75%.
El algoritmo random forest mostró una mejor clasificación sobre redes neuronales, ademas de ser mas rápido en ejecución y el mas robusto ante la presencial de posibles outliers.