Propósito. Esta plantilla documentada guía el flujo completo del taller: (i) justificar variables por fundamento económico, (ii) estimar y comparar especificaciones con 4, 3, 2 y 1 regresores, (iii) probar formas funcionales (lin–lin, log–lin, lin–log, log–log) y (iv) validar supuestos MRLS (RESET; BP/White; DW/BG; JB), aplicando correcciones (HC/WLS/HAC/IV) cuando proceda.
Los comentarios explican qué hace cada línea y se incluyen docstrings (estilo roxygen2) para funciones auxiliares.

1 1. Preparación del entorno

2 2. Formulación: pregunta, hipótesis y fundamento económico

Defina con precisión el fenómeno, mecanismo causal y signos esperados de los parámetros.
- Y (dependiente): ________ (defina unidad de medida y justifique).
- X (candidatas): ________ (mecanismos de oferta/demanda, restricciones, instituciones, dotaciones, preferencias, etc.).
- Amenazas a la validez: omitidas, simultaneidad, medición, selección, etc.


3 3. Carga de datos y construcción de variables

# ---------------------------------------------------------------------------------
# BLOQUE: datos
# Objetivo: cargar los datos según el "caso" seleccionado y construir transformaciones.
# Casos:
#   A: Consumo vs PIB pc (corte transversal). Fuente: WDI (o CSV local).
#   B: Demanda de cigarrillos (posible IV). Fuente: paquete wooldridge.
#   C: Salario-educación (microdatos). Fuente: paquete wooldridge.
#   D: Curva de Phillips (serie de tiempo). Fuente: CSV local / banco central.
# ---------------------------------------------------------------------------------

caso <- params$caso                # ← Lee el caso elegido en el YAML.
usar_internet <- params$usar_internet
ruta_local <- params$ruta_local

if (caso == "A") {
  # --------------------------
  # Caso A: Consumo–PIB pc
  # --------------------------
  if (usar_internet && requireNamespace("WDI", quietly = TRUE)) {
    # Descarga de indicadores WDI si hay internet
    library(WDI)
    wdi <- WDI(
      country  = "all",                                    # Todos los países
      indicator = c(gdp_pc = "NY.GDP.PCAP.KD",             # PIB per cápita (US$ 2015)
                    cons_pc = "NE.CON.PRVT.PC.KD"),        # Consumo privado per cápita
      start = 2015, end = 2023
    ) |> as_tibble()
    # Para cada país, nos quedamos con el último año disponible
    df <- wdi |> dplyr::group_by(iso2c) |> dplyr::filter(year == max(year)) |> dplyr::ungroup()
  } else {
    # Alternativa: leer desde CSV local preparado para el taller
    df <- readr::read_csv(file.path(ruta_local, "wdi_consumo_pibpc.csv"))
  }
  # Selección/renombrado y creación de logs para formas funcionales
  df <- df |>
    dplyr::rename(gdp_pc = gdp_pc, cons_pc = cons_pc) |>
    dplyr::filter(is.finite(gdp_pc), is.finite(cons_pc)) |>
    dplyr::transmute(y = cons_pc, x1 = gdp_pc) |>
    dplyr::mutate(ly = log(y), lx1 = log(x1))
}

if (caso == "B") {
  # --------------------------
  # Caso B: Demanda de cigarrillos (IV potencial)
  # --------------------------
  data("cigarette", package = "wooldridge")  # Carga conjunto del paquete
  df <- as_tibble(cigarette) |>
    dplyr::filter(is.finite(packs), is.finite(price), is.finite(tax), is.finite(income)) |>
    dplyr::transmute(
      y  = packs,   # Demanda (paquetes per cápita)
      x1 = price,   # Precio (potencialmente endógeno)
      x2 = income,  # Ingreso (control)
      z1 = tax      # Instrumento propuesto para price
    ) |>
    dplyr::mutate(
      ly  = log(y),
      lx1 = log(pmax(x1, .Machine$double.eps)),
      lx2 = log(pmax(x2, .Machine$double.eps))
    )
}

if (caso == "C") {
  # --------------------------
  # Caso C: Salario y educación
  # --------------------------
  data("mroz", package = "wooldridge")
  df <- as_tibble(mroz) |>
    dplyr::select(wage, educ, exper, age) |>
    dplyr::filter(is.finite(wage), wage > 0, is.finite(educ), is.finite(exper), is.finite(age)) |>
    dplyr::transmute(
      y  = wage,   # Salario horario
      x1 = educ,   # Años de educación
      x2 = exper,  # Experiencia potencial
      x3 = age     # Edad (control de ciclo de vida)
    ) |>
    dplyr::mutate(
      ly  = log(y),
      lx1 = log(pmax(x1, 1)), lx2 = log(pmax(x2, 1)), lx3 = log(pmax(x3, 1))
    )
}

if (caso == "D") {
  # --------------------------
  # Caso D: Curva de Phillips (serie trimestral)
  # --------------------------
  df <- readr::read_csv(file.path(ruta_local, "phillips.csv")) |>
    dplyr::mutate(date = as.Date(date)) |>
    dplyr::arrange(date) |>
    dplyr::transmute(date, y = infl, x1 = unemp) |>
    # Logs "seguros" (transformación ejemplo si variables pueden ser negativas)
    dplyr::mutate(ly = log(pmax(y + 100, 1)) - log(100),
                  lx1 = log(pmax(x1 + 100, 1)) - log(100))
}

# Inspección de estructura resultante:
glimpse(df)
## Rows: 50
## Columns: 4
## $ y   <dbl> 5438.02, 16723.26, 15570.01, 5205.22, 8980.74, 27229.84, 6294.65, …
## $ x1  <dbl> 6255.92, 21830.63, 14220.63, 4860.44, 8480.31, 32322.66, 2797.98, …
## $ ly  <dbl> 8.601170, 9.724556, 9.653102, 8.557417, 9.102838, 10.212069, 8.747…
## $ lx1 <dbl> 8.741283, 9.991069, 9.562449, 8.488884, 9.045502, 10.383524, 7.936…

Describa la muestra (fuente, periodo, filtros, N y unidades): ________.


4 4. Formas funcionales y significados

# ---------------------------------------------------------------------------------
# BLOQUE: formas
# Objetivo: declarar fórmulas para las cuatro formas funcionales estándar.
# Interpretación económica:
#   lin–lin  → cambios absolutos.
#   log–lin  → semi-elasticidad en Y (Δ%Y por unidad de X).
#   lin–log  → semi-elasticidad en X (ΔY por 1% en X / 100).
#   log–log  → elasticidad (Δ%Y / Δ%X).
# ---------------------------------------------------------------------------------

# Fórmulas con 1 regresor (x1) — más abajo se generaliza a 4,3,2,1 regresores
f_linlin  <- y  ~ x1   # niveles en ambas
f_loglin  <- ly ~ x1   # log(Y) sobre X
f_linlog  <- y  ~ lx1  # Y sobre log(X)
f_loglog  <- ly ~ lx1  # log(Y) sobre log(X)

# Estimaciones rápidas de referencia (solo demostrativas)
mods_base <- list(linlin = f_linlin, loglin = f_loglin, linlog = f_linlog, loglog = f_loglog)
lapply(mods_base, function(f) summary(lm(f, data = df))$coefficients)
## $linlin
##                 Estimate   Std. Error  t value     Pr(>|t|)
## (Intercept) 3334.9087333 380.57180360  8.76289 1.587973e-11
## x1             0.6824148   0.01958021 34.85228 9.679929e-36
## 
## $loglin
##                 Estimate   Std. Error   t value     Pr(>|t|)
## (Intercept) 8.721138e+00 6.025002e-02 144.74912 4.741422e-65
## x1          4.290824e-05 3.099830e-06  13.84212 2.225182e-18
## 
## $linlog
##              Estimate Std. Error   t value     Pr(>|t|)
## (Intercept) -83431.09  6358.5367 -13.12112 1.713815e-17
## lx1          10358.78   674.4538  15.35877 3.729436e-20
## 
## $loglog
##              Estimate Std. Error   t value     Pr(>|t|)
## (Intercept) 2.4581674 0.36181893  6.793916 1.522428e-08
## lx1         0.7372155 0.03837835 19.209152 3.558170e-24

Explique ex–ante qué forma esperaría mejor ajuste y por qué (teoría/elasticidades/outliers): ________.


5 5. Selección económica de variables (4, 3, 2 y 1)

# ---------------------------------------------------------------------------------
# BLOQUE: especificaciones
# Objetivo: definir conjuntos de regresores con 4, 3, 2 y 1 variable(s) usando criterio económico.
# Nota: edite el vector 'cand' con las variables disponibles en 'df'.
# ---------------------------------------------------------------------------------

# (1) Defina candidatas por caso (EDITE según su fundamentación teórica)
if (caso == "A")  cand <- c("x1")               # puede construir variables adicionales y agregarlas
if (caso == "B")  cand <- c("x1","x2")          # price, income (IV: z1 = tax disponible para 2SLS)
if (caso == "C")  cand <- c("x1","x2","x3")     # educ, exper, age
if (caso == "D")  cand <- c("x1")               # unemp (puede añadir rezagos en sección D)

# (2) Particione en 4,3,2,1 (si faltan, recorte al máximo posible)
vars4 <- cand[seq_len(min(4, length(cand)))]
vars3 <- cand[seq_len(min(3, length(cand)))]
vars2 <- cand[seq_len(min(2, length(cand)))]
vars1 <- cand[seq_len(1)]

# (3) Función auxiliar para construir fórmulas
#' Construye una fórmula R a partir del objetivo (Y) y un vector de regresores.
#'
#' @param target  (character) nombre de la variable objetivo, p.ej. "y" o "ly".
#' @param vars    (character) vector con nombres de regresores, p.ej. c("x1","x2").
#' @return        (formula) objeto de clase formula, p.ej. y ~ x1 + x2.
#' @examples
#' build_formula("y", c("x1","x2"))
build_formula <- function(target, vars) {
  # `paste(vars, collapse = " + ")` concatena los nombres con " + " entre ellos.
  as.formula(paste(target, "~", paste(vars, collapse = " + ")))
}

# (4) Conjunto de fórmulas para cada tamaño (k) y forma funcional
f_set <- list(
  k1 = list(
    linlin = build_formula("y",  vars1),                    # y ~ x1
    loglin = build_formula("ly", vars1),                    # ly ~ x1
    linlog = build_formula("y",  paste0("l", vars1)),       # y ~ lx1
    loglog = build_formula("ly", paste0("l", vars1))        # ly ~ lx1
  ),
  k2 = list(
    linlin = build_formula("y",  vars2),
    loglin = build_formula("ly", vars2),
    linlog = build_formula("y",  paste0("l", vars2)),
    loglog = build_formula("ly", paste0("l", vars2))
  ),
  k3 = list(
    linlin = build_formula("y",  vars3),
    loglin = build_formula("ly", vars3),
    linlog = build_formula("y",  paste0("l", vars3)),
    loglog = build_formula("ly", paste0("l", vars3))
  ),
  k4 = list(
    linlin = build_formula("y",  vars4),
    loglin = build_formula("ly", vars4),
    linlog = build_formula("y",  paste0("l", vars4)),
    loglog = build_formula("ly", paste0("l", vars4))
  )
)

# Vista de ejemplo del set más simple:
str(f_set$k1)
## List of 4
##  $ linlin:Class 'formula'  language y ~ x1
##   .. ..- attr(*, ".Environment")=<environment: 0x000001ea63f6f898> 
##  $ loglin:Class 'formula'  language ly ~ x1
##   .. ..- attr(*, ".Environment")=<environment: 0x000001ea63f7a318> 
##  $ linlog:Class 'formula'  language y ~ lx1
##   .. ..- attr(*, ".Environment")=<environment: 0x000001ea641844e0> 
##  $ loglog:Class 'formula'  language ly ~ lx1
##   .. ..- attr(*, ".Environment")=<environment: 0x000001ea6418e3c8>

Justifique económicamente por qué cada conjunto (4,3,2,1) contiene esas variables: ________.


6 6. Estimación OLS y resumen comparativo

# ---------------------------------------------------------------------------------
# BLOQUE: estimar
# Objetivo: ajustar OLS para todas las combinaciones y compilar métricas comparables.
# ---------------------------------------------------------------------------------

#' Ajusta una lista de fórmulas con OLS sobre un data.frame/tibble.
#'
#' @param form_list (list) lista con objetos formula.
#' @param data      (data.frame) datos a usar.
#' @return          (list) lista de objetos "lm" ajustados.
ajustar_modelos <- function(form_list, data) {
  # purrr::map itera sobre la lista y ajusta lm() en cada fórmula.
  purrr::map(form_list, ~ stats::lm(.x, data = data))
}

# Ajuste: mods es una lista de listas: niveles k1..k4 y dentro formas funcionales
mods <- purrr::map(f_set, ajustar_modelos, data = df)

# Resumen tabular: R2, R2 ajustado, AIC, BIC y tamaño muestral
tab_ols <- purrr::imap_dfr(mods, function(mset, k) {
  dplyr::bind_rows(lapply(names(mset), function(ff){
    m <- mset[[ff]]
    g <- broom::glance(m)  # glance() extrae métricas de ajuste
    tibble::tibble(
      tamano = k, forma = ff,
      r2 = g$r.squared, r2_adj = g$adj.r.squared,
      AIC = g$AIC, BIC = g$BIC,
      n = g$df.residual + length(coef(m))
    )
  }))
})

# Mostrar ordenado por tamaño y forma
knitr::kable(dplyr::arrange(tab_ols, tamano, forma), digits = 3,
             caption = "Resumen OLS por forma funcional y tamaño (k)")
Resumen OLS por forma funcional y tamaño (k)
tamano forma r2 r2_adj AIC BIC n
k1 linlin 0.962 0.961 884.505 890.241 50
k1 linlog 0.831 0.827 959.125 964.861 50
k1 loglin 0.800 0.795 9.413 15.149 50
k1 loglog 0.885 0.882 -18.291 -12.555 50
k2 linlin 0.962 0.961 884.505 890.241 50
k2 linlog 0.831 0.827 959.125 964.861 50
k2 loglin 0.800 0.795 9.413 15.149 50
k2 loglog 0.885 0.882 -18.291 -12.555 50
k3 linlin 0.962 0.961 884.505 890.241 50
k3 linlog 0.831 0.827 959.125 964.861 50
k3 loglin 0.800 0.795 9.413 15.149 50
k3 loglog 0.885 0.882 -18.291 -12.555 50
k4 linlin 0.962 0.961 884.505 890.241 50
k4 linlog 0.831 0.827 959.125 964.861 50
k4 loglin 0.800 0.795 9.413 15.149 50
k4 loglog 0.885 0.882 -18.291 -12.555 50

VIF (opcional, cuando haya ≥2 regresores):

# Si el modelo tiene >2 coeficientes (intercepto + ≥2 X), VIF es informativo sobre multicolinealidad.
calc_vif <- function(m) if (length(coef(m)) > 2) car::vif(m) else NA
vifs <- purrr::map(mods, ~ purrr::map(.x, calc_vif))

7 7. Validación de supuestos y correcciones

# ---------------------------------------------------------------------------------
# BLOQUE: tests
# Objetivo: ejecutar suite de diagnósticos sobre cada modelo y ofrecer correcciones.
# ---------------------------------------------------------------------------------

#' Aplica una batería de diagnósticos a un modelo OLS.
#'
#' @param m        (lm) objeto ajustado por lm().
#' @param data_ts  (logical) TRUE si los datos son temporales (autocorrelación relevante).
#' @param hac_lag  (integer) rezago máximo para Newey–West y BG.
#' @return         (list) lista con resultados de tests (RESET, BP, White, JB, DW, BG, HC/HAC).
#' @details
#'  - RESET: especificación/forma funcional (Ramsey).
#'  - BP/White: heterocedasticidad.
#'  - JB: normalidad (útil en n pequeño para t/z exactas).
#'  - DW/BG: autocorrelación (series de tiempo).
#'  - HC1/HAC: errores estándar robustos (corte transversal/serie).
diag_suite <- function(m, data_ts = FALSE, hac_lag = 4) {
  out <- list()
  # 1) RESET: compara contra potencias de valores ajustados (alerta de no linealidades)
  out$reset <- tryCatch(lmtest::resettest(m, power = 2:3, type = "fitted"),
                        error = function(e) NA)
  # 2) Breusch–Pagan clásico (var(u|X) constante?)
  out$bp    <- tryCatch(lmtest::bptest(m), error = function(e) NA)

  # 3) White aproximado: incluye términos cuadráticos en la varianza condicional
  f <- formula(m)                                # extrae fórmula del modelo
  vars <- attr(terms(f), "term.labels")          # nombres de regresores en el lado derecho
  if (length(vars) >= 1) {
    rhs <- paste0(vars, collapse = " + ")
    white_rhs <- paste0(rhs, " + ", paste0("I(", vars, "^2)", collapse = " + "))
    out$white <- tryCatch(lmtest::bptest(m, as.formula(paste("~", white_rhs))),
                          error = function(e) NA)
  } else out$white <- NA

  # 4) Jarque–Bera: normalidad de residuos (más relevante con n pequeño)
  out$jb <- tryCatch(tseries::jarque.bera.test(residuals(m)), error = function(e) NA)

  if (data_ts) {
    # 5) Durbin–Watson y Breusch–Godfrey: autocorrelación
    out$dw  <- tryCatch(lmtest::dwtest(m), error = function(e) NA)
    out$bg  <- tryCatch(lmtest::bgtest(m, order = hac_lag), error = function(e) NA)
    # 6) Errores HAC (Newey–West): robustos a hetero + autocorrelación débil
    out$hac <- tryCatch(lmtest::coeftest(m, vcov = sandwich::NeweyWest(m, lag = hac_lag, prewhite = FALSE)),
                        error = function(e) NA)
  } else {
    # 6') Errores HC1 (White) para corte transversal/microdatos
    out$hc1 <- tryCatch(lmtest::coeftest(m, vcov = sandwich::vcovHC(m, type = "HC1")),
                        error = function(e) NA)
  }
  out
}

# ¿Este caso es serie de tiempo?
is_ts <- (caso == "D")

# Aplicar diagnósticos a todos los modelos en "mods"
tests <- purrr::map(mods, ~ purrr::map(.x, diag_suite, data_ts = is_ts))

Gráficos de diagnóstico para el modelo preferido (cámbielo a voluntad):

# Seleccione un "modelo estrella" para ilustrar (cambie k y forma).
m_star <- mods$k4$loglog   # ← edite: ej. mods$k2$linlog, etc.

# augment() añade columnas como .fitted y .resid para graficar diagnósticos fácilmente.
res <- broom::augment(m_star)

# Dispersión de residuos vs ajustados (patrones → hetero / no linealidad)
p1 <- ggplot(res, aes(.fitted, .resid)) +
  geom_point() +                      # puntos de residuos
  geom_smooth(se = FALSE) +           # suavizador LOESS para ver tendencia
  labs(x = "Ajustados", y = "Residuos", title = "Residuos vs Ajustados")

# QQ-plot para evaluar normalidad (línea recta ≈ normalidad)
p2 <- ggplot(res, aes(sample = .resid)) +
  stat_qq() + stat_qq_line() +
  labs(title = "QQ-plot de residuos")

# Arreglo visual lado a lado
ggpubr::ggarrange(p1, p2, ncol = 2)

Series (solo D):

# Modelo simple en niveles para ilustrar autocorrelación
m <- mods$k1$linlin
# Pruebas de autocorrelación
lmtest::dwtest(m); lmtest::bgtest(m, order = 4)
# Errores HAC (Newey–West)
lmtest::coeftest(m, vcov = sandwich::NeweyWest(m, lag = 4, prewhite = FALSE))
# Funciones de autocorrelación de residuos
acf(resid(m)); pacf(resid(m))

WLS / HAC / Dinámica (según proceda):

if (!is_ts) {
  # Ejemplo de ponderación WLS si var(u|X) ∝ x1^2
  w <- 1/(df$x1^2)                               # pesos inversos a x1^2
  m_wls <- tryCatch(lm(formula(m_star), data = df, weights = w), error = function(e) NULL)
  if (!is.null(m_wls)) summary(m_wls)            # compare con OLS
} else {
  # Dinámica mínima en series: incluir un rezago del regresor x1
  if ("date" %in% names(df)) {
    df <- df |> dplyr::arrange(date) |> dplyr::mutate(x1_l1 = dplyr::lag(x1, 1))
    m_dyn <- lm(y ~ x1 + x1_l1, data = df)
    summary(m_dyn)
    lmtest::coeftest(m_dyn, vcov = sandwich::NeweyWest(m_dyn, lag = 4))
  }
}
## 
## Call:
## lm(formula = formula(m_star), data = df, weights = w)
## 
## Weighted Residuals:
##        Min         1Q     Median         3Q        Max 
## -1.105e-04 -5.876e-06  4.748e-06  1.153e-05  1.173e-04 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  3.43901    0.50893   6.757 1.73e-08 ***
## lx1          0.62750    0.05989  10.477 5.39e-14 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3.533e-05 on 48 degrees of freedom
## Multiple R-squared:  0.6957, Adjusted R-squared:  0.6894 
## F-statistic: 109.8 on 1 and 48 DF,  p-value: 5.393e-14

8 8. (Solo B) — Endogeneidad y 2SLS

# ---------------------------------------------------------------------------------
# BLOQUE: IV (2SLS)
# Objetivo: comparar OLS ingenuo vs IV usando tax como instrumento de price.
# ---------------------------------------------------------------------------------

# OLS "ingenuo" (posible sesgo si price es endógeno)
m_ols <- lm(y ~ x1 + x2, data = df)

# IV (2SLS): primera etapa instrumenta price con tax (manteniendo income exógeno)
m_iv  <- AER::ivreg(y ~ x1 + x2 | z1 + x2, data = df)

# Resúmenes con diagnósticos: incluye F de 1ra etapa y test de endogeneidad
summary(m_iv, diagnostics = TRUE)

# Errores robustos HC1 para comparar con OLS
lmtest::coeftest(m_ols, vcov = sandwich::vcovHC(m_ols, type = "HC1"))
lmtest::coeftest(m_iv,  vcov = sandwich::vcovHC(m_iv,  type = "HC1"))

Discuta validez del IV (relevancia y exogeneidad; amenazas de violación): ________.


9 9. Comparación y decisión de especificación

# Ordene por BIC (penaliza complejidad): menor BIC suele preferirse
best <- tab_ols |> dplyr::arrange(BIC) |> dplyr::slice(1)
best

Síntesis (≤10 líneas): Especificación elegida (forma y tamaño), signos/magnitudes, estado de supuestos y correcciones, interpretación económica (elasticidades/semielasticidades) y límites.


10 10. Reproducibilidad y sesión

# Información sobre versiones y plataforma para replicar resultados
sessionInfo()
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 10 x64 (build 19045)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=Spanish_Colombia.utf8  LC_CTYPE=Spanish_Colombia.utf8   
## [3] LC_MONETARY=Spanish_Colombia.utf8 LC_NUMERIC=C                     
## [5] LC_TIME=Spanish_Colombia.utf8    
## 
## time zone: America/Bogota
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] forecast_8.24.0  wooldridge_1.4-4 AER_1.2-15       survival_3.8-3  
##  [5] tseries_0.10-58  ggpubr_0.6.1     car_3.1-3        carData_3.0-5   
##  [9] sandwich_3.1-1   lmtest_0.9-40    zoo_1.8-14       broom_1.0.9     
## [13] lubridate_1.9.4  forcats_1.0.0    stringr_1.5.2    dplyr_1.1.4     
## [17] purrr_1.1.0      readr_2.1.5      tidyr_1.3.1      tibble_3.3.0    
## [21] ggplot2_4.0.0    tidyverse_2.0.0 
## 
## loaded via a namespace (and not attached):
##  [1] tidyselect_1.2.1   timeDate_4041.110  farver_2.1.2       S7_0.2.0          
##  [5] fastmap_1.2.0      digest_0.6.37      timechange_0.3.0   lifecycle_1.0.4   
##  [9] magrittr_2.0.3     compiler_4.5.1     rlang_1.1.6        sass_0.4.10       
## [13] tools_4.5.1        yaml_2.3.10        knitr_1.50         ggsignif_0.6.4    
## [17] labeling_0.4.3     bit_4.6.0          curl_7.0.0         TTR_0.24.4        
## [21] RColorBrewer_1.1-3 abind_1.4-8        withr_3.0.2        nnet_7.3-20       
## [25] grid_4.5.1         xts_0.14.1         colorspace_2.1-1   scales_1.4.0      
## [29] cli_3.6.5          rmarkdown_2.29     crayon_1.5.3       generics_0.1.4    
## [33] rstudioapi_0.17.1  tzdb_0.5.0         cachem_1.1.0       splines_4.5.1     
## [37] parallel_4.5.1     urca_1.3-4         vctrs_0.6.5        Matrix_1.7-3      
## [41] jsonlite_2.0.0     hms_1.1.3          bit64_4.6.0-1      rstatix_0.7.2     
## [45] Formula_1.2-5      jquerylib_0.1.4    quantmod_0.4.28    glue_1.8.0        
## [49] cowplot_1.2.0      stringi_1.8.7      gtable_0.3.6       quadprog_1.5-8    
## [53] pillar_1.11.0      htmltools_0.5.8.1  R6_2.6.1           vroom_1.6.5       
## [57] evaluate_1.0.5     lattice_0.22-7     backports_1.5.0    fracdiff_1.5-3    
## [61] bslib_0.9.0        Rcpp_1.1.0         nlme_3.1-168       mgcv_1.9-3        
## [65] xfun_0.53          pkgconfig_2.0.3

10.1 Apéndice — Espacios para sus respuestas (escriba en prosa)

(R1) Fundamentación teórica de variables (4, 3, 2, 1): escriba aquí su argumento.

(R2) Forma funcional preferida y por qué: escriba aquí.

(R3) Diagnósticos: interpretación de RESET, BP/White, DW/BG, JB: escriba aquí.

(R4) Correcciones aplicadas y efecto en inferencias: escriba aquí.

(R5) Conclusión ejecutiva: escriba aquí.