Skip to contents

The links frmtmb accepts, what each one maps, and where each one may be used. Every family constructor takes a link argument for the mean and a link_<dpar> argument for each of its other distributional parameters, so student(link_sigma = "softplus") puts sigma on a softplus. The roster follows brms 2.23.0: a model ported from brms is fitted through the same inverse link.

Value

A link is not a free-standing function. It is named to a family constructor, which resolves it against the registry and carries it on the fitted model, so the value a link contributes is the scale each distributional parameter is estimated on. Read it back with $link and $link_<dpar> on the family, and read a custom link's own fields with the list that was supplied. This page documents the roster.

Details

A link is defined here over plain arithmetic that RTMB overloads, not through stats::make.link(), because make.link() clamps at C level in ways the automatic differentiation tape cannot see.

The roster

g is the link and g^-1 its inverse. The inverse is the one that does the work: it maps a linear predictor to the parameter, so its RANGE is the parameter support the link fits. eta is the linear predictor and mu the parameter.

Linkg(mu)g^-1(eta)RangeRobust field
identitymuetathe real line
loglog(mu)exp(eta)positivelog_eta
softpluslog(expm1(mu))log1p(exp(eta))positivelog_eta
squareplus(mu^2 - 1) / mu(eta + sqrt(eta^2 + 4)) / 2positivelog_eta
inverse1 / mu1 / etapositive
1/mu^21 / mu^21 / sqrt(eta)positive
sqrtsqrt(mu)eta^2non-negativelog_eta
logitlog(mu / (1 - mu))1 / (1 + exp(-eta))the unit intervallogit_eta
probitqnorm(mu)pnorm(eta)the unit intervallogit_eta
probit_approxqnorm(mu)plogis(0.07056 eta^3 + 1.5976 eta)the unit intervallogit_eta
clogloglog(-log(1 - mu))1 - exp(-exp(eta))the unit intervallogit_eta
cauchittan(pi (mu - 0.5))0.5 + atan(eta) / pithe unit interval
softitlog(expm1(mu / (1 - mu)))s / (1 + s) for s = log1p(exp(eta))the unit intervallogit_eta
logm1log(mu - 1)1 + exp(eta)above one
log1plog1p(mu)expm1(eta)above minus one
power12log((mu - 1) / (2 - mu))1 + 1 / (1 + exp(-eta))between one and two
tan_halftan(mu / 2)2 atan(eta)the circle

probit_approx is the one pair that is not an exact inverse, in frmtmb and in brms alike. brms generates Stan code that uses Phi_approx(), the logistic of a cubic, while its own R-side inv_link() answers pnorm(). The Stan form is the one a ported model was fitted with, so it is the form used here.

sqrt is not injective on the whole line. brms allows it for a count mean anyway, and so does frmtmb.

Each family constructor takes, for mu, the links brms 2.23.0 takes for that family, and refuses the rest by name with the set it allows: bernoulli("sqrt") is an error, as in brms, because a probability on eta^2 is not bounded by one. The sets are read out of brms by a script rather than copied by hand. The first link listed is the default.

The link may be written unquoted, as in student(identity) or negbinomial(sqrt), as stats::family() and brms allow. Only the link for the mean can be; a link_<dpar> argument is a string.

A custom link object (see Custom links) is not held to the table: brms has no such object, and a user who writes one has said what range the mean has. frmtmb_family() checks no set at all, because an extension family is free to mean something else by its own mu.

nbinom1, tweedie and huber have no brms family. They take the set of the nearest brms family: negbinomial, Gamma and gaussian, in that order.

FamilyLinks for mu
gaussian, student, skew_normalidentity, log, inverse, softplus, squareplus, and every unit-interval link
lognormal, shifted_lognormal, hurdle_lognormalidentity, inverse
Gamma, weibull, exponential, hurdle_gammalog, identity, inverse, softplus, squareplus
asym_laplace, exgaussian, zero_inflated_asym_laplaceidentity, log, inverse, softplus, squareplus
poisson, negbinomial, negbinomial2 (through brmsfamily()), geometric, compois, and the zero-inflated and hurdle countslog, identity, sqrt, softplus, squareplus
binomial, bernoulli, Beta, xbeta, zero_inflated_binomial, zero_inflated_beta, zero_inflated_beta_binomial, zero_one_inflated_betalogit, probit, probit_approx, cloglog, cauchit, softit, identity, log
beta_binomialthe same list WITHOUT log: brms's own table for this one family stops at identity
inverse.gaussian1/mu^2, inverse, identity, log, softplus, squareplus
von_misestan_half, identity
cumulative, hurdle_cumulative, acatlogit, probit, probit_approx, cloglog, cauchit, softit
sratio, cratiologit, probit, probit_approx, cloglog, cauchit
categorical, multinomial, dirichlet_multinomial, dirichletlogit
logistic_normalidentity
dirichlet2, through brmsfamily()log, softplus, squareplus, identity, logm1
frechetlog, identity, inverse, softplus, squareplus
gen_extreme_valueidentity, log, inverse, softplus, squareplus
discrete_weibulllogit, probit, probit_approx, cloglog, cauchit, softit, identity

An ordinal family's link names the cumulative distribution function the thresholds are read through, not a link on a mean, so only a link whose inverse maps onto the unit interval can serve.

acat() reads its link in two forms, as brms does (brms:::inv_link_acat()). On the logit a category probability is c(1, cumprod(exp(x))) normalized, the log-linear form. Off the logit it is a product of distribution functions times a reversed product of survivals, normalized. The second form agrees with the first when the distribution function is logistic, so it generalizes the same model rather than replacing it.

link_<dpar> takes the values brms allows for that parameter, and the set is fixed by what the parameter must stay inside. The first link listed is the default.

ParameterArgumentLinks
sigma, shape, phi, kappa, beta, ndt, disc, and the nu of compoislink_sigma and so onlog, identity, softplus, squareplus
nu of student and frechetlink_nulogm1, identity
zi, hu, zoi, coi, quantilelink_zi, link_hu, link_zoi, link_coi, link_quantilelogit, identity
alpha of skew_normallink_alphaidentity, log, softplus, squareplus
xi of gen_extreme_valuelink_xilog1p, identity

identity is in every one of those sets because brms puts it there. It lets a parameter that must stay positive go negative, which the density then reports as a NaN rather than as a bad link. It is offered so that a brms model ports, not because it is a good choice.

The power of tweedie() takes no argument. It is confined to the open interval from one to two, power12 is the only link in the roster that maps onto it, and brms has no tweedie to port from.

A prior class is a distributional parameter name, so changing a parameter's link changes where its prior sits. set_prior(class = "sigma") is a density on sigma itself, and the placement frm() gives it is read from sigma's link, so changing link_sigma changes the Jacobian that prior carries. See set_prior().

What a robust field buys

An inverse link SATURATES. plogis(40) is exactly one in double precision, and so is 1 - exp(-exp(4)). A density written over 1 - mu then reads log(0), which is -Inf with an unusable gradient, where the true log density is an ordinary -40. The linear predictor never saturated, so a link that carries a robust field recovers the quantity the density actually needs from the linear predictor directly: logit_eta gives the log odds and log_eta the log mean.

The field is present only where the plain round trip measurably saturates AND an exact form exists. cauchit has neither the problem nor a cure: its tails are polynomial, so the plain round trip keeps eight digits out to a linear predictor of 3.2e9. inverse and 1/mu^2 cannot overflow or underflow at any representable positive linear predictor.

Nothing has to be done to use this. A family whose link carries the field is put on the robust form of its density automatically: binomial() on dbinom_robust(), negbinomial() on dnbinom_robust().

Wherever a link is taken, a list is taken instead of a name. It must carry name, linkfun, linkinv and mu_eta, the derivative of linkinv, which frm_linpred(se.fit = TRUE) and every delta-method interval read. logit_eta and log_eta are optional; supply one only if it is exact.

See also

frmtmb-families for the constructors that take these, set_prior() for what a link does to a prior.

Examples

set.seed(1)
d <- data.frame(x = rnorm(80))
d$y <- rbinom(80, 1, pnorm(0.4 + 0.8 * d$x))

# the mean on a probit rather than a logit
fixef_by_dpar(frm(bf(y ~ x), family = bernoulli(link = "probit"),
                  data = d))$mu
#> (Intercept)           x 
#>   0.2330309   1.0758635 

# a link on a parameter that is not the mean
d$z <- rnorm(80, 1 + d$x, exp(0.2 + 0.3 * d$x))
frm(bf(z ~ x, sigma ~ x), family = student(link_sigma = "log"), data = d)
#>  Family: student 
#>  Links: mu = identity; sigma = log; nu = logm1
#> 
#> Formula: z ~ x 
#>    Data: d (Number of observations: 80) 
#>  Method: ML   logLik: -129.955   AIC: 269.909   BIC: 281.82 
#> 
#> Regression Coefficients:
#>                 Estimate Est.Error l-95% CI u-95% CI z value Pr(>|z|)
#> Intercept           0.88      0.14     0.62     1.15    6.46  1.0e-10
#> sigma_Intercept     0.19      0.08     0.03     0.34    2.35    0.019
#> x                   0.83      0.16     0.51     1.15    5.08  3.9e-07
#> sigma_x             0.17      0.10    -0.02     0.36    1.74    0.082
#> 
#> Further Distributional Parameters:
#>     Estimate    Est.Error l-95% CI u-95% CI
#> nu 417352048 3.624559e+12        1      Inf