TeorĂ­a

Una Red Neuronal Artificial (ANN) modela la relaciĂ³n entre un conjunto de entradas y una salida, resolviendo un problema de aprendizaje.

Ejemplos prĂ¡cticos de aplicaciĂ³n de Redes Neuronales son:

  • La recomendaciĂ³n de contenido de Netflix
  • El feed de Instagram o Tiktok
  • Determinar el nĂºmero o letra escrito a mano

Instalar paquetes y llamar librerĂ­as

# install.packages(c("neuralnet","caret","dplyr","pROC"))
suppressPackageStartupMessages({
  library(neuralnet)
  library(caret)
  library(dplyr)
  library(pROC)
})

Alimentar con ejemplos

examen   <- c(20,10,30,20,80,30)
proyecto <- c(90,20,40,50,50,80)
estatus  <- c(1,0,0,0,0,1)

df <- data.frame(examen, proyecto, estatus)

Generar la Red Neuronal

red_neuronal <- neuralnet(estatus ~ ., data = df)
plot(red_neuronal, rep = "best")

Predecir con la Red Neuronal

set.seed(123)

prueba_examen   <- c(30,40,85)
prueba_proyecto <- c(85,50,40)

# Construir data.frame con los mismos nombres de columnas que usaste al entrenar
# Si tu fĂ³rmula era: estatus ~ examen + proyecto
prueba <- data.frame(examen = prueba_examen,
                     proyecto = prueba_proyecto)

# Calcular la predicciĂ³n usando neuralnet::compute (¡clave!)
prediccion <- neuralnet::compute(red_neuronal, prueba)

# Probabilidad estimada (entre 0 y 1)
probabilidad <- as.numeric(prediccion$net.result)

# ClasificaciĂ³n binaria con umbral 0.5
resultado <- ifelse(probabilidad > 0.5, 1, 0)

probabilidad
## [1] 0.3334934 0.3334934 0.3334934
resultado
## [1] 0 0 0

Modelo de Red Neuronal — CĂ¡ncer de mama

A continuaciĂ³n, entrenamos un modelo de red neuronal y evaluamos su desempeño sobre un conjunto de prueba.

Importar la Base de Datos

datos_cancer <- read.csv("~/Library/CloudStorage/OneDrive-InstitutoTecnologicoydeEstudiosSuperioresdeMonterrey/SEM 7/M2/cancer_de_mama.csv"
, stringsAsFactors = FALSE, fileEncoding = "UTF-8-BOM")
names(datos_cancer) <- make.names(names(datos_cancer))

Definir/ajustar la variable objetivo

objetivo <- "diagnosis"

# factor con el orden correcto
datos_cancer[[objetivo]] <- factor(datos_cancer[[objetivo]], levels = c("B","M"))

# versiĂ³n numĂ©rica para la red: B=0, M=1
objetivo_num <- paste0(objetivo, "_num")
datos_cancer[[objetivo_num]] <- as.numeric(datos_cancer[[objetivo]]) - 1 # B=0, M=1

SelecciĂ³n de predictores numĂ©ricos

predictores <- setdiff(names(datos_cancer), c(objetivo, objetivo_num))

datos_cancer <- na.omit(datos_cancer)

Red Neuronal

set.seed(123)
idx <- createDataPartition(datos_cancer[[objetivo]], p = 0.7, list = FALSE)
train <- datos_cancer[idx, , drop = FALSE]
test  <- datos_cancer[-idx, , drop = FALSE]

# FĂ³rmula para neuralnet
form_nn <- as.formula(paste(objetivo_num, "~", paste(predictores, collapse = " + ")))

# Entrenamiento de la red
set.seed(123)
red_mama <- neuralnet(
  form_nn,
  data          = train,
  hidden        = c(5),      # ajustable: p.ej. c(8) o c(8,4)
  linear.output = FALSE,     # salida sigmoidal (clasificaciĂ³n)
  stepmax       = 1e+06,
  lifesign      = "minimal",
  threshold     = 0.01
)
## hidden: 5    thresh: 0.01    rep: 1/1    steps:    6076  error: 2.45225  time: 1.03 secs
# 8) VisualizaciĂ³n
plot(red_mama, rep = "best")

Tests de PredicciĂ³n

modelo_nn <- red_mama

Xcols <- all.vars(form_nn)[-1] 
Xtest <- test[, Xcols, drop = FALSE]

stopifnot(all(vapply(Xtest, is.numeric, logical(1))))

pred_test <- neuralnet::compute(modelo_nn, Xtest)

prob <- as.numeric(pred_test$net.result)

pred_num <- ifelse(prob >= 0.5, 1, 0)
pred_fac <- factor(pred_num, levels = c(0,1), labels = c("B","M"))

caret::confusionMatrix(pred_fac, test[["diagnosis"]])
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   B   M
##          B 104   8
##          M   3  55
##                                           
##                Accuracy : 0.9353          
##                  95% CI : (0.8872, 0.9673)
##     No Information Rate : 0.6294          
##     P-Value [Acc > NIR] : <2e-16          
##                                           
##                   Kappa : 0.859           
##                                           
##  Mcnemar's Test P-Value : 0.2278          
##                                           
##             Sensitivity : 0.9720          
##             Specificity : 0.8730          
##          Pos Pred Value : 0.9286          
##          Neg Pred Value : 0.9483          
##              Prevalence : 0.6294          
##          Detection Rate : 0.6118          
##    Detection Prevalence : 0.6588          
##       Balanced Accuracy : 0.9225          
##                                           
##        'Positive' Class : B               
## 

ROC y AUC

roc_obj <- pROC::roc(response = test[[objetivo]],
                     predictor = prob,
                     levels = c("B","M"),
                     direction = ">")
plot(roc_obj, main = paste("ROC - AUC:", round(pROC::auc(roc_obj), 4)))

LS0tCnRpdGxlOiAiUmVkZXMgTmV1cm9uYWxlcyIKYXV0aG9yOiAiQW5uYSBEdXLDoW4gQTAxMjg1Njc0IgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiBUUlVFICNUYWJsYSBkZSBjb250ZW5pZG9zCiAgICB0b2NfZmxvYXQ6IFRSVUUgI1RhYmxhIGRlIGFsZ28KICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUgI1BvZGVyIGRlc2NhcmdhciBjw7NkaWdvCiAgICB0aGVtZTogc2ltcGxleAotLS0KCiFbXShodHRwczovL21pcm8ubWVkaXVtLmNvbS92Mi9yZXNpemU6Zml0OjEyMDAvMSpsR3NJd2NybVo5NjBUY3ZuQldTTHdBLmdpZikKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiM1MjhCOEI7Ij48Yj4gVGVvcsOtYSA8L2I+PC9zcGFuPgpVbmEgKipSZWQgTmV1cm9uYWwgQXJ0aWZpY2lhbCAoQU5OKSoqIG1vZGVsYSBsYSByZWxhY2nDs24gZW50cmUgdW4gY29uanVudG8gZGUgZW50cmFkYXMgeSB1bmEgc2FsaWRhLCByZXNvbHZpZW5kbyB1biBwcm9ibGVtYSBkZSBhcHJlbmRpemFqZS4gIAoKCkVqZW1wbG9zIHByw6FjdGljb3MgZGUgYXBsaWNhY2nDs24gZGUgUmVkZXMgTmV1cm9uYWxlcyBzb246CgoqIExhIHJlY29tZW5kYWNpw7NuIGRlIGNvbnRlbmlkbyBkZSBOZXRmbGl4ICAKKiBFbCBmZWVkIGRlIEluc3RhZ3JhbSBvIFRpa3RvayAgCiogRGV0ZXJtaW5hciBlbCBuw7ptZXJvIG8gbGV0cmEgZXNjcml0byBhIG1hbm8gIAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IzUyOEI4QjsiPjxiPiBJbnN0YWxhciBwYXF1ZXRlcyB5IGxsYW1hciBsaWJyZXLDrWFzIDwvYj48L3NwYW4+CmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcyhjKCJuZXVyYWxuZXQiLCJjYXJldCIsImRwbHlyIiwicFJPQyIpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogIGxpYnJhcnkobmV1cmFsbmV0KQogIGxpYnJhcnkoY2FyZXQpCiAgbGlicmFyeShkcGx5cikKICBsaWJyYXJ5KHBST0MpCn0pCmBgYAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IzUyOEI4QjsiPjxiPiBBbGltZW50YXIgY29uIGVqZW1wbG9zIDwvYj48L3NwYW4+CmBgYHtyfQpleGFtZW4gICA8LSBjKDIwLDEwLDMwLDIwLDgwLDMwKQpwcm95ZWN0byA8LSBjKDkwLDIwLDQwLDUwLDUwLDgwKQplc3RhdHVzICA8LSBjKDEsMCwwLDAsMCwxKQoKZGYgPC0gZGF0YS5mcmFtZShleGFtZW4sIHByb3llY3RvLCBlc3RhdHVzKQoKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjojNTI4QjhCOyI+PGI+IEdlbmVyYXIgbGEgUmVkIE5ldXJvbmFsIDwvYj48L3NwYW4+CmBgYHtyfQpyZWRfbmV1cm9uYWwgPC0gbmV1cmFsbmV0KGVzdGF0dXMgfiAuLCBkYXRhID0gZGYpCnBsb3QocmVkX25ldXJvbmFsLCByZXAgPSAiYmVzdCIpCmBgYAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IzUyOEI4QjsiPjxiPiBQcmVkZWNpciBjb24gbGEgUmVkIE5ldXJvbmFsIDwvYj48L3NwYW4+CmBgYHtyfQpzZXQuc2VlZCgxMjMpCgpwcnVlYmFfZXhhbWVuICAgPC0gYygzMCw0MCw4NSkKcHJ1ZWJhX3Byb3llY3RvIDwtIGMoODUsNTAsNDApCgojIENvbnN0cnVpciBkYXRhLmZyYW1lIGNvbiBsb3MgbWlzbW9zIG5vbWJyZXMgZGUgY29sdW1uYXMgcXVlIHVzYXN0ZSBhbCBlbnRyZW5hcgojIFNpIHR1IGbDs3JtdWxhIGVyYTogZXN0YXR1cyB+IGV4YW1lbiArIHByb3llY3RvCnBydWViYSA8LSBkYXRhLmZyYW1lKGV4YW1lbiA9IHBydWViYV9leGFtZW4sCiAgICAgICAgICAgICAgICAgICAgIHByb3llY3RvID0gcHJ1ZWJhX3Byb3llY3RvKQoKIyBDYWxjdWxhciBsYSBwcmVkaWNjacOzbiB1c2FuZG8gbmV1cmFsbmV0Ojpjb21wdXRlICjCoWNsYXZlISkKcHJlZGljY2lvbiA8LSBuZXVyYWxuZXQ6OmNvbXB1dGUocmVkX25ldXJvbmFsLCBwcnVlYmEpCgojIFByb2JhYmlsaWRhZCBlc3RpbWFkYSAoZW50cmUgMCB5IDEpCnByb2JhYmlsaWRhZCA8LSBhcy5udW1lcmljKHByZWRpY2Npb24kbmV0LnJlc3VsdCkKCiMgQ2xhc2lmaWNhY2nDs24gYmluYXJpYSBjb24gdW1icmFsIDAuNQpyZXN1bHRhZG8gPC0gaWZlbHNlKHByb2JhYmlsaWRhZCA+IDAuNSwgMSwgMCkKCnByb2JhYmlsaWRhZApyZXN1bHRhZG8KYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjojRUUxMjg5OyI+PGI+IE1vZGVsbyBkZSBSZWQgTmV1cm9uYWwg4oCUIEPDoW5jZXIgZGUgbWFtYTwvYj48L3NwYW4+CkEgY29udGludWFjacOzbiwgZW50cmVuYW1vcyB1biBtb2RlbG8gZGUgcmVkIG5ldXJvbmFsIHkgZXZhbHVhbW9zIHN1IGRlc2VtcGXDsW8gc29icmUgdW4gY29uanVudG8gZGUgcHJ1ZWJhLgoKIyA8c3BhbiBzdHlsZT0iY29sb3I6I0VFMTI4OTsiPjxiPiBJbXBvcnRhciBsYSBCYXNlIGRlIERhdG9zIDwvYj48L3NwYW4+CmBgYHtyfQpkYXRvc19jYW5jZXIgPC0gcmVhZC5jc3YoIn4vTGlicmFyeS9DbG91ZFN0b3JhZ2UvT25lRHJpdmUtSW5zdGl0dXRvVGVjbm9sb2dpY295ZGVFc3R1ZGlvc1N1cGVyaW9yZXNkZU1vbnRlcnJleS9TRU0gNy9NMi9jYW5jZXJfZGVfbWFtYS5jc3YiCiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBmaWxlRW5jb2RpbmcgPSAiVVRGLTgtQk9NIikKbmFtZXMoZGF0b3NfY2FuY2VyKSA8LSBtYWtlLm5hbWVzKG5hbWVzKGRhdG9zX2NhbmNlcikpCmBgYAoKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiNFRTEyODk7Ij48Yj4gRGVmaW5pci9hanVzdGFyIGxhIHZhcmlhYmxlIG9iamV0aXZvIDwvYj48L3NwYW4+CmBgYHtyfQpvYmpldGl2byA8LSAiZGlhZ25vc2lzIgoKIyBmYWN0b3IgY29uIGVsIG9yZGVuIGNvcnJlY3RvCmRhdG9zX2NhbmNlcltbb2JqZXRpdm9dXSA8LSBmYWN0b3IoZGF0b3NfY2FuY2VyW1tvYmpldGl2b11dLCBsZXZlbHMgPSBjKCJCIiwiTSIpKQoKIyB2ZXJzacOzbiBudW3DqXJpY2EgcGFyYSBsYSByZWQ6IEI9MCwgTT0xCm9iamV0aXZvX251bSA8LSBwYXN0ZTAob2JqZXRpdm8sICJfbnVtIikKZGF0b3NfY2FuY2VyW1tvYmpldGl2b19udW1dXSA8LSBhcy5udW1lcmljKGRhdG9zX2NhbmNlcltbb2JqZXRpdm9dXSkgLSAxICMgQj0wLCBNPTEKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjojRUUxMjg5OyI+PGI+IFNlbGVjY2nDs24gZGUgcHJlZGljdG9yZXMgbnVtw6lyaWNvcyA8L2I+PC9zcGFuPgpgYGB7cn0KcHJlZGljdG9yZXMgPC0gc2V0ZGlmZihuYW1lcyhkYXRvc19jYW5jZXIpLCBjKG9iamV0aXZvLCBvYmpldGl2b19udW0pKQoKZGF0b3NfY2FuY2VyIDwtIG5hLm9taXQoZGF0b3NfY2FuY2VyKQpgYGAKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiNFRTEyODk7Ij48Yj4gUmVkIE5ldXJvbmFsIDwvYj48L3NwYW4+CmBgYHtyfQpzZXQuc2VlZCgxMjMpCmlkeCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGRhdG9zX2NhbmNlcltbb2JqZXRpdm9dXSwgcCA9IDAuNywgbGlzdCA9IEZBTFNFKQp0cmFpbiA8LSBkYXRvc19jYW5jZXJbaWR4LCAsIGRyb3AgPSBGQUxTRV0KdGVzdCAgPC0gZGF0b3NfY2FuY2VyWy1pZHgsICwgZHJvcCA9IEZBTFNFXQoKIyBGw7NybXVsYSBwYXJhIG5ldXJhbG5ldApmb3JtX25uIDwtIGFzLmZvcm11bGEocGFzdGUob2JqZXRpdm9fbnVtLCAifiIsIHBhc3RlKHByZWRpY3RvcmVzLCBjb2xsYXBzZSA9ICIgKyAiKSkpCgojIEVudHJlbmFtaWVudG8gZGUgbGEgcmVkCnNldC5zZWVkKDEyMykKcmVkX21hbWEgPC0gbmV1cmFsbmV0KAogIGZvcm1fbm4sCiAgZGF0YSAgICAgICAgICA9IHRyYWluLAogIGhpZGRlbiAgICAgICAgPSBjKDUpLCAgICAgICMgYWp1c3RhYmxlOiBwLmVqLiBjKDgpIG8gYyg4LDQpCiAgbGluZWFyLm91dHB1dCA9IEZBTFNFLCAgICAgIyBzYWxpZGEgc2lnbW9pZGFsIChjbGFzaWZpY2FjacOzbikKICBzdGVwbWF4ICAgICAgID0gMWUrMDYsCiAgbGlmZXNpZ24gICAgICA9ICJtaW5pbWFsIiwKICB0aHJlc2hvbGQgICAgID0gMC4wMQopCgojIDgpIFZpc3VhbGl6YWNpw7NuCnBsb3QocmVkX21hbWEsIHJlcCA9ICJiZXN0IikKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjojRUUxMjg5OyI+PGI+IFRlc3RzIGRlIFByZWRpY2Npw7NuIDwvYj48L3NwYW4+CmBgYHtyfQptb2RlbG9fbm4gPC0gcmVkX21hbWEKClhjb2xzIDwtIGFsbC52YXJzKGZvcm1fbm4pWy0xXSAKWHRlc3QgPC0gdGVzdFssIFhjb2xzLCBkcm9wID0gRkFMU0VdCgpzdG9waWZub3QoYWxsKHZhcHBseShYdGVzdCwgaXMubnVtZXJpYywgbG9naWNhbCgxKSkpKQoKcHJlZF90ZXN0IDwtIG5ldXJhbG5ldDo6Y29tcHV0ZShtb2RlbG9fbm4sIFh0ZXN0KQoKcHJvYiA8LSBhcy5udW1lcmljKHByZWRfdGVzdCRuZXQucmVzdWx0KQoKcHJlZF9udW0gPC0gaWZlbHNlKHByb2IgPj0gMC41LCAxLCAwKQpwcmVkX2ZhYyA8LSBmYWN0b3IocHJlZF9udW0sIGxldmVscyA9IGMoMCwxKSwgbGFiZWxzID0gYygiQiIsIk0iKSkKCmNhcmV0Ojpjb25mdXNpb25NYXRyaXgocHJlZF9mYWMsIHRlc3RbWyJkaWFnbm9zaXMiXV0pCmBgYAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6I0VFMTI4OTsiPjxiPiBST0MgeSBBVUMgPC9iPjwvc3Bhbj4KYGBge3J9CnJvY19vYmogPC0gcFJPQzo6cm9jKHJlc3BvbnNlID0gdGVzdFtbb2JqZXRpdm9dXSwKICAgICAgICAgICAgICAgICAgICAgcHJlZGljdG9yID0gcHJvYiwKICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQiIsIk0iKSwKICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIj4iKQpwbG90KHJvY19vYmosIG1haW4gPSBwYXN0ZSgiUk9DIC0gQVVDOiIsIHJvdW5kKHBST0M6OmF1Yyhyb2Nfb2JqKSwgNCkpKQpgYGAKCg==