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.
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.
# ---------------------------------------------------------------------------------
# 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): ________.
# ---------------------------------------------------------------------------------
# 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): ________.
# ---------------------------------------------------------------------------------
# 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: ________.
# ---------------------------------------------------------------------------------
# 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)")
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))
# ---------------------------------------------------------------------------------
# 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
# ---------------------------------------------------------------------------------
# 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): ________.
# 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.
# 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
(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í.