Background

Motivation

  • Climate change is intensifying extreme environmental conditions: heatwaves, cold spells are becoming more frequent and severe

  • Environmental exposures rarely act instantaneously, as their health impact unfolds over time:

    • A heatwave today may elevate mortality risk several days later

    • Cold temperatures can trigger cardiovascular events long after exposure

    • Air pollution accumulates biological damage across days or weeks

  • Standard regression approaches struggle to capture these delayed and usually non-linear effects simultaneously

Distributed Lag Non-Linear Models (DLNMs)

DLNMs (Gasparrini et al. 2010) are the standard framework for capturing these dynamics, simultaneously modelling two dimensions of risk:

  1. Exposure-response: how risk changes across exposure levels

  1. Lag-response: how risk evolves over time after exposure (lags)

  • Usually splines (natural cubic, B-splines or P-splines) are used to define these usually non-linear relationships in each dimension.

Distributed Lag Non-Linear Models (DLNMs)

  • The tensor product of the two spline bases defines the cross-basis: a smooth bivariate surface over exposure and lag
  1. Exposure-response

\(\times\)

  1. Lag-response

\(=\)

DLNMs: Model formulation

\[\log(E(Y_t)) = \alpha + \underbrace{cb(x_t, \ldots, x_{t-L}) \cdot \boldsymbol{\beta}}_{\text{cross-basis}} + \sum_{k} \gamma_k u_{kt}\]

Term Description
\(cb(\cdot)\) Cross-basis: tensor product of exposure and lag spline bases
\(\boldsymbol{\beta}\) Coefficients of the cross-basis
\(u_{kt}\) (Time-varying) confounders (e.g. seasonality, trend)
\(\gamma_k\) Coefficients of the confounders
\(\alpha\) Intercept

Bayesian DLNMs

Same model, with prior distributions placed on all parameters:

\[\log(E(Y_t)) = \alpha + \underbrace{cb(x_t, \ldots, x_{t-L}) \cdot \boldsymbol{\beta}}_{\text{cross-basis}} + \sum_{k} \gamma_k u_{kt}\]

\[\alpha, \boldsymbol{\beta}, \gamma_k \sim \text{(prior distributions)}\]

Every parameter now has its posterior distribution

This enables:

  • Full uncertainty quantification of all estimates via posterior distributions

  • Uncertainty propagation in derived measures (optimal exposure, attributable burden) without additional approximations

  • Hierarchical extensions to add layers of complexity in the model (e.g. Spatial Bayesian DLNMs, Quijal-Zamorano et al. (2024))

The {bdlnm} R package

{bdlnm}


  • The goal of {bdlnm} is to extend frequentist DLNMs to all kinds of Bayesian DLNMs (B-DLNMs)

  • Built on {dlnm}, the reference package for frequentist DLNMs (Gasparrini et al. 2011)

  • Uses R-INLA (Rue et al. 2009) for efficient Bayesian inference


Published on CRAN since March 2026:

        

Overview of the package


Purpose Function Based on
Model fitting bdlnm() New
Optimal exposure optimal_exposure() plot.optimal_exposure New
Prediction bcrosspred() dlnm::crosspred()
Visualisation plot.bcrosspred() dlnm::plot.crosspred()
Attribution attributable() attrdl() (Gasparrini and Leone 2014)

Hands-on {bdlnm}: An application

Temperature-mortality study

  • We assess the immediate and delayed non-linear effect of daily mean temperature on mortality (age 75+) in London, 2000–2011

  • We will use the {bdlnm} built-in london dataset: one observation per day, containing mortality counts, mean temperature, and calendar variables:

date year dow tmean mort_00_74 mort_75plus mort
2000-01-01 2000 Sat 7.642016 101 226 327
2000-01-02 2000 Sun 8.351041 100 191 291
2000-01-03 2000 Mon 8.188446 107 205 312
2000-01-04 2000 Tue 6.320066 97 191 288
2000-01-05 2000 Wed 6.550981 92 213 305
2000-01-06 2000 Thu 8.728774 82 213 295

(Vicedo-Cabrera et al. 2019)

Model specification

\[Y_t \sim \text{Poisson}(\mu_t), \quad \quad \log(\mu_t) = \alpha + cb(x_t, \ldots, x_{t-L}) \cdot \beta + \sum_{k} \gamma_k u_{kt}\]

Cross-basis (\(cb\))

  • Exposure-response: natural spline, knots at 10th, 75th, 90th percentiles
  • Lag-response: natural spline, 3 knots on log scale, max lag 21 days

Confounders (\(u_{kt}\))

  • Seasonality/trend: natural spline, 8 df/year
  • Day of week: factor

Building the cross-basis

  • We have to use first the {dlnm} package to build the cross-basis:
library(dlnm)
argvar <- list(
  fun = "ns",
  knots = quantile(london$tmean, c(10, 75, 90) / 100, na.rm = TRUE),
  Bound = range(london$tmean, na.rm = TRUE)
)
arglag <- list(
  fun = "ns",
  knots = logknots(21, nk = 3)
)
cb <- crossbasis(london$tmean, lag = 21, argvar, arglag)
  • And build the seasonality and temperature prediction grid:
library(splines)
seas <- ns(london$date, df = round(8 * length(london$date) / 365.25))
temp <- round(seq(min(london$tmean), max(london$tmean), by = 0.1), 1)

Fitting the Bayesian DLNM

mod <- bdlnm(
  mort_75plus ~ cb + factor(dow) + seas,
  data = london,
  family = "poisson",
  sample.arg = list(n = 1000, seed = 5243)
)

bdlnm() handles two things internally:

  1. Fits the model using R-INLA
  2. Returns posterior samples and summaries for all parameters
List of 4 (class "bdlnm")
 $ model               : list [49]      — fitted R-INLA model object
 $ basis               : list [1]       — cross-basis
 $ coefficients        : num [123, 1000] — posterior samples
 $ coefficients.summary: num [123, 6]    — posterior summary

Fitting the Bayesian DLNM

Now we have a matrix with the estimated posterior samples of the model coefficients, together with their summary across samples:

Posterior samples mod$coefficients

                 sample1      sample2      sample3      sample4      sample5
(Intercept)  5.177126982  5.078820055  5.087683979  5.240468411  5.259946480
cbv1.l1     -0.139254820 -0.154092463 -0.112435103 -0.110085718 -0.153345807
cbv1.l2     -0.007785162  0.008057831  0.001246025 -0.003957057  0.006234502
cbv1.l3     -0.057349056 -0.056023923 -0.045405679 -0.044017954 -0.055955602
cbv1.l4      0.048904544  0.057243423  0.025429828  0.028536089  0.049960368

Posterior summary mod$coefficients.summary

                    mean         sd  0.025quant     0.5quant  0.975quant
(Intercept)  5.204972340 0.10244169  5.00329053  5.205428027  5.39781786
cbv1.l1     -0.134951449 0.02148864 -0.17689662 -0.134049849 -0.09601856
cbv1.l2     -0.006084204 0.01031606 -0.02556688 -0.006093614  0.01455691
cbv1.l3     -0.049708682 0.01141099 -0.07279473 -0.049392945 -0.02789958
cbv1.l4      0.049567985 0.01806032  0.01484373  0.050353168  0.08412770

* Visualizing only the first 5 coefficients and the first 5 posterior samples

Minimum mortality temperature (MMT)

The minimum mortality temperature (MMT) is the temperature at which the overall cumulative mortality risk is minimised. It is used as the reference value to center relative risk estimates, so that all effects are interpreted relative to the temperature associated with lowest mortality

We will use the optimal_exposure() function to calculate it:

mmt <- optimal_exposure(mod, exp_at = temp)
List of 2 (class "optimal_exposure")
 $ est    : num [1:1000] — posterior samples of the MMT
 $ summary: num [1:6]    — posterior summary (mean, sd, quantiles)

MMT posterior distribution

The posterior is concentrated around 18.9°C and unimodal: the median is a stable centering value for the relative risk estimates

Predicting exposure-lag-response effects

From the fitted model, bcrosspred() computes the full bivariate exposure-lag-response association. Relative risks will be centered at the MMT:

cen <- mmt$summary[["0.5quant"]]
cpred <- bcrosspred(mod, exp_at = temp, cen = cen)
List (class "bcrosspred")
 $ coefficients        : num [20, 1000]      — posterior samples of cross-basis coefficients
 $ coefficients.summary: num [20, 6]         — posterior summary of cross-basis coefficients
 $ matRRfit            : num [326, 22, 1000] — posterior samples of RR (exposure x lag x samples)
 $ matRRfit.summary    : num [326, 22, 6]    — posterior summary of RR (exposure x lag x summaries)
 $ allRRfit            : num [326, 1000]     — posterior samples of overall RR (exposure x samples)
 $ allRRfit.summary    : num [326, 6]        — posterior summary of overall RR (exposure x summaries)

Predicting exposure-lag-response effects

Now we have an array of estimated posterior RRs for each temperature–lag combination, together with their summary across samples:

Posterior samples cpred$matRRfit

, , sample1

          lag0     lag1     lag2     lag3
-3.4 0.8489699 1.078465 1.144323 1.100592
-3.3 0.8496304 1.077665 1.143102 1.099767
-3.2 0.8502913 1.076867 1.141883 1.098942
-3.1 0.8509526 1.076069 1.140665 1.098119

*Visualizing only first 4 temperatures and lags and 1 sample

Posterior summary cpred$matRRfit.summary

, , mean

          lag0     lag1     lag2     lag3
-3.4 0.8526728 1.071554 1.134939 1.094427
-3.3 0.8533699 1.070944 1.133932 1.093743
-3.2 0.8540676 1.070335 1.132926 1.093060
-3.1 0.8547656 1.069726 1.131921 1.092377

*Visualizing only first 4 temperatures and lags and 1 summary statistic

plot.bcrosspred(): visualise predictions

plot(cpred, ptype = "3d")

plot.bcrosspred(): visualise predictions

plot(cpred, ptype = "3d")
plot(cpred, ptype = "slices", exp_at = round(quantile(london$tmean, 0.99), 1))

plot.bcrosspred(): visualise predictions

plot(cpred, ptype = "3d")
plot(cpred, ptype = "slices", lag_at = 0)

plot.bcrosspred(): visualise predictions

plot(cpred, ptype = "3d")
plot(cpred, ptype = "overall")

Attributable burden

  • The attributable() function estimates the mortality burden attributable to non-optimal temperature exposures:

    • Attributable fraction (AF): proportion of all mortality events attributable to temperature
    • Attributable number (AN): absolute number of deaths attributable to temperature
  • If we have estimated \(\beta_x\) associated with a certain exposure (centered to an optimal reference one) we can calculate the attribution to non-optimal temperature exposure as:

\[\text{AF}_{x,t} = 1 - \exp(-\beta_x) \qquad \text{AN}_{x,t} = n_t \cdot \text{AF}_{x,t}\]

  • In a DLNM setting, the overall cumulative effect \(\beta_{x,\,\text{overall}}\) can be used as \(\beta_x\) (forward perspective)

Computing attributable burden

attributable() returns daily and aggregated AF and AN using either the forward or backward perspective:

attr <- attributable(mod, london, name_date = "date", name_exposure = "tmean", name_cases = "mort_75plus", cen = cen, dir = "forw")
List of 8
 $ af             : num [4383, 1000] — posterior samples of daily AF
 $ an             : num [4383, 1000] — posterior samples of daily AN
 $ aftotal        : num [1:1000]     — posterior samples of total AF
 $ antotal        : num [1:1000]     — posterior samples of total AN
 $ af.summary     : num [4383, 6]    — posterior summary of daily AF
 $ an.summary     : num [4383, 6]    — posterior summary of daily AN
 $ aftotal.summary: num [1:6]        — posterior summary of total AF
 $ antotal.summary: num [1:6]        — posterior summary of total AN

Daily attributable fraction

Time series of daily attributable fractions (AFs), together with the temperature exposition in that given day:

Total attributable burden

Total mortality burden attributable to non-optimal temperatures in the London 75+ population across 2000–2011:

mean sd 0.025quant 0.5quant 0.975quant mode
Attributable fraction 0.174 0.018 0.139 0.175 0.207 0.176
Attributable number 68878.817 7130.981 55093.340 69199.634 82015.701 69863.303

Be cautious about the interpretation of these results as we estimate an association from an observational study, and not a causal effect

Conclusions

Conclusions

  • The {bdlnm} package provides a complete and accessible implementation of Bayesian Distributed Lag Non-Linear Models in R

  • Combining the flexibility of DLNMs with full Bayesian inference enables researchers to fit more realistic and complex models

  • The posterior distribution of all estimates allows direct uncertainty quantification of derived measures (e.g., MMT, attributable fractions, attributable numbers) without additional approximations

  • Posterior summaries are fully compatible with frequentist workflows, making adoption straightforward for practitioners familiar with {dlnm}

  • {bdlnm} constitutes a valuable tool for environmental risk research and, more generally, for any time series analysis with delayed non-linear effects

Present and future work

Coming soon:

  • Multi-location analysis: model different exposure-lag-response curves across cities or regions within a single model (e.g., SB-DLNM)

  • Parallelization: faster inference via {futurize} for large datasets

  • Compatibility beyond INLA: use MCMC algorithm (e.g. NIMBLE, Stan) for Bayesian model estimation

Further resources



bdlnm package website
📦 Full tutorials and documentation are available on the package website
pasahe.github.io/bdlnm
GitHub repository
🐛 Bug reports and contributions are welcome via the GitHub repository
github.com/pasahe/bdlnm

References

Gasparrini, A., B. Armstrong, and M. G. Kenward. 2010. “Distributed Lag Non-Linear Models.” Statistics in Medicine 29 (21): 2224–34. https://doi.org/https://doi.org/10.1002/sim.3940.
Gasparrini, Antonio, Ben Armstrong, and Fabian Scheipl. 2011. “Distributed Lag Linear and Non-Linear Models in R: The Package dlnm.” Journal of Statistical Software 43 (8): 1–20. https://doi.org/10.18637/jss.v043.i08.
Gasparrini, Antonio, and Michela Leone. 2014. “Attributable Risk from Distributed Lag Models.” BMC Medical Research Methodology 14 (April): 55. https://doi.org/10.1186/1471-2288-14-55.
Quijal-Zamorano, Marcos, Miguel A Martinez-Beneito, Joan Ballester, and Marc Marí-Dell’Olmo. 2024. “Spatial Bayesian Distributed Lag Non-Linear Models (SB-DLNM) for Small-Area Exposure-Lag-Response Epidemiological Modelling.” International Journal of Epidemiology 53 (3): dyae061. https://doi.org/10.1093/ije/dyae061.
Rue, Håvard, Sara Martino, and Nicholas Chopin. 2009. “Approximate Bayesian Inference for Latent Gaussian Models Using Integrated Nested Laplace Approximations (with Discussion).” Journal of the Royal Statistical Society B 71: 319–92.
Vicedo-Cabrera, Ana M., Francesco Sera, and Antonio Gasparrini. 2019. “A Hands-on Tutorial on a Modeling Framework for Projections of Climate Change Impacts on Health.” Epidemiology 30 (3): 321–29. https://doi.org/10.1097/ede.0000000000000982.

Thank you!


pasahe.github.io/bdlnm

Appendix

Spatial Bayesian DLNMs (SB-DLNMs)

SB-DLNMs (Quijal-Zamorano et al. 2024) adds a spatial structure to the cross-basis coefficients for reliable small-area estimation:

\[Y_{it} \sim \text{Poisson}(\mu_{it}) \qquad \log(\mu_{it}) = \alpha_i + \underbrace{cb(x_{it}, \ldots, x_{it-L}) \cdot \beta_i}_{\text{spatial cross-basis}} + \sum_{k} \gamma_k u_{kit}\]

\[\beta_i = \mu_\beta + \phi_i + \epsilon_i, \qquad \phi_i \mid \phi_{-i} \sim \mathcal{N}\!\left(\bar{\phi}_{\delta_i},\, \frac{\sigma^2_\phi}{|\delta_i|}\right)\]

Term Description
\(\beta_i\) Location-specific cross-basis coefficients
\(\mu_\beta\) Overall pooled exposure-lag-response association
\(\phi_i\) Spatially structured random effect (ICAR prior)
\(\epsilon_i \sim \mathcal{N}(0, \sigma^2_\epsilon)\) Unstructured random effect
\(\delta_i\) Set of spatial neighbours of area \(i\)

Exposure-lag-response surface

The full bivariate association can be represented as a 3-D surface over temperature and lag, giving the RR at each specific temperature-lag combination:

Overall cumulative effect