Y ~ 1 + time + time:tx + (1 + time | id): How to make time nonlinear?

Some time ago, @Solomon asked on Twitter how to make time nonlinear for y ~ 1 + time + time:tx + (1 + time | id). He proposed y ~ s(time, by = tx, k = 3) + s(time, id, k = 3, bs = "fs"), but questioned whether “this holds the intercept constant across groups”.
A short discussion (with @tjmahr, @ucfagls, @mattansb and others) led to no real solution…
So my question is: Is there a (simple) nonlinear equivalent for a linear growth model in brms?

3 Likes

Admittedly, I’m biased. But this is a great question and I’d be excited for a resolution.

My best bet would be on some combination of the new bs = "sz" and some cp = 0 or something?

brm(y ~ s(time) + s(time, tx, bs = "sz", pc = list(time = 0, tx = factor("ctrl"))),
           data = data)

This code done NOT work, but I swear I can smell it…

Code smells–someone’s been watching the great Jenny Bryan (Code smells and feels).

Thank you for this hint.
However, I understand that brms needs mgcv::gamm behind the scene to convert splines to random effects (see here). But smooth.construct.sz.smooth.spec is implemented in mgcv::gam only (not in mgcv::gamm). So currently, we can’t use bs = "sz" within brms

The question remains open…

I’m not sure this is helpful, but we have implemented non-linear inter temporal choice models in brms:

main_model = bf(choice ~ inv_logit((rewmag / (1 + exp(logk) * delay) - smag) / noise),
                  noise ~ treat + (1|subjid), 
                  logk ~ treat + (treat|subjid),
                  nl = TRUE)

# Fit the model to the data
main_fit = brm(main_model,
             data = all_trials, family = bernoulli(link='identity'),
             prior = c(prior(normal(-5,3), nlpar = 'logk'), prior(normal(1,.5),lb = 0, nlpar = 'noise')),
             inits = "0", 
             chains = 10, iter = 6000, warmup=2000, cores = 10)