1 Introducción

En Ciencias de Datos y Estadística aplicada, la simulación de datos es una herramienta fundamental para:

  • Diseñar y probar modelos estadísticos y de machine learning sin depender de bases de datos reales.
  • Ilustrar conceptos teóricos en un contexto controlado (docencia, talleres, cursos).
  • Evaluar el comportamiento de estimadores, pruebas de hipótesis y métricas de desempeño bajo distintos escenarios.
  • Prototipar pipelines de análisis, desde la exploración hasta el modelado.

En este documento se utilizan principalmente tres funciones de R para simulación:

  • rnorm() para generar datos con distribución normal.
  • runif() para generar datos con distribución uniforme.
  • simulate() para generar respuestas simuladas a partir de un modelo ajustado (por ejemplo, regresión lineal).

A continuación se presentan varios ejemplos con contexto aplicado y explicaciones detalladas de cada bloque de código.


2 Ejemplo 1: rnorm() en un contexto educativo

En este ejemplo se simulan puntuaciones de estudiantes bajo tres métodos de enseñanza:
Tradicional, Interactivo y Online. El objetivo es disponer de una base simulada para comparar estadísticamente el rendimiento promedio de cada método (por ejemplo, con ANOVA).

2.1 Código

# Generar datos simulados con rnorm en un contexto educativo

# Fijar semilla para garantizar reproducibilidad
set.seed(123)

# Crear un data.frame con el método de enseñanza y las puntuaciones simuladas
datos <- data.frame(
  Metodo = rep(c("Tradicional", "Interactivo", "Online"), each = 10),  # 3 métodos, 10 estudiantes cada uno
  Puntuacion = c(
    rnorm(10, mean = 70, sd = 5),  # Método Tradicional
    rnorm(10, mean = 75, sd = 6),  # Método Interactivo
    rnorm(10, mean = 78, sd = 4)   # Método Online
  )
)

# Mostrar las primeras filas
head(datos)
##        Metodo Puntuacion
## 1 Tradicional   67.19762
## 2 Tradicional   68.84911
## 3 Tradicional   77.79354
## 4 Tradicional   70.35254
## 5 Tradicional   70.64644
## 6 Tradicional   78.57532

2.2 Explicación del código

  • set.seed(123): fija la semilla del generador de números aleatorios. Esto asegura que cualquiera que ejecute este documento obtendrá los mismos datos simulados.
  • data.frame(...): crea una tabla con columnas llamadas Metodo y Puntuacion.
  • rep(c("Tradicional", "Interactivo", "Online"), each = 10): genera un vector con 30 elementos, repitiendo cada método 10 veces (10 estudiantes por método).
  • rnorm(10, mean = 70, sd = 5): genera 10 puntuaciones con distribución normal, media 70 y desviación estándar 5 (método tradicional).
  • Las otras dos llamadas a rnorm() crean puntuaciones para los métodos interactivo y online, con medias y dispersiones diferentes.
  • head(datos): muestra una vista rápida de las primeras observaciones para validar que la estructura es correcta.

2.3 Importancia para Ciencias de Datos

Este tipo de simulación permite:

  • Crear ejemplos docentes para explicar comparaciones de medias (ANOVA, pruebas t).
  • Probar gráficos (boxplots, histogramas, densidades) sin usar datos sensibles.
  • Diseñar escenarios controlados de evaluación de métodos de enseñanza, reproduciendo las mismas condiciones cuantas veces sea necesario.

3 Ejemplo 2: runif() en tiempos de respuesta de clientes

Aquí se simulan tiempos de respuesta (en segundos) de una plataforma digital para clientes de distintos países y tipos de servicio.

3.1 Código

# Simulación de tiempos de respuesta con runif en un contexto de servicio al cliente

# Fijar semilla para reproducibilidad
set.seed(123)

# Definir tamaño de muestra
n <- 100

# Simular tiempos de respuesta entre 0 y 5 segundos
tiempos_respuesta <- runif(n = n, min = 0, max = 5)

# Crear un data.frame con información adicional del cliente
data_simulada <- data.frame(
  ID_Cliente  = 1:n,
  Tiempo_Respuesta = tiempos_respuesta,
  Pais = sample(c("Colombia", "México", "Chile", "Perú"), 
                size = n, replace = TRUE),
  Tipo_Servicio = sample(c("Transferencia", "Consulta", "Pago", "Reclamo"),
                         size = n, replace = TRUE)
)

# Mostrar las primeras filas
head(data_simulada)
##   ID_Cliente Tiempo_Respuesta     Pais Tipo_Servicio
## 1          1        1.4378876 Colombia      Consulta
## 2          2        3.9415257     Perú      Consulta
## 3          3        2.0448846   México       Reclamo
## 4          4        4.4150870 Colombia Transferencia
## 5          5        4.7023364     Perú       Reclamo
## 6          6        0.2277825   México       Reclamo

3.2 Explicación del código

  • n <- 100: define que se simularán datos para 100 clientes.
  • runif(n = n, min = 0, max = 5): genera 100 tiempos de respuesta con distribución uniforme entre 0 y 5 segundos.
  • data.frame(...): construye una tabla con:
    • ID_Cliente: un identificador secuencial de 1 a 100.
    • Tiempo_Respuesta: el tiempo uniforme simulado.
    • Pais: país asignado aleatoriamente con sample() a partir de un conjunto de países latinoamericanos.
    • Tipo_Servicio: tipo de operación (transferencia, consulta, pago, reclamo), también asignada con sample().

3.3 Importancia para Ciencias de Datos

Este dataset simulado permite:

  • Analizar tiempos de respuesta por país y tipo de servicio.
  • Probar dashboards en Shiny, Power BI o aplicaciones web sin exponer datos reales.
  • Diseñar ejemplos prácticos para cursos de calidad de servicio, colas y rendimiento de sistemas.

4 Ejemplo 3: simulate() con un modelo de regresión lineal

En este ejemplo se usa la función simulate() para generar nuevas respuestas simuladas a partir de un modelo de regresión lineal ajustado con la base cars.

4.1 Código

# Uso de simulate() con un modelo de regresión lineal

# Tomar las primeras 5 observaciones del conjunto cars
datos_cars <- cars[1:5, ]

# Ajustar un modelo lineal de distancias de frenado en función de la velocidad
mod <- lm(dist ~ speed, data = datos_cars)

# Simular nuevas distancias de frenado a partir del modelo ajustado
sim_dist <- simulate(object = mod, nsim = 1, seed = 1234)

# Mostrar datos originales y simulados
datos_cars
##   speed dist
## 1     4    2
## 2     4   10
## 3     7    4
## 4     7   22
## 5     8   16
sim_dist
##       sim_1
## 1 -3.769550
## 2  8.175135
## 3 21.954305
## 4 -5.645603
## 5 19.110007

4.2 Explicación del código

  • cars[1:5, ]: selecciona las primeras 5 filas del conjunto de datos cars, que contiene:
    • speed: velocidad del automóvil.
    • dist: distancia de frenado.
  • lm(dist ~ speed, data = datos_cars): ajusta una regresión lineal donde la distancia de frenado se modela como función de la velocidad.
  • simulate(object = mod, nsim = 1, seed = 1234):
    • Usa el modelo mod para generar una simulación de la variable respuesta dist.
    • nsim = 1 indica que se generará un solo conjunto simulado.
    • seed = 1234 fija la semilla interna de la simulación.
  • El resultado sim_dist muestra distancias de frenado simuladas coherentes con el modelo ajustado.

4.3 Importancia para Ciencias de Datos

El uso de simulate() es relevante para:

  • Realizar experimentos de Monte Carlo basados en modelos estimados.
  • Evaluar la variabilidad de predicciones y estadísticas derivadas.
  • Enseñar el vínculo entre modelo teórico (lm) y datos observados/simulados en cursos de regresión.

5 Ejemplo 4: runif() + rnorm() en un contexto de Churn (Machine Learning)

En este ejemplo se construye un dataset para un problema de clasificación de abandono de clientes (churn), combinando runif() y rnorm().

5.1 Código

# Simulación de un problema de churn (abandono de clientes)

# Fijar semilla
set.seed(2026)

# Variables numéricas simuladas con runif
tiempo_uso <- runif(n = 200, min = 0, max = 120)   # minutos diarios de uso de la plataforma
transacciones <- runif(n = 200, min = 0, max = 40) # número de transacciones mensuales
satisfaccion <- runif(n = 200, min = 1, max = 5)   # nivel de satisfacción (1 a 5)

# Variable binaria: churn (1 = abandona, 0 = no abandona)
churn <- ifelse(
  0.4 * tiempo_uso + 0.6 * transacciones + rnorm(200, 0, 20) > 50,
  1, 0
)

# Construir el data.frame con las variables simuladas
datos_ml <- data.frame(
  Tiempo_Uso = tiempo_uso,
  Transacciones = transacciones,
  Satisfaccion = satisfaccion,
  Churn = factor(churn)
)

# Mostrar las primeras filas
head(datos_ml)
##   Tiempo_Uso Transacciones Satisfaccion Churn
## 1  83.840817      35.52233     2.331444     1
## 2  66.783661      25.21652     2.631264     0
## 3  16.816795      12.42834     3.706944     0
## 4  34.286797      38.52861     1.599441     1
## 5  66.644281      16.39627     2.637191     0
## 6   3.015738      29.92520     1.348459     0
# División entrenamiento / prueba (70 % / 30 %)
set.seed(2026)
indice <- sample(1:nrow(datos_ml), size = 0.7 * nrow(datos_ml))

train <- datos_ml[indice, ]
test  <- datos_ml[-indice, ]

5.2 Explicación del código

  • Se simulan tres variables de comportamiento de cliente con runif():
    • Tiempo_Uso: minutos de uso de la plataforma por día.
    • Transacciones: número de transacciones al mes.
    • Satisfaccion: nivel de satisfacción entre 1 y 5.
  • churn <- ifelse(...): define la variable objetivo:
    • Se construye una combinación lineal de tiempo_uso y transacciones.
    • rnorm(200, 0, 20) añade ruido normal para representar variabilidad no explicada.
    • La condición > 50 establece un umbral para clasificar en 1 (abandona) o 0 (no abandona).
  • data.frame(...): reúne las variables en una estructura apta para modelado.
  • factor(churn): convierte la variable objetivo a factor, útil para modelos de clasificación.
  • sample(1:nrow(datos_ml), size = 0.7 * nrow(datos_ml)): selecciona índices aleatorios para el conjunto de entrenamiento (70 % de las observaciones).
  • train y test: forman los conjuntos de entrenamiento y prueba.

5.3 Importancia para Ciencias de Datos

Este ejemplo es útil para:

  • Practicar el flujo completo de machine learning supervisado: exploración, partición train/test, ajuste de modelos y evaluación.
  • Demostrar cómo el ruido (rnorm) afecta la clasificación.
  • Prototipar algoritmos de clasificación como regresión logística, árboles de decisión, random forest, etc.

6 Ejemplo 5: rnorm() + runif() en un contexto de riesgo crediticio

Por último, se simula un problema más complejo de riesgo crediticio, combinando variables normales y uniformes para construir un escenario realista.

6.1 Código

# Simulación de un problema de riesgo crediticio

# Fijar semilla para reproducibilidad
set.seed(2026)

# Variables con distribución normal (rnorm)
ingresos <- rnorm(n = 300, mean = 3500, sd = 900)    # Ingreso mensual
deuda    <- rnorm(n = 300, mean = 1200, sd = 300)    # Deuda mensual
edad     <- rnorm(n = 300, mean = 40, sd = 12)       # Edad del solicitante

# Variables con distribución uniforme (runif)
score_historial <- runif(n = 300, min = 300, max = 850)   # Score crediticio
ratio_uso       <- runif(n = 300, min = 0, max = 1)       # Porcentaje de uso de la tarjeta

# Generación de variable objetivo (riesgo: 1 = alto, 0 = bajo)
riesgo <- ifelse(
  0.003 * ingresos - 0.002 * deuda - 1.5 * ratio_uso +
    rnorm(300, 0, 0.5) + (score_historial / 1000) < 1.6,
  1, 0
)

# Construcción del data.frame final
datos_credito <- data.frame(
  Ingresos = ingresos,
  Deuda = deuda,
  Edad = edad,
  Score = score_historial,
  Ratio_Uso = ratio_uso,
  Riesgo = factor(riesgo)
)

# Mostrar las primeras filas
head(datos_credito)
##   Ingresos     Deuda     Edad    Score Ratio_Uso Riesgo
## 1 3968.530 1155.4224 51.54566 627.5871 0.9105402      0
## 2 2528.278 1145.1142 37.86238 406.1334 0.6387369      0
## 3 3625.314  942.5556 40.03948 485.3961 0.2996506      0
## 4 3423.726 1487.4478 46.13938 401.3664 0.2634275      0
## 5 2900.024  948.2769 34.52727 458.9722 0.5012102      0
## 6 1235.520  972.0827 37.46915 387.3767 0.2506156      1

6.2 Explicación del código

  • ingresos, deuda y edad se simulan con rnorm():
    • Cada una tiene una media y desviación estándar elegidas para representar un contexto financiero plausible.
  • score_historial y ratio_uso se simulan con runif():
    • score_historial entre 300 y 850 (típico de scores crediticios).
    • ratio_uso entre 0 y 1, interpretado como porcentaje de utilización del crédito.
  • En la construcción de riesgo:
    • Ingresos altos reducen el riesgo.
    • Deuda alta y alto ratio_uso incrementan el riesgo.
    • rnorm(300, 0, 0.5) aporta ruido para que la frontera de decisión no sea perfecta, imitando un contexto real.
    • (score_historial / 1000) ajusta el riesgo según el historial crediticio.
    • La condición < 1.6 define el umbral para clasificar a los clientes como de alto riesgo (1) o bajo riesgo (0).
  • datos_credito reúne todas las variables en un solo data.frame apto para:
    • Entrenar modelos de clasificación de riesgo.
    • Evaluar métricas como accuracy, AUC, sensibilidad y especificidad.
    • Construir dashboards de riesgo crediticio.

7 Conclusiones

En este documento se han integrado, dentro de un único RMarkdown, varios ejemplos donde se combinan:

  • rnorm() para simular variables con distribución normal.
  • runif() para simular variables con distribución uniforme.
  • simulate() para generar datos a partir de modelos ajustados.

Cada ejemplo incluye:

  • Código completamente reproducible.
  • Explicaciones detalladas de cada línea, comando y función.
  • Contextos aplicados (educación, servicio al cliente, churn, riesgo crediticio).

La simulación de datos es una herramienta esencial en Ciencias de Datos porque permite:

  • Probar ideas, algoritmos y modelos sin depender de datos sensibles.
  • Desarrollar material docente de alta calidad.
  • Diseñar experimentos computacionales controlados para comprender el comportamiento de los métodos estadísticos y de machine learning.

Este RMarkdown puede servir como base para talleres, clases prácticas o como documento de estudio para estudiantes de estadística y ciencia de datos.