Goal and Question
Hi all! Hoping you can help with a simple (?) brms
interface question.
- Goal: predict a non-decreasing proportion p in a population sampled over time.
- Example: the proportion of cars on the road that were manufactured after 1990. At 1990, p is by definition zero. After that, let’s assume some steady-state with pre-1990 cars surviving effectively forever, such that \theta = \lim_{t\to\infty} p, with \theta \lt 1.
- Assume an exponential-decay model:
- p = \text{Pr}(Y = \text{post-1990} | t) = \theta \times (1 - \text{exp}(-\lambda \, t))
- … with 1990 represented by t = 0.
- Question: how can I set a better prior on \theta, while using the non-linear functionality afforded by the
brms
package? Reprex below.
Simulation
Thanks to @jsocolar for the helpful pointer to the Estimating Non-Linear Models with brms vignette. With that, I got the code below working. It adequately recovers the simulated \theta and \lambda. But it puts a truncated \text{Normal}(0.5, 10) prior on \theta, with upper bound 1 and lower bound 0. Not ideal …
When I tried replacing:
prior(normal(0.5, 10), nlpar = "theta", lb = 0, ub = 1)
… with:
prior(beta_binomial(1, 1), nlpar = "theta")
… I got this error message:
Function 'beta_binomial_lpdf' is not implemented for distribution 'beta_binomial', use 'beta_binomial_lpmf' instead.
Is this a case of not-yet-implemented functionality in brms
? Or am I missing something obvious to y’all? Perhaps a different prior is warranted? Or not?
Code
library(tidyverse)
library(brms)
#' Helper function
rbernoulli <- function (n, prob = 0.5) {
sample(c(0L, 1L), size = n, replace = TRUE, prob = c(1 - prob, prob))
}
#' `p()` should yield zero for 1990, and approach `theta` after that
#' Let the "true" `theta` be 0.75, and the "true" `lambda` be 0.3
p <- function (since_1990, theta = 0.75, lambda = 0.3) {
return(theta * (1 - exp(-lambda * since_1990)))
}
#' Simulated data
sim_data <-
tibble(
since_1990 = 5:20, # observations start at 1995
p = p(since_1990),
Y = map(p, function (p) rbernoulli(100, p))) %>%
unnest(cols = c(Y)) %>%
glimpse()
# Exponential model for binary observations
exp_mod <-
bf(
Y ~ 0 + theta * (1 - exp(-lambda * since_1990)),
nl = TRUE,
theta + lambda ~ 1,
family = bernoulli(link = "identity"))
#'
#' Q1: What's a better prior for `theta` that spans 0, 1?
#'
priors <-
#prior(beta_binomial(1, 1), nlpar = "theta") + # this fails
prior(normal(0.5, 10), nlpar = "theta", lb = 0, ub = 1) +
prior(exponential(3), nlpar = "lambda", lb = 0)
fit <- brm(
formula = exp_mod,
prior = priors,
data = sim_data)
#' `theta` and `lambda` are acceptably recovered
summary(fit)