# Non-linear specification (variable is not a valid distributional or non-linear parameter)

I am trying to use non-linear syntax to estimate several parameters in a model with brms where I am treating the outcome as a Beta proportion and trying to infer several other parameters.

The general specification is:

\begin{align*} S_{r,t} & \sim Beta(\mu, \kappa) \\ \mu & = I \\ I_{p,d} & = 1 + B_{p,d} \\ B_{p,d} & = a * R^b + c \\ \end{align*}

S_{r,t}, C, and R are observed, so I want to estimate I, B, a, b, and c

I first tried

bform <- bf(
Srt ~ I,
I ~ 1 + (C * B )+ (1|r) + (1|t),
B ~ 1 + (a * R^b + c),
a ~ 1,
b ~ 1,
c ~ 1,
nl = TRUE
)

But, that gives me a power error:
Error in terms.formula(as.formula(x)) : invalid power in formula

I assumed this was do to how R is interpreting the ^

So I eliminated b and assumed a 2

bform <- bf(
seroprev ~ I,
I ~ 1 + (C * B + (1|r) + (1|t),
B ~ 1 + (a * R^2 + c),
a ~ 1,
c ~ 1,
nl = TRUE
)

This gives a different error:
Error: The parameter 'B' is not a valid distributional or non-linear parameter. Did you forget to set 'nl = TRUE'?

I have set nl = TRUE.

Is it possible to estimate multiple parameters this way? Or should I be â€śinjectingâ€ť these parameters into the transformed parameters block somehow?

When you eliminate the b and assume a 2, the model is no longer non-linear (R is observed, so R^2 is a constant).

You may well be right that the original problem has to do with how R interprets ^ in a model formula (i.e. as a degree of interaction). However,^ works in the example A real-world non-linear model in the relevant brms vignette here:
https://cran.r-project.org/web/packages/brms/vignettes/brms_nonlinear.html

If you could post a reproducible example of the original failure that yields Error in terms.formula(as.formula(x)) : invalid power in formula (running the call to bf from your post doesnâ€™t reproduce the error for me) then I might be able to help. But Iâ€™ll also go ahead and pass you up the food chain by paging @paul.buerkner.

Thank you very much!

Hereâ€™s is an (unprincipled) reprex:

# load packaged
library(dplyr)
library(brms)

# Some fake data
Data <- expand.grid(r = factor(c(1:5)),
t = factor(c(1:8))
) %>%
mutate(C = round(rnorm(nrow(.),500, 150)),
D = round(rnorm(nrow(.),10000, 1000)),
R = C/D,
Srt = rnorm(nrow(.),0.5, 0.15))

# Non-linear formula
bform <- bf(
Srt ~ I,
I ~ 1 + (C * B) + (1|r) + (1|t),
B ~ 1 + (a * R(...^b) + c),
a ~ 1,
b ~ 1,
c ~ 1,
nl = TRUE
)

# Get available priors
get_prior(bform,
data = Data,
family = Beta())

This gives the following error:
Error: The parameter 'B' is not a valid distributional or non-linear parameter. Did you forget to set 'nl = TRUE'?

I see 2 problems:

(a) you canâ€™t mix linear and non-linear formula syntax, that is I ~ B + (1 | r) for example is invalid if B is supposed to be a non-linear parameter.

(b) non-linear formula except for the main one need to be wrapped in nlf() to work. that is for example nlf(B ~ b^2)

Thank you, @paul.buerkner !

Where is the correct place to enter grouping variables for the non-linear parameters? In this case I want to group I, C, and B by r and t and leave a, b, and c independent of r and t.

I tried:

bform <- bf(
Srt ~ I + (1|r) + (1|t),
nlf(I ~ C * B),
nlf(B ~ a * R^b + c),
nlf(a ~ 1),
nlf(b ~ 1),
nlf(c ~ 1),
nl = TRUE
)

get_prior(bform,
data = Data,
family = Beta())

But this gives me:
Error in vector("list", nrow(re)) : invalid 'length' argument

group level terms need to be entered in linear formulas only.

and you need to distinguish between a non-linear parameter (e.g. c) and a non-linear formula. for example you donâ€™t need nlf() around c ~ 1 because the formula itself is linear.

Thank you very much, @paul.buerkner !

This seems to be approaching the correct syntax (at least no immediate errors):

bform <- bf(
Srt ~ I + (1|r) + (1|t),
nlf(I ~ C * B),
nlf(B ~ a * R^b + c),
a ~ 1,
b ~ 1,
c ~ 1,
nl = TRUE
)

get_prior(bform,
data = Data,
family = Beta())

Is it possible to set priors on group-level effects in non-linear models?

Make some fake data:

Data <- expand.grid(r = factor(c(1:5)),
t = factor(c(1:8))
) %>%
mutate(C = round(rnorm(nrow(.),500, 150)),
D = round(rnorm(nrow(.),10000, 1000)),
R = C/D,
Srt = rnorm(nrow(.),0.5, 0.15))

Model formula:

bform <- bf(
Srt ~ I,
I ~ (1|r) + (1|t),
nlf(I ~ C * B),
nlf(B ~ a * R^b + c),
a ~ 1,
b ~ 1,
c ~ 1,
nl = TRUE
)

Get available priors:

prior_list <- get_prior(bform,
data = Data,
family = Beta())

Set priors on nlpars:

nl_priors <- c(
set_prior("normal(0, 10)",
class = "b",
nlpar = "a"),
set_prior("normal(0, 10)",
class = "b",
nlpar = "b"),
set_prior("normal(0, 10)",
class = "b",
nlpar = "c")
)

Compile and run model:

NL_Mod <- brm(bform,
Data,
family = Beta(),
prior = nl_priors,
inits = "random",
iter = 2000,
warmup = 1000,
chains = 4,
cores = ncores,
backend = "cmdstan",
normalize = FALSE,
save_pars = save_pars(all = TRUE),
control = list(adapt_delta = 0.9,
max_treedepth = 12)
)

Am I still mis-specifying in some way?

@paul.buerkner , I have the model running now, at least with the fake data.

However, I only get estimates for population level-parameters (a, b, and c) and I is a primary estimate of interest. How might I specify the model to return the estimates of I?

You can use posterior_epred(..., nlpar = "I")

1 Like