Skip to contents

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.

Usage

temporal_rtr(temporal, restrict_to)

# S3 method for class 'ratiod_rtr'
print(x, ...)

Arguments

temporal

A temporal specification (temporal_rw1, temporal_gp, etc.)

restrict_to

Formula specifying which covariates to orthogonalize against (e.g., ~ year_effect + trend). The temporal effect will be constrained to be orthogonal to the column space of these covariates.

x

A ratiod_rtr object

...

Passed to underlying print method

Value

A modified temporal specification with RTR enabled

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

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)

# \donttest{
# Generate data with temporal confounding
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,
  family = ratiod_poisson_gamma(),
  temporal = temporal_rw2("year"),
  mode = "hmc",
  control = list(iter = 400, chains = 1, seed = 1)
)

# RTR to protect temperature coefficient
fit2 <- tratio(
  count | effort ~ temperature,
  data = df,
  family = ratiod_poisson_gamma(),
  temporal = temporal_rtr(
    temporal_rw2("year"),
    restrict_to = ~ temperature
  ),
  mode = "hmc",
  control = list(iter = 400, chains = 1, seed = 1)
)

# Compare coefficient estimates
summary(fit1)  # May be attenuated
#> ratio model summary
#> ===================
#> 
#> Inference: Exact (Tier 1) via hmc
#> Family: poisson_gamma 
#> 
#> Fixed effects (numerator):
#>        parameter  mean    sd   2.5% 97.5%  rhat ess_bulk
#>  num:(Intercept) 1.720 0.809 -0.152 3.046 1.098       14
#>  num:temperature 0.079 0.049 -0.003 0.193 1.086       14
#> 
#> Fixed effects (denominator):
#>          parameter  mean    sd   2.5% 97.5%  rhat ess_bulk
#>  denom:(Intercept) 0.450 1.354 -1.909 2.558 1.026       29
#>  denom:temperature 0.054 0.082 -0.071 0.196 1.023       30
#> 
#> Variance components:
#>     parameter    mean      sd   2.5%   97.5%  rhat ess_bulk
#>         shape   3.229   0.521  2.366   4.297 1.000       69
#>  tau_temporal 315.842 166.225 77.682 715.092 1.029       42
#> 
#> Other parameters:
#>     parameter   mean    sd   2.5%  97.5%  rhat ess_bulk
#>  temporal[10]  0.002 0.056 -0.110  0.119 0.999       33
#>  temporal[11] -0.013 0.050 -0.104  0.083 1.013       29
#>  temporal[12] -0.014 0.053 -0.113  0.083 1.038       38
#>  temporal[13] -0.006 0.053 -0.096  0.100 1.049       40
#>  temporal[14]  0.007 0.061 -0.116  0.130 1.006       52
#>  temporal[15]  0.006 0.064 -0.118  0.136 1.010       63
#>  temporal[16] -0.014 0.062 -0.124  0.095 1.022       56
#>  temporal[17] -0.038 0.055 -0.149  0.064 1.097       12
#>  temporal[18] -0.052 0.052 -0.143  0.037 1.074       16
#>  temporal[19] -0.055 0.059 -0.177  0.052 1.031       21
#>   temporal[1]  0.161 0.111 -0.020  0.345 1.015       27
#>  temporal[20] -0.047 0.077 -0.188  0.127 1.028       26
#>  temporal[21] -0.044 0.083 -0.201  0.106 1.017       21
#>  temporal[22] -0.101 0.084 -0.283  0.048 1.045       16
#>  temporal[23] -0.172 0.093 -0.381 -0.004 1.099       12
#>  temporal[24] -0.231 0.123 -0.492 -0.005 1.065       13
#>   temporal[2]  0.168 0.077  0.050  0.338 0.995       20
#>   temporal[3]  0.156 0.069  0.055  0.295 1.002       24
#>   temporal[4]  0.141 0.070  0.023  0.287 1.019       22
#>   temporal[5]  0.091 0.068 -0.035  0.221 1.009       30
#>   temporal[6]  0.037 0.060 -0.081  0.148 1.003       36
#>   temporal[7]  0.004 0.056 -0.106  0.116 1.042       30
#>   temporal[8]  0.008 0.059 -0.082  0.139 1.043       21
#>   temporal[9]  0.005 0.055 -0.093  0.105 1.017       33
#> 
#> Diagnostics:
#>   Divergences: 0 
#>   Avg. acceptance: 0.926 
#>   Chains: 1 
#>   Iterations: 400 
#>   Warmup: 200 
#>   R-hat > 1.01 for 23 parameter(s), largest 1.099 (temporal[23]).
#>   Bulk ESS < 100 for 30 parameter(s), smallest 12 (temporal[17]).
#>   Run longer chains or reparameterise before using these estimates.
summary(fit2)  # Protected from temporal confounding
#> ratio model summary
#> ===================
#> 
#> Inference: Exact (Tier 1) via hmc
#> Family: poisson_gamma 
#> 
#> Fixed effects (numerator):
#>        parameter  mean    sd   2.5% 97.5%  rhat ess_bulk
#>  num:(Intercept) 1.720 0.809 -0.152 3.046 1.098       14
#>  num:temperature 0.079 0.049 -0.003 0.193 1.086       14
#> 
#> Fixed effects (denominator):
#>          parameter  mean    sd   2.5% 97.5%  rhat ess_bulk
#>  denom:(Intercept) 0.450 1.354 -1.909 2.558 1.026       29
#>  denom:temperature 0.054 0.082 -0.071 0.196 1.023       30
#> 
#> Variance components:
#>     parameter    mean      sd   2.5%   97.5%  rhat ess_bulk
#>         shape   3.229   0.521  2.366   4.297 1.000       69
#>  tau_temporal 315.842 166.225 77.682 715.092 1.029       42
#> 
#> Other parameters:
#>     parameter   mean    sd   2.5%  97.5%  rhat ess_bulk
#>  temporal[10]  0.002 0.056 -0.110  0.119 0.999       33
#>  temporal[11] -0.013 0.050 -0.104  0.083 1.013       29
#>  temporal[12] -0.014 0.053 -0.113  0.083 1.038       38
#>  temporal[13] -0.006 0.053 -0.096  0.100 1.049       40
#>  temporal[14]  0.007 0.061 -0.116  0.130 1.006       52
#>  temporal[15]  0.006 0.064 -0.118  0.136 1.010       63
#>  temporal[16] -0.014 0.062 -0.124  0.095 1.022       56
#>  temporal[17] -0.038 0.055 -0.149  0.064 1.097       12
#>  temporal[18] -0.052 0.052 -0.143  0.037 1.074       16
#>  temporal[19] -0.055 0.059 -0.177  0.052 1.031       21
#>   temporal[1]  0.161 0.111 -0.020  0.345 1.015       27
#>  temporal[20] -0.047 0.077 -0.188  0.127 1.028       26
#>  temporal[21] -0.044 0.083 -0.201  0.106 1.017       21
#>  temporal[22] -0.101 0.084 -0.283  0.048 1.045       16
#>  temporal[23] -0.172 0.093 -0.381 -0.004 1.099       12
#>  temporal[24] -0.231 0.123 -0.492 -0.005 1.065       13
#>   temporal[2]  0.168 0.077  0.050  0.338 0.995       20
#>   temporal[3]  0.156 0.069  0.055  0.295 1.002       24
#>   temporal[4]  0.141 0.070  0.023  0.287 1.019       22
#>   temporal[5]  0.091 0.068 -0.035  0.221 1.009       30
#>   temporal[6]  0.037 0.060 -0.081  0.148 1.003       36
#>   temporal[7]  0.004 0.056 -0.106  0.116 1.042       30
#>   temporal[8]  0.008 0.059 -0.082  0.139 1.043       21
#>   temporal[9]  0.005 0.055 -0.093  0.105 1.017       33
#> 
#> Diagnostics:
#>   Divergences: 0 
#>   Avg. acceptance: 0.926 
#>   Chains: 1 
#>   Iterations: 400 
#>   Warmup: 200 
#>   R-hat > 1.01 for 23 parameter(s), largest 1.099 (temporal[23]).
#>   Bulk ESS < 100 for 30 parameter(s), smallest 12 (temporal[17]).
#>   Run longer chains or reparameterise before using these estimates.
# }