Teoría

Una Red Neuronal Artificial (ANN) modela una relación entre un conjunto de entradas y salidas, resolviendo un problema de aprendizaje.

Ejemplos prácticos de la aplicación de Redes Neuronales son:

  • Recomendación Netflix
  • Feed Instagram o TikTok
  • Determinar el número o letras escritas a mano.

Instalación de paquetes y llamar librerías

#install.packages("neuralnet")
library(neuralnet)
set.seed(123)

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 Red Neuronal

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

# Crear datos de prueba
prueba_examen <- c(30,40,85)
prueba_proyecto <- c(85,50,40)
prueba <- data.frame(prueba_examen, prueba_proyecto)

modelo <- neuralnet(estatus ~ examen + proyecto,
                    data = df,
                    hidden = 2,          # 2 neuronas ocultas
                    linear.output = FALSE)

plot(modelo, rep="best")

# Ahora s, usar tus datos de prueba
prueba_examen <- c(30,40,85)
prueba_proyecto <- c(85,50,40)
prueba <- data.frame(examen = prueba_examen, proyecto = prueba_proyecto)

# Hacer predicciones
prediccion <- compute(modelo, prueba)

# Revisar resultados en probabilidad
prediccion$net.result
##           [,1]
## [1,] 0.3341435
## [2,] 0.3341435
## [3,] 0.3341434
# Convertir con umbral 0.5
probabilidad <- prediccion$net.result
resultado <- ifelse(probabilidad > 0.5, 1, 0)
resultado
##      [,1]
## [1,]    0
## [2,]    0
## [3,]    0
df <- read.csv("C:/Users/Salvador/Downloads/cancer_de_mama (1).csv", stringsAsFactors = FALSE)

# Convertir diagnosis a 0/1 → M=1, B=0
df$diagnosis <- ifelse(df$diagnosis == "M", 1, 0)

Generar Red Neuronal

# install.packages("neuralnet")
library(neuralnet)

set.seed(123)

# --- 1) Selección de columnas y limpieza ---
cols <- c("diagnosis","radius_mean","texture_mean","perimeter_mean","area_mean","smoothness_mean")
df_nn <- na.omit(df[ , cols])

# Asegurar que la variable objetivo sea 0/1 numérica
# Edita los niveles según tu dataset ("M"/"B", "Malignant"/"Benign", etc.)
if (is.character(df_nn$diagnosis) || is.factor(df_nn$diagnosis)) {
  df_nn$diagnosis <- ifelse(df_nn$diagnosis %in% c("M","Malignant","1"), 1, 0)
}
df_nn$diagnosis <- as.numeric(df_nn$diagnosis)

# --- 2) Escalado de predictores (0-1) para estabilidad del entrenamiento ---
rng01 <- function(x) (x - min(x)) / (max(x) - min(x))
Xcols <- setdiff(cols, "diagnosis")
df_nn[ , Xcols] <- lapply(df_nn[ , Xcols], rng01)

# (Opcional) Partición train/test
n <- nrow(df_nn)
idx <- sample(seq_len(n), size = floor(0.8*n))
train <- df_nn[idx, ]
test  <- df_nn[-idx, ]

# --- 3) Entrenamiento con hiperparámetros más tolerantes ---
# Tips para evitar "did not converge":
# - reducir tamaño de la red (p.ej. hidden = c(4) o c(5,3) si ya escala)
# - aumentar stepmax
# - usar algorithm = "rprop+" (resilient backprop)
# - subir threshold (criterio de parada) ligeramente
formula_nn <- diagnosis ~ radius_mean + texture_mean + perimeter_mean + area_mean + smoothness_mean

red_neuronal <- neuralnet(
  formula = formula_nn,
  data = train,
  hidden = c(4),              # empieza simple; luego puedes probar c(5,3)
  act.fct = "logistic",
  linear.output = FALSE,
  algorithm = "rprop+",
  stepmax = 5e6,
  threshold = 0.05,
  lifesign = "minimal",
  rep = 3
)
## hidden: 4    thresh: 0.05    rep: 1/3    steps:     277  error: 10.13928 time: 0.12 secs
## hidden: 4    thresh: 0.05    rep: 2/3    steps:     230  error: 10.31412 time: 0.09 secs
## hidden: 4    thresh: 0.05    rep: 3/3    steps:     323  error: 10.20643 time: 0.1 secs
# --- 4) Graficar solo si hay pesos (convergió al menos una réplica) ---
convergio <- length(red_neuronal$weights) > 0 &&
             length(red_neuronal$weights[[1]]) > 0 &&
             all(!sapply(red_neuronal$weights[[1]], is.null))

if (convergio) {
  plot(red_neuronal, rep = which.min(red_neuronal$result.matrix["error", ]))
} else {
  message("La red no convergió. Ajusta hidden/stepmax/threshold o verifica datos.")
}

# --- 5) Predicción y umbral ---
if (convergio) {
  pred_prob <- compute(red_neuronal, test[ , Xcols])$net.result
  pred_clas <- ifelse(pred_prob > 0.5, 1, 0)

  # Métrica rápida (si tienes test$diagnosis)
  if (nrow(test) > 0) {
    acc <- mean(pred_clas == test$diagnosis)
    cat(sprintf("\nAccuracy test: %.3f\n", acc))
  }

  # Ver predicciones de ejemplo
  head(data.frame(prob = pred_prob, pred = pred_clas))
}
## 
## Accuracy test: 0.930
##         prob pred
## 1  0.9683749    1
## 9  0.9697277    1
## 15 0.9374889    1
## 17 0.6831005    1
## 18 0.9956391    1
## 28 0.9959247    1
# Crear datos de prueba (ejemplo con 3 pacientes)
prueba <- data.frame(
  radius_mean      = c(14.5, 20.1, 10.3),
  texture_mean     = c(20.2, 12.5, 18.4),
  perimeter_mean   = c(88.5, 130.1, 70.4),
  area_mean        = c(520, 1250, 320),
  smoothness_mean  = c(0.10, 0.09, 0.12)
)

# Predicciones
prediccion <- compute(red_neuronal, prueba)
probabilidad <- as.vector(prediccion$net.result)
resultado <- ifelse(probabilidad > 0.5, 1, 0)

# Mostrar resultados
data.frame(prueba, probabilidad, resultado)
##   radius_mean texture_mean perimeter_mean area_mean smoothness_mean
## 1        14.5         20.2           88.5       520            0.10
## 2        20.1         12.5          130.1      1250            0.09
## 3        10.3         18.4           70.4       320            0.12
##   probabilidad resultado
## 1    0.9999962         1
## 2    0.9999962         1
## 3    0.9999962         1
LS0tDQp0aXRsZTogIlJlZGVzIE5ldXJvbmFsZXMiDQphdXRob3I6ICJTYWx2YWRvciBOYXJ2YWV6IEEwMDU3MTg0OCINCmRhdGU6ICIyMDI1LTA4LTI1Ig0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IGJvb3RzdHJhcA0KLS0tDQoNCjxjZW50ZXI+DQohW10oaHR0cHM6Ly9taXJvLm1lZGl1bS5jb20vdjIvcmVzaXplOmZpdDoxNDAwLzEqbHFEN1BBWkhMdzZvVHk2YmNzVlc5US5naWYpDQo8L2NlbnRlcj4NCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6bmF2eTsiPiBUZW9yw61hIDwvc3Bhbj4NCg0KVW5hIFJlZCBOZXVyb25hbCBBcnRpZmljaWFsIChBTk4pIG1vZGVsYSB1bmEgcmVsYWNpw7NuIGVudHJlIHVuIGNvbmp1bnRvIGRlIGVudHJhZGFzIHkgc2FsaWRhcywgcmVzb2x2aWVuZG8gdW4gcHJvYmxlbWEgZGUgYXByZW5kaXphamUuDQoNCkVqZW1wbG9zIHByw6FjdGljb3MgZGUgbGEgYXBsaWNhY2nDs24gZGUgUmVkZXMgTmV1cm9uYWxlcyBzb246DQoNCiogUmVjb21lbmRhY2nDs24gTmV0ZmxpeA0KKiBGZWVkIEluc3RhZ3JhbSBvIFRpa1Rvaw0KKiBEZXRlcm1pbmFyIGVsIG7Dum1lcm8gbyBsZXRyYXMgZXNjcml0YXMgYSBtYW5vLg0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjpuYXZ5OyI+IEluc3RhbGFjacOzbiBkZSBwYXF1ZXRlcyB5IGxsYW1hciBsaWJyZXLDrWFzIDwvc3Bhbj4NCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoIm5ldXJhbG5ldCIpDQpsaWJyYXJ5KG5ldXJhbG5ldCkNCnNldC5zZWVkKDEyMykNCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjpuYXZ5OyI+IEFsaW1lbnRhciBjb24gZWplbXBsb3MgPC9zcGFuPg0KYGBge3J9DQpleGFtZW4gPC0gYygyMCwxMCwzMCwyMCw4MCwzMCkNCnByb3llY3RvIDwtIGMoOTAsMjAsNDAsNTAsNTAsODApDQplc3RhdHVzIDwtIGMoMSwwLDAsMCwwLDEpDQpkZiA8LSBkYXRhLmZyYW1lKGV4YW1lbixwcm95ZWN0byxlc3RhdHVzKQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOm5hdnk7Ij4gR2VuZXJhciBSZWQgTmV1cm9uYWwgPC9zcGFuPg0KYGBge3J9DQpyZWRfbmV1cm9uYWwgPC0gbmV1cmFsbmV0KGVzdGF0dXN+LiwgZGF0YT1kZikNCnBsb3QocmVkX25ldXJvbmFsLCByZXA9ImJlc3QiKQ0KYGBgDQpgYGB7cn0NCiMgQ3JlYXIgZGF0b3MgZGUgcHJ1ZWJhDQpwcnVlYmFfZXhhbWVuIDwtIGMoMzAsNDAsODUpDQpwcnVlYmFfcHJveWVjdG8gPC0gYyg4NSw1MCw0MCkNCnBydWViYSA8LSBkYXRhLmZyYW1lKHBydWViYV9leGFtZW4sIHBydWViYV9wcm95ZWN0bykNCg0KbW9kZWxvIDwtIG5ldXJhbG5ldChlc3RhdHVzIH4gZXhhbWVuICsgcHJveWVjdG8sDQogICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkZiwNCiAgICAgICAgICAgICAgICAgICAgaGlkZGVuID0gMiwgICAgICAgICAgIyAyIG5ldXJvbmFzIG9jdWx0YXMNCiAgICAgICAgICAgICAgICAgICAgbGluZWFyLm91dHB1dCA9IEZBTFNFKQ0KDQpwbG90KG1vZGVsbywgcmVwPSJiZXN0IikNCmBgYA0KYGBge3J9DQojIEFob3JhIHMsIHVzYXIgdHVzIGRhdG9zIGRlIHBydWViYQ0KcHJ1ZWJhX2V4YW1lbiA8LSBjKDMwLDQwLDg1KQ0KcHJ1ZWJhX3Byb3llY3RvIDwtIGMoODUsNTAsNDApDQpwcnVlYmEgPC0gZGF0YS5mcmFtZShleGFtZW4gPSBwcnVlYmFfZXhhbWVuLCBwcm95ZWN0byA9IHBydWViYV9wcm95ZWN0bykNCg0KIyBIYWNlciBwcmVkaWNjaW9uZXMNCnByZWRpY2Npb24gPC0gY29tcHV0ZShtb2RlbG8sIHBydWViYSkNCg0KIyBSZXZpc2FyIHJlc3VsdGFkb3MgZW4gcHJvYmFiaWxpZGFkDQpwcmVkaWNjaW9uJG5ldC5yZXN1bHQNCmBgYA0KYGBge3J9DQojIENvbnZlcnRpciBjb24gdW1icmFsIDAuNQ0KcHJvYmFiaWxpZGFkIDwtIHByZWRpY2Npb24kbmV0LnJlc3VsdA0KcmVzdWx0YWRvIDwtIGlmZWxzZShwcm9iYWJpbGlkYWQgPiAwLjUsIDEsIDApDQpyZXN1bHRhZG8NCmBgYA0KYGBge3J9DQpkZiA8LSByZWFkLmNzdigiQzovVXNlcnMvU2FsdmFkb3IvRG93bmxvYWRzL2NhbmNlcl9kZV9tYW1hICgxKS5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCiMgQ29udmVydGlyIGRpYWdub3NpcyBhIDAvMSDihpIgTT0xLCBCPTANCmRmJGRpYWdub3NpcyA8LSBpZmVsc2UoZGYkZGlhZ25vc2lzID09ICJNIiwgMSwgMCkNCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjpuYXZ5OyI+IEdlbmVyYXIgUmVkIE5ldXJvbmFsIDwvc3Bhbj4NCmBgYHtyfQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJuZXVyYWxuZXQiKQ0KbGlicmFyeShuZXVyYWxuZXQpDQoNCnNldC5zZWVkKDEyMykNCg0KIyAtLS0gMSkgU2VsZWNjacOzbiBkZSBjb2x1bW5hcyB5IGxpbXBpZXphIC0tLQ0KY29scyA8LSBjKCJkaWFnbm9zaXMiLCJyYWRpdXNfbWVhbiIsInRleHR1cmVfbWVhbiIsInBlcmltZXRlcl9tZWFuIiwiYXJlYV9tZWFuIiwic21vb3RobmVzc19tZWFuIikNCmRmX25uIDwtIG5hLm9taXQoZGZbICwgY29sc10pDQoNCiMgQXNlZ3VyYXIgcXVlIGxhIHZhcmlhYmxlIG9iamV0aXZvIHNlYSAwLzEgbnVtw6lyaWNhDQojIEVkaXRhIGxvcyBuaXZlbGVzIHNlZ8O6biB0dSBkYXRhc2V0ICgiTSIvIkIiLCAiTWFsaWduYW50Ii8iQmVuaWduIiwgZXRjLikNCmlmIChpcy5jaGFyYWN0ZXIoZGZfbm4kZGlhZ25vc2lzKSB8fCBpcy5mYWN0b3IoZGZfbm4kZGlhZ25vc2lzKSkgew0KICBkZl9ubiRkaWFnbm9zaXMgPC0gaWZlbHNlKGRmX25uJGRpYWdub3NpcyAlaW4lIGMoIk0iLCJNYWxpZ25hbnQiLCIxIiksIDEsIDApDQp9DQpkZl9ubiRkaWFnbm9zaXMgPC0gYXMubnVtZXJpYyhkZl9ubiRkaWFnbm9zaXMpDQoNCiMgLS0tIDIpIEVzY2FsYWRvIGRlIHByZWRpY3RvcmVzICgwLTEpIHBhcmEgZXN0YWJpbGlkYWQgZGVsIGVudHJlbmFtaWVudG8gLS0tDQpybmcwMSA8LSBmdW5jdGlvbih4KSAoeCAtIG1pbih4KSkgLyAobWF4KHgpIC0gbWluKHgpKQ0KWGNvbHMgPC0gc2V0ZGlmZihjb2xzLCAiZGlhZ25vc2lzIikNCmRmX25uWyAsIFhjb2xzXSA8LSBsYXBwbHkoZGZfbm5bICwgWGNvbHNdLCBybmcwMSkNCg0KIyAoT3BjaW9uYWwpIFBhcnRpY2nDs24gdHJhaW4vdGVzdA0KbiA8LSBucm93KGRmX25uKQ0KaWR4IDwtIHNhbXBsZShzZXFfbGVuKG4pLCBzaXplID0gZmxvb3IoMC44Km4pKQ0KdHJhaW4gPC0gZGZfbm5baWR4LCBdDQp0ZXN0ICA8LSBkZl9ublstaWR4LCBdDQoNCiMgLS0tIDMpIEVudHJlbmFtaWVudG8gY29uIGhpcGVycGFyw6FtZXRyb3MgbcOhcyB0b2xlcmFudGVzIC0tLQ0KIyBUaXBzIHBhcmEgZXZpdGFyICJkaWQgbm90IGNvbnZlcmdlIjoNCiMgLSByZWR1Y2lyIHRhbWHDsW8gZGUgbGEgcmVkIChwLmVqLiBoaWRkZW4gPSBjKDQpIG8gYyg1LDMpIHNpIHlhIGVzY2FsYSkNCiMgLSBhdW1lbnRhciBzdGVwbWF4DQojIC0gdXNhciBhbGdvcml0aG0gPSAicnByb3ArIiAocmVzaWxpZW50IGJhY2twcm9wKQ0KIyAtIHN1YmlyIHRocmVzaG9sZCAoY3JpdGVyaW8gZGUgcGFyYWRhKSBsaWdlcmFtZW50ZQ0KZm9ybXVsYV9ubiA8LSBkaWFnbm9zaXMgfiByYWRpdXNfbWVhbiArIHRleHR1cmVfbWVhbiArIHBlcmltZXRlcl9tZWFuICsgYXJlYV9tZWFuICsgc21vb3RobmVzc19tZWFuDQoNCnJlZF9uZXVyb25hbCA8LSBuZXVyYWxuZXQoDQogIGZvcm11bGEgPSBmb3JtdWxhX25uLA0KICBkYXRhID0gdHJhaW4sDQogIGhpZGRlbiA9IGMoNCksICAgICAgICAgICAgICAjIGVtcGllemEgc2ltcGxlOyBsdWVnbyBwdWVkZXMgcHJvYmFyIGMoNSwzKQ0KICBhY3QuZmN0ID0gImxvZ2lzdGljIiwNCiAgbGluZWFyLm91dHB1dCA9IEZBTFNFLA0KICBhbGdvcml0aG0gPSAicnByb3ArIiwNCiAgc3RlcG1heCA9IDVlNiwNCiAgdGhyZXNob2xkID0gMC4wNSwNCiAgbGlmZXNpZ24gPSAibWluaW1hbCIsDQogIHJlcCA9IDMNCikNCmBgYA0KDQpgYGB7cn0NCiMgLS0tIDQpIEdyYWZpY2FyIHNvbG8gc2kgaGF5IHBlc29zIChjb252ZXJnacOzIGFsIG1lbm9zIHVuYSByw6lwbGljYSkgLS0tDQpjb252ZXJnaW8gPC0gbGVuZ3RoKHJlZF9uZXVyb25hbCR3ZWlnaHRzKSA+IDAgJiYNCiAgICAgICAgICAgICBsZW5ndGgocmVkX25ldXJvbmFsJHdlaWdodHNbWzFdXSkgPiAwICYmDQogICAgICAgICAgICAgYWxsKCFzYXBwbHkocmVkX25ldXJvbmFsJHdlaWdodHNbWzFdXSwgaXMubnVsbCkpDQoNCmlmIChjb252ZXJnaW8pIHsNCiAgcGxvdChyZWRfbmV1cm9uYWwsIHJlcCA9IHdoaWNoLm1pbihyZWRfbmV1cm9uYWwkcmVzdWx0Lm1hdHJpeFsiZXJyb3IiLCBdKSkNCn0gZWxzZSB7DQogIG1lc3NhZ2UoIkxhIHJlZCBubyBjb252ZXJnacOzLiBBanVzdGEgaGlkZGVuL3N0ZXBtYXgvdGhyZXNob2xkIG8gdmVyaWZpY2EgZGF0b3MuIikNCn0NCmBgYA0KYGBge3J9DQojIC0tLSA1KSBQcmVkaWNjacOzbiB5IHVtYnJhbCAtLS0NCmlmIChjb252ZXJnaW8pIHsNCiAgcHJlZF9wcm9iIDwtIGNvbXB1dGUocmVkX25ldXJvbmFsLCB0ZXN0WyAsIFhjb2xzXSkkbmV0LnJlc3VsdA0KICBwcmVkX2NsYXMgPC0gaWZlbHNlKHByZWRfcHJvYiA+IDAuNSwgMSwgMCkNCg0KICAjIE3DqXRyaWNhIHLDoXBpZGEgKHNpIHRpZW5lcyB0ZXN0JGRpYWdub3NpcykNCiAgaWYgKG5yb3codGVzdCkgPiAwKSB7DQogICAgYWNjIDwtIG1lYW4ocHJlZF9jbGFzID09IHRlc3QkZGlhZ25vc2lzKQ0KICAgIGNhdChzcHJpbnRmKCJcbkFjY3VyYWN5IHRlc3Q6ICUuM2ZcbiIsIGFjYykpDQogIH0NCg0KICAjIFZlciBwcmVkaWNjaW9uZXMgZGUgZWplbXBsbw0KICBoZWFkKGRhdGEuZnJhbWUocHJvYiA9IHByZWRfcHJvYiwgcHJlZCA9IHByZWRfY2xhcykpDQp9DQpgYGANCg0KYGBge3J9DQojIENyZWFyIGRhdG9zIGRlIHBydWViYSAoZWplbXBsbyBjb24gMyBwYWNpZW50ZXMpDQpwcnVlYmEgPC0gZGF0YS5mcmFtZSgNCiAgcmFkaXVzX21lYW4gICAgICA9IGMoMTQuNSwgMjAuMSwgMTAuMyksDQogIHRleHR1cmVfbWVhbiAgICAgPSBjKDIwLjIsIDEyLjUsIDE4LjQpLA0KICBwZXJpbWV0ZXJfbWVhbiAgID0gYyg4OC41LCAxMzAuMSwgNzAuNCksDQogIGFyZWFfbWVhbiAgICAgICAgPSBjKDUyMCwgMTI1MCwgMzIwKSwNCiAgc21vb3RobmVzc19tZWFuICA9IGMoMC4xMCwgMC4wOSwgMC4xMikNCikNCg0KIyBQcmVkaWNjaW9uZXMNCnByZWRpY2Npb24gPC0gY29tcHV0ZShyZWRfbmV1cm9uYWwsIHBydWViYSkNCnByb2JhYmlsaWRhZCA8LSBhcy52ZWN0b3IocHJlZGljY2lvbiRuZXQucmVzdWx0KQ0KcmVzdWx0YWRvIDwtIGlmZWxzZShwcm9iYWJpbGlkYWQgPiAwLjUsIDEsIDApDQoNCiMgTW9zdHJhciByZXN1bHRhZG9zDQpkYXRhLmZyYW1lKHBydWViYSwgcHJvYmFiaWxpZGFkLCByZXN1bHRhZG8pDQpgYGANCg0K