Escuela Militar de Ingeniería

Carrera de Ingeniería de Sistemas

Integrantes:

  • Brayan Choquehuanca Mamani (A28573-0)
  • Alvin Ariel Cayo Quispe (A25769-9)
  • Einard Gutierrez Huanca (A26654-X)

Docente: Ing. Angela Santos
Fecha: 15 de Agosto de 2025


Introducción

En este documento se presenta una simulación del modelo Lotka–Volterra (depredador-presa) con ruido, utilizando una red neuronal artificial entrenada con el paquete nnet en R para predecir la evolución poblacional de un paso hacia adelante.


Instalación y carga de librerías

library(dplyr)
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
library(tidyr)
library(nnet)

set.seed(42)

simulate_lv <- function(T = 300,
                        r = 0.5, a = 0.02, b = 0.01, m = 0.3,
                        N0 = 40, P0 = 9, noiseN = 1.0, noiseP = 0.8) {
  N <- numeric(T); P <- numeric(T)
  N[1] <- N0; P[1] <- P0
  for (t in 2:T) {
    dN <- r * N[t-1] - a * N[t-1] * P[t-1]
    dP <- b * N[t-1] * P[t-1] - m * P[t-1]
    N[t] <- pmax(N[t-1] + dN + rnorm(1, 0, noiseN), 0)
    P[t] <- pmax(P[t-1] + dP + rnorm(1, 0, noiseP), 0)
  }
  tibble(t = 1:T, N = N, P = P)
}

df_ts <- simulate_lv()

df <- df_ts |>
  transmute(
    N_t   = N,
    P_t   = P,
    N_tp1 = lead(N),
    P_tp1 = lead(P)
  ) |>
  drop_na()

set.seed(123)
n <- nrow(df)
idx <- sample.int(n, size = floor(0.7*n))
train <- df[idx, ]
test  <- df[-idx, ]

minmax_fit <- function(x) list(min = min(x), max = max(x))
minmax_tr  <- function(x, s) (x - s$min) / (s$max - s$min + 1e-8)
minmax_inv <- function(z, s) z * (s$max - s$min + 1e-8) + s$min

cols <- c("N_t","P_t","N_tp1","P_tp1")
sc <- lapply(train[cols], minmax_fit)

train_s <- train; test_s <- test
for (nm in cols) {
  train_s[[nm]] <- minmax_tr(train[[nm]], sc[[nm]])
  test_s[[nm]]  <- minmax_tr(test[[nm]],  sc[[nm]])
}

x_train <- as.matrix(train_s[, c("N_t","P_t")])
y_train <- as.matrix(train_s[, c("N_tp1","P_tp1")])
x_test  <- as.matrix(test_s[,  c("N_t","P_t")])

set.seed(999)
model <- nnet(
  x = x_train,
  y = y_train,
  size = 8,        # 8 neuronas ocultas
  linout = TRUE,   # salida lineal (regresión)
  rang = 0.1,
  decay = 1e-4,
  maxit = 500,
  trace = FALSE
)

pred_s <- predict(model, x_test)
pred <- tibble(
  N_hat = minmax_inv(pred_s[,1], sc$N_tp1),
  P_hat = minmax_inv(pred_s[,2], sc$P_tp1)
)

res <- bind_cols(test, pred)

mae  <- function(y, yhat) mean(abs(y - yhat))
rmse <- function(y, yhat) sqrt(mean((y - yhat)^2))

metrics <- tibble(
  Variable = c("Presas (N)","Depredadores (P)"),
  MAE  = c(mae(res$N_tp1, res$N_hat), mae(res$P_tp1, res$P_hat)),
  RMSE = c(rmse(res$N_tp1, res$N_hat), rmse(res$P_tp1, res$P_hat))
)
metrics
## # A tibble: 2 × 3
##   Variable           MAE  RMSE
##   <chr>            <dbl> <dbl>
## 1 Presas (N)       11.5  19.3 
## 2 Depredadores (P)  1.89  3.15
plot_df <- res |>
  mutate(idx = row_number()) |>
  select(idx, N_real = N_tp1, N_pred = N_hat,
         P_real = P_tp1, P_pred = P_hat) |>
  pivot_longer(-idx, names_to = "serie", values_to = "valor")

ggplot(plot_df, aes(x = idx, y = valor, color = serie)) +
  geom_line(linewidth = 0.9) +
  scale_color_manual(
    values = c("N_real" = "#0000FF","N_pred" = "#87CEFA",
               "P_real" = "#FFC0CB","P_pred" = "#FF0000"),
    labels = c("N_real"="Presas (real)","N_pred"="Presas (pred.)",
               "P_real"="Depredadores (real)","P_pred"="Depredadores (pred.)")
  ) +
  labs(
    title = "Predicción de un paso con red neuronal (nnet)",
    subtitle = "Sólido = real | Semitransparente = predicción",
    x = "Índice en conjunto de prueba", y = "Población"
  ) +
  theme_minimal(base_size = 12) +
  theme(legend.title = element_blank())