The frequentist analog of brms's hypothesis(): evaluates
expressions of the model parameters at the estimates and tests them
against zero. A hypothesis is "lhs = rhs", e.g. "x1 - x2 = 0" or
"exp(Intercept) = 1", or brms's directional "lhs > rhs" /
"lhs < rhs". Every hypothesis states a relation: a string with no
=, < or > is refused, as it is in brms, so write "x1 = 0"
rather than "x1".
Usage
hypothesis(x, ...)
# S3 method for class 'frmtmb_fit'
hypothesis(
x,
hypothesis,
class = "b",
group = "",
scope = c("standard", "ranef", "coef"),
alpha = 0.05,
robust = FALSE,
seed = NULL,
method = c("wald", "profile", "boot"),
nsim = 500,
vcov = NULL,
...
)
# S3 method for class 'frmtmb_multiple'
hypothesis(
x,
hypothesis,
class = "b",
group = "",
scope = c("standard", "ranef", "coef"),
alpha = 0.05,
robust = FALSE,
seed = NULL,
...
)Arguments
- x
A
frmtmb_fit, or afrmtmb_multiplefor pooled tests.- ...
Backend controls: passed to
TMB::tmbprofile()formethod = "profile"(e.g.ytol,ystep,maxit,parm.range) and tofrm_bootstrap()formethod = "boot"(e.g.re_formula = NULLfor a conditional bootstrap). Refused for"wald".- hypothesis
Character vector of hypotheses. Names on it become the
Hypothesislabels, as in brms.- class, group
brms's name prefix; see brms class and group shorthand. The default
class = "b"is brms's.- scope
brms's
"standard"is the only scope a fit supports:"ranef"and"coef"evaluate the hypothesis on each group level's draws, which a maximum-likelihood fit does not have, and are refused by name.- alpha
Test level; the reported interval covers
1 - alphafor a two-sided row and1 - 2 * alphafor a directional one, as in brms.- robust
brms's median-and-MAD switch. It summarizes draws and a fit has none, so
TRUEis refused by name.- seed
Optional seed for
method = "boot".- method
"wald","profile", or"boot".- nsim
Bootstrap draws for
method = "boot"; all hypotheses share one bootstrap run.- vcov
method = "wald"only: a covariance matrix over the whole outer parameter vector to use in place of the model-based one -vcov_cluster()withfull = TRUE, or a function of the fit returning such a matrix. The delta-method standard error is then the cluster-robust one, and a matrix carrying reference degrees of freedom switches the test to atreference.
Value
A frmtmb_hypothesis list in brms's shape; see
The returned object.
plot() shows the bootstrap distribution, the profile curve, or
the implied Wald normal density, one panel per hypothesis.
The returned object
brms's SHAPE under frmtmb's own class: a list of class
"frmtmb_hypothesis" with the elements brms has, in brms's order.
It does not carry brms's brmshypothesis class. frmtmb owns
print() and plot() for its own class and a frmtmb fit is not a
brms fit, so is(x, "brmshypothesis") in a ported script is a
rule-2 divergence like the other seventeen the port ledger records.
hypothesis: a data frame with brms's eight columns, one row per hypothesis. On a maximum-likelihood fit they mean:Hypothesis: brms's label,(lhs)-(rhs) > 0, or the name given on the hypothesis vector.Estimate: the expression at the estimates.Est.Error: its delta-method standard error ("wald","profile"), the bootstrap standard deviation ("boot"), or the Rubin pooled standard error (afrm_multiple()result).CI.Lower,CI.Upper: brms's interval, which is central at1 - alphafor"="and central at1 - 2 * alphafor a directional row, so that its relevant end is the one-sided bound. Wald, profile-likelihood or bootstrap percentile, permethod.Evid.Ratio,Post.Prob:NA. They are posterior quantities, and a fit has no posterior.Star:"*"when a two-sided row's interval excludes 0, or when a directional row's one-sided test rejects at levelalpha(brms stars a posterior probability above1 - alphathere).
samples: brms's frame of draws, columnsH1,H2, ...: the bootstrap replicates for"boot", and no rows otherwise.prior_samples: the same columns, allNA.class: the name prefixclassandgroupproduced, without its trailing underscores, as brms stores it.alpha.
What brms's frame has no column for rides on attributes, so the
frame keeps brms's shape: attr(h, "test") is the test statistic
and its p-value per row (z, or t with df for a pooled or
degrees-of-freedom-carrying covariance), attr(h, "method"), and the
method payload, attr(h, "draws") for the bootstrap matrix and
attr(h, "profiles") for the profile curves.
Directional hypotheses
"lhs > rhs" and "lhs < rhs" test the same difference
(lhs) - (rhs) against zero with a one-sided alternative, so the
reported p is the one-sided tail probability. p is pnorm() of
the signed z statistic for "wald" and, as in the two-sided case
where the standard error and the statistic stay Wald-based, for
"profile" too: the profile changes the INTERVAL and nothing else.
For "boot" p is the tail proportion of the replicates with the
(1 + k) / (1 + n) correction. Where brms reports the posterior
probability of the direction, this reports its frequentist
complement: small p is evidence for the stated direction.
">=" and "<=" read as ">" and "<".
brms class and group shorthand
The hypothesis is read as brms:::eval_hypothesis() reads it. Every
variable in the text gets the prefix class and group make, and a
prefixed name the model does not have is refused with brms's message,
"Some parameters cannot be found in the model". brms's default
class = "b" reads "x1 - x2 = 0" as b_x1 - b_x2, so it refuses
"b_x1 = 0", which it reads as b_b_x1. class = "sd", group = "patient" reads "Intercept - age > 0" as sd_patient__Intercept - sd_patient__age. class = NULL (or "") takes every name as
written, which is what sigma or sd_g__Intercept needs, as in
brms.
A name may carry what brms's names carry: x:fe is the interaction
coefficient b_x:fe, not R's : operator, and ar[1] is the
autocorrelation. brms's renaming (: to ___, [ and ] to .,
, to ..) is applied to the text before it is parsed, as in brms.
Available names, which variables() lists, are brms's: the
coefficients (b_Intercept, b_x, b_IxE2 for I(x^2),
b_sigma_Intercept for a sigma formula, bs_sx_1 for the
unpenalized part of s(x)); a distributional parameter nobody wrote
a formula for, on its natural scale (sigma, shape, nu, and
sigma_ya for response y_a of a multivariate model); the
group-level summaries sd_<group>__<coef> and
cor_<group>__<coef1>__<coef2>, where the coefficient of a
distributional or nonlinear parameter carries that parameter's name
(sd_g__sigma_Intercept); the autocorrelation parameters (ar[1],
cosy); and the residual correlations rescor__<resp1>__<resp2>.
So an ICC is
hypothesis(fit, "sd_g__Intercept^2 / (sd_g__Intercept^2 + sigma^2) = 0", class = NULL). The traffic runs the other way too: confint(parm = )
and profile(parm = ) take these names, whenever one of them stands
for a single internal parameter.
Which random-effect blocks contribute names
Every block whose covariance parameters ARE standard deviations and
correlations: the plain structures (us, diag, homdiag, cs,
ar1, toep, the spatial and reduced-rank ones) and the
known-structure blocks gr(cov = ), gr(prec = ) and equalto(),
whose sd_/cor_ names describe the WITHIN-level covariance that
multiplies the fixed relationship matrix. That is what makes
heritability-as-ICC writable directly:
"sd_id__Intercept^2 / (sd_id__Intercept^2 + sigma^2) = 0" with
class = NULL on an animal model fitted with
(1 | gr(id, cov = A)). An equalto() block estimates nothing, so
its names are constants with zero variance.
An |ID|-merged block is ONE block, so it contributes one name per
merged coefficient, and the names carry the predictor they came from
in brms's spelling. A two-trait animal model written
(1 | q | gr(id, cov = A)) in both formulas of an mvbf() gives
sd_id__y1_Intercept, sd_id__y2_Intercept and
cor_id__y1_Intercept__y2_Intercept, the last being the genetic
correlation between the traits. variables() prints them.
Two terms that give one grouping factor the same coefficient, an
animal model's (1 | gr(id, cov = A)) + (1 | id), are refused when
the model is built, with brms's message "Duplicated group-level
effects are not allowed". Give the second term a copy of the factor
under another name, (1 | gr(id, cov = A)) + (1 | id_pe), and the
two are sd_id__Intercept and sd_id_pe__Intercept.
Excluded: s()/t2() smooths, car() and spde(). Their theta
segments are not standard deviations: an inverse smoothing
parameter, a mixing proportion, a precision and an inverse range.
There is no sd_<group>__<coef> to name. Read those off
confint_varcorr(), which reports each under its own label
(sd(car), ...).
A gp() term contributes brms's own names: sdgp_<term> for its
marginal standard deviation and lscale_<term> for its length scale,
on brms's scales, so the length scale is on the inputs gp(scale = TRUE) divides by their largest distance. The term is brms's label,
gpx for gp(x), with a response or distributional parameter
prefix as for every other name, the by-level after it for
gp(x, by = f) (sdgp_gpxfa), and the covariate after that for a
non-isotropic term's length scales (lscale_gpxzx).
Names that would collide
brms's renaming can give two parameters one name, and frmtmb does what brms does with each case:
Within one predictor, a covariate whose renamed column repeats another's,
y ~ Intercept + x((Intercept)andInterceptare bothIntercept), is refused with brms's "Internal renaming led to duplicated names".Across predictors, the later name takes brms's
__1suffix: inbf(y ~ sigma_z, sigma ~ z)the covariatesigma_zofmuand the coefficientzofsigmaareb_sigma_zandb_sigma_z__1.A group-level coefficient given twice on one group is refused, see above.
Two responses brms spells alike,
y_aandya, are refused with brms's "Cannot use the same response variable twice".A group-level label given twice on draws, from levels
lvl 1andlvl.1, takes brms's__1on the later level.An interaction group two of whose levels brms joins to one string (
1_2:3and1:2_3) is refused: brms pools the two levels.
A coefficient and a natural-scale name cannot meet: every coefficient
starts b_, bs_ or bsp_, and sigma does not.
A mixture's weights with no theta formula are brms's simplex,
theta1 ... thetaK, the mixing probabilities, computed together from
the K - 1 estimated log ratios against the last component.
See also
vcov.frmtmb_fit() with full = TRUE for the same joint
covariance (fixed effects plus covariance parameters, on their
internal scale) as a matrix, which is what the "wald" method uses
here.
Methods:
"wald"(default): delta-method z-test, finite-difference gradient against the joint parameter covariance (under REML, from the joint precision)."profile": profile-likelihood interval viaTMB::tmbroot()with alincombdirection. Only for hypotheses that are linear in the parameters, and only for ML fits; the standard error and the test stay Wald-based, because the method changes the interval."boot": parametric bootstrap throughfrm_bootstrap()(percentile interval;pis the two-sided percentile p-value, whose resolution is limited bynsim;Est.Erroris the bootstrap SD). Handles any expression, including the variance-component names, whose sampling distributions Wald approximates poorly.
For a frm_multiple() result the Wald estimate and delta-method
variance are computed per imputation and pooled by Rubin's rules
with Barnard-Rubin degrees of freedom; the test attribute carries
t and df in place of z, and only Wald inference is available.
Examples
set.seed(4)
dd <- data.frame(x1 = rnorm(120), x2 = rnorm(120),
g = factor(rep(1:10, 12)))
dd$y <- rnorm(120, 1 + 0.6 * dd$x1 + 0.4 * dd$x2 +
rnorm(10, 0, 0.5)[dd$g], 1)
fit <- frm(bf(y ~ x1 + x2 + (1 | g)) + gaussian(), data = dd)
h <- hypothesis(fit, c("x1 - x2 = 0", "exp(Intercept) = 1"))
h
#> Hypothesis Tests for class b:
#> Hypothesis Estimate Est.Error CI.Lower CI.Upper Evid.Ratio
#> 1 (x1-x2) = 0 0.37 0.13 0.12 0.62 NA
#> 2 (exp(Intercept))-(1) = 0 1.51 0.48 0.56 2.45 NA
#> Post.Prob Star
#> 1 NA *
#> 2 NA *
#> ---
#> 'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
#> Method: wald. Est.Error is the standard error; Evid.Ratio and
#> Post.Prob are NA, because a maximum-likelihood fit has no posterior.
#> '*': For one-sided hypotheses, the one-sided test rejects at level 0.05;
#> for two-sided hypotheses, the value tested against lies outside the 95%-CI.
#> Hypothesis z p
#> (x1-x2) = 0 2.889 0.003859
#> (exp(Intercept))-(1) = 0 3.122 0.001799
h$hypothesis$Est.Error
#> [1] 0.1280462 0.4829377
attr(h, "test")$p
#> [1] 0.003859416 0.001799301
# brms's directional form: one-sided p, and a 90% interval
hypothesis(fit, "x1 > x2")
#> Hypothesis Tests for class b:
#> Hypothesis Estimate Est.Error CI.Lower CI.Upper Evid.Ratio Post.Prob Star
#> 1 (x1)-(x2) > 0 0.37 0.13 0.16 0.58 NA NA *
#> ---
#> 'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
#> Method: wald. Est.Error is the standard error; Evid.Ratio and
#> Post.Prob are NA, because a maximum-likelihood fit has no posterior.
#> '*': For one-sided hypotheses, the one-sided test rejects at level 0.05;
#> for two-sided hypotheses, the value tested against lies outside the 95%-CI.
#> Hypothesis z p
#> (x1)-(x2) > 0 2.889 0.00193
# class/group name the natural-scale random-effect summaries
hypothesis(fit, "Intercept > 0", class = "sd", group = "g")
#> Hypothesis Tests for class sd_g:
#> Hypothesis Estimate Est.Error CI.Lower CI.Upper Evid.Ratio Post.Prob
#> 1 (Intercept) > 0 0.55 0.15 0.3 0.8 NA NA
#> Star
#> 1 *
#> ---
#> 'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
#> Method: wald. Est.Error is the standard error; Evid.Ratio and
#> Post.Prob are NA, because a maximum-likelihood fit has no posterior.
#> '*': For one-sided hypotheses, the one-sided test rejects at level 0.05;
#> for two-sided hypotheses, the value tested against lies outside the 95%-CI.
#> Hypothesis z p
#> (Intercept) > 0 3.614 0.0001508
# variance-component expressions need class = NULL, as in brms: an
# ICC with bootstrap intervals
hypothesis(fit, "sd_g__Intercept^2 / (sd_g__Intercept^2 + sigma^2) = 0",
class = NULL, method = "boot", nsim = 20, seed = 1)
#> Hypothesis Tests for class :
#> Hypothesis Estimate Est.Error
#> 1 (sd_g__Intercept^2/(sd_g__Intercept^2+sigma^2)) = 0 0.27 0.12
#> CI.Lower CI.Upper Evid.Ratio Post.Prob Star
#> 1 0.03 0.42 NA NA *
#> ---
#> 'CI': 90%-CI for one-sided and 95%-CI for two-sided hypotheses.
#> Method: boot (20 bootstrap draws, 0 failed or not converged). Est.Error is the bootstrap SD; Evid.Ratio and
#> Post.Prob are NA, because a maximum-likelihood fit has no posterior.
#> '*': For one-sided hypotheses, the one-sided test rejects at level 0.05;
#> for two-sided hypotheses, the value tested against lies outside the 95%-CI.
#> Hypothesis z p
#> (sd_g__Intercept^2/(sd_g__Intercept^2+sigma^2)) = 0 2.189 0.09524