Skip to contents

The goal of hmde is to fit a model for the rate of change in some quantity based on a set of pre-defined functions arising from ecological applications. We estimate differential equation parameters from repeated observations of a process, such as growth rate parameters to data of sizes over time. In other language, hmde implements hierarchical Bayesian longitudinal models to solve the Bayesian inverse problem of estimating differential equation parameters based on repeat measurement surveys. Estimation is done using Markov Chain Monte Carlo, implemented through Stan via RStan, built under R 4.3.3. The inbuilt models are based on case studies in ecology.

A pre-print paper is available on bioarXiv, or as the hmde_paper.pdf file here.

The Maths

The general use case is to estimate a vector of parameters θ\theta for a chosen differential equation f(Y(t),θ)=dYdtf\left( Y \left( t \right), \theta \right) = \frac{dY}{dt} based on the longitudinal structure Y(tj+1)=Y(tj)+tjtj+1f(Y(t),θ)dt.Y \left( t_{j+1} \right) = Y\left( t_j \right) + \int_{t_j}^{t_{j+1}}f\left( Y \left( t \right), \theta \right)\,dt.

The input data are observations of the form yijy_{ij} for individual ii at time tjt_j, with repeated observations coming from the same individual. We parameterise ff at the individual level by estimating θi\theta_i as the vector of parameters. We have hyper-parameters that determine the distribution of θi\theta_i with typical prior distribution θilog𝒩(μlog(θ),σlog(θ)),\theta_i \sim \log \mathcal{N}\left(\mu_{\log\left(\theta\right)}, \sigma_{\log \left( \theta \right)}\right), where μlog(θ)\mu_{\log\left(\theta\right)} and σlog(θ)\sigma_{\log\left(\theta\right)} are vectors of means and standard deviations. In the case of a single individual, these are chosen prior values. In the case of a multi-individual model μlog(θ)\mu_{\log\left(\theta\right)} and σlog(θ)\sigma_{\log\left(\theta\right)} have their own prior distributions and are fit to data.

Implemented Models

hmde comes with four DEs built and ready to go, each of which has a version for a single individual and multiple individuals.

Constant Model

The constant model is given by f(Y(t),β)=dYdt=β,f \left( Y \left( t \right), \beta \right) = \frac{dY}{dt} = \beta, and is best understood as describing the average rate of change over time.

von Bertalanffy

The von Bertalanffy mode is given by f(Y(t),β,Ymax)=dYdt=β(YmaxY(t)),f \left( Y \left( t \right), \beta, Y_{max} \right) = \frac{dY}{dt} = \beta \left( Y_{max} - Y \left( t \right) \right), where β\beta is the growth rate parameter and YmaxY_{max} is the maximum value that YY takes.

Canham

The Canham (Canham et al. 2004) model is a hump-shaped function given by f(Y(t),fmax,Ymax,k)=dYdt=fmaxexp(12(ln(Y(t)/Ymax)k)2),f \left( Y \left( t \right), f_{max}, Y_{max}, k \right) = \frac{dY}{dt} = f_{max} \exp \Bigg( -\frac{1}{2} \bigg( \frac{ \ln \left( Y \left( t \right) / Y_{max} \right) }{k} \bigg)^2 \Bigg), where fmaxf_{max} is the maximum growth rate, YmaxY_{max} is the YY-value at which that maximum occurs, and kk controls how narrow or wide the peak is.

Installation

‘hmde’ is under active development. You can install the current developmental version of ‘hmde’ from GitHub with:

# install.packages("remotes")
remotes::install_github("traitecoevo/hmde")

Quick demo

Create constant growth data with measurement error:

library(hmde)
y_obs <- seq(from=2, to=15, length.out=10) + rnorm(10, 0, 0.1)

Measurement error is necessary as otherwise the normal likelihood sij𝒩(0,σe)s_{ij} \sim \mathcal{N}\left( 0, \sigma_e \right) blows up as σe\sigma_e approaches 0.

Fit the model:

constant_fit <- hmde_model("constant_single_ind") |>
        hmde_assign_data(n_obs = 10,                  #Integer
                         y_obs = y_obs,               #vector length n_obs
                         obs_index = 1:10,            #vector length n_obs
                         time = 0:9,                  #Vector length n_obs
                         y_0_obs = y_obs[1]           #Real
        ) |>
        hmde_run(chains = 1, iter = 1000, verbose = FALSE, show_messages = FALSE)

Found a bug?

Please submit a GitHub issue with details of the bug. A reprex would be particularly helpful with the bug-proofing process!