Apply Restricted Temporal Regression to mitigate temporal confounding. RTR orthogonalizes the temporal effect to the covariate space, preventing the temporal random effect from absorbing covariate information.
This is important when covariates have temporal trends (e.g., increasing over time) because the temporal random effect can "steal" variance from these covariates, leading to biased coefficient estimates.
Details
The RTR approach (analogous to Restricted Spatial Regression) modifies the temporal random effect to be orthogonal to the fixed effect design matrix:
$$f_{RTR}(t) = (I - P_X) f(t)$$
where \(P_X = X(X'X)^{-1}X'\) is the projection matrix onto the column space of X.
When to use RTR:
Covariates have temporal trends (e.g., increasing/decreasing over time)
Interested in causal interpretation of covariate effects
Coefficients appear attenuated toward zero
Time and covariates are correlated
When NOT to use RTR:
Covariates are temporally uncorrelated (random sampling over time)
Temporal effect is the primary quantity of interest
Prediction is the main goal (not causal inference)
References
Hanks, E. M., Schliep, E. M., Hooten, M. B., & Hoeting, J. A. (2015). Restricted spatial regression in practice: geostatistical models, confounding, and robustness under model misspecification. Environmetrics, 26(4), 243-254.
See also
temporal_rw1(), temporal_rw2(), temporal_gp(),
spatial_rsr() for the spatial analog
Examples
# Create RTR temporal structure
rtr <- temporal_rtr(
temporal_rw2("year"),
restrict_to = ~ temperature + precipitation
)
print(rtr)
#> tulpaRatio temporal specification
#> ============================
#>
#> Type: RW2 (Second-order Random Walk)
#> Time variable: year
#> Shared: Yes (enters both processes)
#>
#> Restricted Temporal Regression (RTR):
#> Orthogonal to: ~temperature + precipitation
#> (Temporal effect constrained to be orthogonal to covariate space)
if (FALSE) { # \dontrun{
# Generate data with temporal confounding (not run - RTR experimental)
set.seed(170)
years <- 2000:2023
n_per_year <- 4
df <- data.frame(
year = rep(years, each = n_per_year),
# Temperature increasing over time (confounded with year)
temperature = rep(seq(15, 18, length.out = length(years)), each = n_per_year) +
rnorm(length(years) * n_per_year, 0, 0.5),
count = rpois(length(years) * n_per_year, lambda = 20),
effort = rgamma(length(years) * n_per_year, shape = 4, rate = 1)
)
# Standard RW2 (may have temporal confounding)
fit1 <- tratio(
count | effort ~ temperature,
data = df,
temporal = temporal_rw2("year"),
mode = "hmc",
control = list(iter = 200, warmup = 100, chains = 1)
)
# RTR to protect temperature coefficient
fit2 <- tratio(
count | effort ~ temperature,
data = df,
temporal = temporal_rtr(
temporal_rw2("year"),
restrict_to = ~ temperature
),
mode = "hmc",
control = list(iter = 200, warmup = 100, chains = 1)
)
# Compare coefficient estimates
summary(fit1) # May be attenuated
summary(fit2) # Protected from temporal confounding
} # }