--- title: "Getting started with fgls" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with fgls} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` ```{r setup} library(fgls) ``` **fgls** estimates linear regressions by *feasible generalized least squares* (FGLS). It implements two recent methods: * **Serial correlation** (Perron and González-Coya, 2026): the errors are approximated by an autoregression whose order is chosen by BIC and whose coefficients come from a *Durbin regression*. The resulting estimator is consistent even when the regressors are only *pre-determined*, a situation where OLS and Cochrane-Orcutt are not. A variance estimator accounts for the estimated filter. * **Heteroskedasticity of unknown form** (González-Coya and Perron, 2024): the log of the squared residuals is modeled by an *adaptive Lasso* over a dictionary of candidate covariates, and the weighted regression is paired with a bias-corrected sandwich variance that stays valid when that model is wrong. The two corrections can be combined (Supplement S-4 of the 2026 paper). The R package is a port of the Python package [pyfgls](https://pypi.org/project/pyfgls/), and the two agree to machine precision on deterministic quantities (see `vignette("validation")`). ## Three examples ### Serial correlation `simulate_serial()` generates the design of Table 1 of the 2026 paper: AR(1) errors with coefficient 0.8, and a regressor that responds to past innovations, \(x_t = v_t + e_{t-1}\), so it is pre-determined but not exogenous. ```{r serial} sim <- simulate_serial(500, seed = 1) fit <- serial_fgls(y ~ x, data = sim) summary(fit) ``` The true slope is 1. OLS is badly biased in this design; FGLS is not: ```{r serial-compare} compare_fgls(OLS = lm(y ~ x, data = sim), FGLS = fit) ``` `fit$ar_order` is the order chosen by BIC, `fit$rho` the AR coefficients and `fit$nonexogeneity_share` the relative size of the correction that makes the variance robust to non-exogenous regressors. ### Heteroskedasticity of unknown form ```{r hetero} het <- simulate_hetero(200, skedastic = "log2", seed = 2) fit_h <- lasso_fgls(y ~ x, data = het, seed = 1) fit_h$skedastic$selected compare_fgls(OLS = lm(y ~ x, data = het), FGLS = fit_h) ``` The candidate covariates default to \(x, x^2, \log x, (\log x)^2, \cos x, \cos 2x\) for every non-constant regressor (`make_dictionary()`); supply your own with `z`. The penalty and the exponent of the adaptive weights are chosen by 10-fold cross-validation, so set `seed` for reproducible results. ### Both ```{r combined} both <- simulate_combined(200, ar = 0.5, skedastic = "x2", seed = 3) fit_b <- fgls(y ~ x, data = both, seed = 1) fit_b compare_fgls(`F-C` = fit_b$stages$serial, `F-CH` = fit_b) ``` `fgls()` is the general function: `serial = "none"` gives the heteroskedasticity-only estimator and `hetero = "none"` the serial-only one. ## Working with fits Fits behave like `lm` objects: ```{r methods} coef(fit) confint(fit, level = 0.9) predict(fit, newdata = data.frame(x = c(-1, 0, 1)), interval = "confidence") vcov(fit, type = "naive") # PG26 eq. (27), valid only for exogenous regressors ``` They work with `lmtest::coeftest()`, `lmtest::coefci()` and the broom generics `tidy()`, `glance()` and `augment()`. `plot(fit)` draws diagnostics: the autocorrelation function of the innovations (residuals of the final filtered regression) should look like white noise. ## Time series inputs Rows must be in time order. Besides data frames, `fgls()` accepts `ts`, `zoo` and `xts` objects; a data frame can carry a time index through `time =`, which is checked for sorting and gaps: ```{r ts} dates <- seq(as.Date("2000-01-01"), by = "month", length.out = 500) df <- data.frame(date = dates, sim) serial_fgls(y ~ x, data = df, time = "date")$ar_order ``` ## Choosing options * With several stochastic regressors, the BIC that penalizes only the AR order can select the largest order; use `control = fgls_control(ic_penalty = "params")`. * Declare lagged dependent variables among the regressors in `lagged_dep_vars`. * For errors known to be MA(1), such as multi-step forecast errors, use `serial = "ma1"`. * `exog = "exogenous"` never changes the estimates. In the serial-only estimator it only changes the notes, and the robust variance is valid either way. In the combined estimator it also drops the first-stage correction from the variance by default (`first_stage_correction = FALSE`); that correction is needed when the regressors are only pre-determined, so keep the default `exog = "predetermined"` unless they are known to be exogenous. See `vignette("serial-correlation")`, `vignette("heteroskedasticity")` and `vignette("combined")` for the methods in more detail. ## References Perron, P. and González-Coya, E. (2026). Feasible GLS for time series regression. *Journal of Econometrics*, 258, 106346. González-Coya, E. and Perron, P. (2024). Estimation in the presence of heteroskedasticity of unknown form: a Lasso-based approach. *Journal of Econometric Methods*, 13(1), 29--48.