(Non-)Linear Tests for Null Hypotheses, Joint Hypotheses, Equivalence, Non Superiority, and Non Inferiority

## Description

Uncertainty estimates are calculated as first-order approximate standard errors for linear or non-linear functions of a vector of random variables with known or estimated covariance matrix. In that sense, `hypotheses` emulates the behavior of the excellent and well-established car::deltaMethod and car::linearHypothesis functions, but it supports more models; requires fewer dependencies; expands the range of tests to equivalence and superiority/inferiority; and offers convenience features like robust standard errors.

Warning #1: Tests are conducted directly on the scale defined by the `type` argument. For some models, it can make sense to conduct hypothesis or equivalence tests on the `“link”` scale instead of the `“response”` scale which is often the default.

Warning #2: For hypothesis tests on objects produced by the `marginaleffects` package, it is safer to use the `hypothesis` argument of the original function. Using `hypotheses()` may not work in certain environments, in lists, or when working programmatically with *apply style functions.

## Usage

``````hypotheses(
model,
hypothesis = NULL,
vcov = NULL,
conf_level = 0.95,
df = Inf,
equivalence = NULL,
joint = FALSE,
joint_test = "f",
FUN = NULL,
...
)
``````

## Arguments

 model Model object or object generated by the `comparisons()`, `slopes()`, `predictions()`, or `marginal_means()` functions. hypothesis specify a hypothesis test or custom contrast using a numeric value, vector, or matrix, a string, or a string formula. Numeric: Single value: the null hypothesis used in the computation of Z and p (before applying `transform`). Vector: Weights to compute a linear combination of (custom contrast between) estimates. Length equal to the number of rows generated by the same function call, but without the `hypothesis` argument. Matrix: Each column is a vector of weights, as describe above, used to compute a distinct linear combination of (contrast between) estimates. The column names of the matrix are used as labels in the output. String formula to specify linear or non-linear hypothesis tests. If the `term` column uniquely identifies rows, terms can be used in the formula. Otherwise, use `b1`, `b2`, etc. to identify the position of each parameter. Examples: `hp = drat` `hp + drat = 12` `b1 + b2 + b3 = 0` String: "pairwise": pairwise differences between estimates in each row. "reference": differences between the estimates in each row and the estimate in the first row. "sequential": difference between an estimate and the estimate in the next row. "revpairwise", "revreference", "revsequential": inverse of the corresponding hypotheses, as described above. See the Examples section below and the vignette: https://vincentarelbundock.github.io/marginaleffects/articles/hypothesis.html vcov Type of uncertainty estimates to report (e.g., for robust standard errors). Acceptable values: FALSE: Do not compute standard errors. This can speed up computation considerably. TRUE: Unit-level standard errors using the default `vcov(model)` variance-covariance matrix. String which indicates the kind of uncertainty estimates to return. Heteroskedasticity-consistent: `“HC”`, `“HC0”`, `“HC1”`, `“HC2”`, `“HC3”`, `“HC4”`, `“HC4m”`, `“HC5”`. See `?sandwich::vcovHC` Heteroskedasticity and autocorrelation consistent: `“HAC”` Mixed-Models degrees of freedom: "satterthwaite", "kenward-roger" Other: `“NeweyWest”`, `“KernHAC”`, `“OPG”`. See the `sandwich` package documentation. One-sided formula which indicates the name of cluster variables (e.g., `~unit_id`). This formula is passed to the `cluster` argument of the `sandwich::vcovCL` function. Square covariance matrix Function which returns a covariance matrix (e.g., `stats::vcov(model)`) conf_level numeric value between 0 and 1. Confidence level to use to build a confidence interval. df Degrees of freedom used to compute p values and confidence intervals. A single numeric value between 1 and `Inf`. When `df` is `Inf`, the normal distribution is used. When `df` is finite, the `t` distribution is used. See insight::get_df for a convenient function to extract degrees of freedom. Ex: `slopes(model, df = insight::get_df(model))` equivalence Numeric vector of length 2: bounds used for the two-one-sided test (TOST) of equivalence, and for the non-inferiority and non-superiority tests. See Details section below. joint Joint test of statistical significance. The null hypothesis value can be set using the `hypothesis` argument. FALSE: Hypotheses are not tested jointly. TRUE: All parameters are tested jointly. String: A regular expression to match parameters to be tested jointly. `grep(joint, perl = TRUE)` Character vector of parameter names to be tested. Characters refer to the names of the vector returned by `coef(object)`. Integer vector of indices. Which parameters positions to test jointly. joint_test A character string specifying the type of test, either "f" or "chisq". The null hypothesis is set by the `hypothesis` argument, with default null equal to 0 for all parameters. FUN `NULL` or function. `NULL` (default): hypothesis test on a model’s coefficients, or on the quantities estimated by one of the `marginaleffects` package functions. Function which accepts a model object and returns a numeric vector or a data.frame with two columns called `term` and `estimate`. This argument can be useful when users want to conduct a hypothesis test on an arbitrary function of quantities held in a model object. ... Additional arguments are passed to the `predict()` method supplied by the modeling package.These arguments are particularly useful for mixed-effects or bayesian models (see the online vignettes on the `marginaleffects` website). Available arguments can vary from model to model, depending on the range of supported arguments by each modeling package. See the "Model-Specific Arguments" section of the `?marginaleffects` documentation for a non-exhaustive list of available arguments.

## Joint hypothesis tests

The test statistic for the joint Wald test is calculated as (R * theta_hat - r)’ * inv(R * V_hat * R’) * (R * theta_hat - r) / Q, where theta_hat is the vector of estimated parameters, V_hat is the estimated covariance matrix, R is a Q x P matrix for testing Q hypotheses on P parameters, r is a Q x 1 vector for the null hypothesis, and Q is the number of rows in R. If the test is a Chi-squared test, the test statistic is not normalized.

The p-value is then calculated based on either the F-distribution (for F-test) or the Chi-squared distribution (for Chi-squared test). For the F-test, the degrees of freedom are Q and (n - P), where n is the sample size and P is the number of parameters. For the Chi-squared test, the degrees of freedom are Q.

## Equivalence, Inferiority, Superiority

is an estimate, `_` its estimated standard error, and `[a, b]` are the bounds of the interval supplied to the `equivalence` argument.

Non-inferiority:

• `H_0`: `a`

• `H_1`: `> a`

• `t=(- a)/_`

• p: Upper-tail probability

Non-superiority:

• `H_0`: `b`

• `H_1`: `< b`

• `t=(- b)/_`

• p: Lower-tail probability

Equivalence: Two One-Sided Tests (TOST)

• p: Maximum of the non-inferiority and non-superiority p values.

Thanks to Russell V. Lenth for the excellent `emmeans` package and documentation which inspired this feature.

## Examples

``````library(marginaleffects)

library(marginaleffects)
mod <- lm(mpg ~ hp + wt + factor(cyl), data = mtcars)

# When `FUN` and `hypotheses` are `NULL`, `hypotheses()` returns a data.frame of parameters
hypotheses(mod)``````
``````
Term Estimate Std. Error     z Pr(>|z|)   2.5 %    97.5 %     S
b1  35.8460      2.041 17.56   <0.001 31.8457 39.846319 227.0
b2  -0.0231      0.012 -1.93   0.0531 -0.0465  0.000306   4.2
b3  -3.1814      0.720 -4.42   <0.001 -4.5918 -1.771012  16.6
b4  -3.3590      1.402 -2.40   0.0166 -6.1062 -0.611803   5.9
b5  -3.1859      2.170 -1.47   0.1422 -7.4399  1.068169   2.8

Columns: term, estimate, std.error, statistic, p.value, conf.low, conf.high, s.value ``````
``````# Test of equality between coefficients
hypotheses(mod, hypothesis = "hp = wt")``````
``````
Term Estimate Std. Error    z Pr(>|z|) 2.5 % 97.5 %    S
hp = wt     3.16       0.72 4.39   <0.001  1.75   4.57 16.4

Columns: term, estimate, std.error, statistic, p.value, conf.low, conf.high, s.value ``````
``````# Non-linear function
hypotheses(mod, hypothesis = "exp(hp + wt) = 0.1")``````
``````
Term Estimate Std. Error     z Pr(>|z|)  2.5 %  97.5 %   S
exp(hp + wt) = 0.1  -0.0594     0.0292 -2.04   0.0418 -0.117 -0.0022 4.6

Columns: term, estimate, std.error, statistic, p.value, conf.low, conf.high, s.value ``````
``````# Robust standard errors
hypotheses(mod, hypothesis = "hp = wt", vcov = "HC3")``````
``````
Term Estimate Std. Error    z Pr(>|z|) 2.5 % 97.5 %    S
hp = wt     3.16      0.805 3.92   <0.001  1.58   4.74 13.5

Columns: term, estimate, std.error, statistic, p.value, conf.low, conf.high, s.value ``````
``````# b1, b2, ... shortcuts can be used to identify the position of the
# parameters of interest in the output of FUN
hypotheses(mod, hypothesis = "b2 = b3")``````
``````
Term Estimate Std. Error    z Pr(>|z|) 2.5 % 97.5 %    S
b2 = b3     3.16       0.72 4.39   <0.001  1.75   4.57 16.4

Columns: term, estimate, std.error, statistic, p.value, conf.low, conf.high, s.value ``````
``````# term names with special characters have to be enclosed in backticks
hypotheses(mod, hypothesis = "`factor(cyl)6` = `factor(cyl)8`")``````
``````
Term Estimate Std. Error      z Pr(>|z|) 2.5 %
`factor(cyl)6` = `factor(cyl)8`   -0.173       1.65 -0.105    0.917 -3.41
97.5 %   S
3.07 0.1

Columns: term, estimate, std.error, statistic, p.value, conf.low, conf.high, s.value ``````
``````mod2 <- lm(mpg ~ hp * drat, data = mtcars)
hypotheses(mod2, hypothesis = "`hp:drat` = drat")``````
``````
Term Estimate Std. Error    z Pr(>|z|) 2.5 % 97.5 %   S
`hp:drat` = drat    -6.08       2.89 -2.1   0.0357 -11.8 -0.405 4.8

Columns: term, estimate, std.error, statistic, p.value, conf.low, conf.high, s.value ``````
``````# predictions(), comparisons(), and slopes()
mod <- glm(am ~ hp + mpg, data = mtcars, family = binomial)
cmp <- comparisons(mod, newdata = "mean")
hypotheses(cmp, hypothesis = "b1 = b2")``````
``````
Term Estimate Std. Error     z Pr(>|z|)   S  2.5 %  97.5 %
b1=b2   -0.288      0.125 -2.31   0.0209 5.6 -0.532 -0.0435

Columns: term, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high ``````
``````mfx <- slopes(mod, newdata = "mean")
hypotheses(cmp, hypothesis = "b2 = 0.2")``````
``````
Term Estimate Std. Error     z Pr(>|z|)   S  2.5 % 97.5 %
b2=0.2    0.101      0.131 0.774    0.439 1.2 -0.155  0.358

Columns: term, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high ``````
``````pre <- predictions(mod, newdata = datagrid(hp = 110, mpg = c(30, 35)))
hypotheses(pre, hypothesis = "b1 = b2")``````
``````
Term  Estimate Std. Error      z Pr(>|z|)   S     2.5 %   97.5 %
b1=b2 -3.57e-05   0.000172 -0.207    0.836 0.3 -0.000373 0.000302

Columns: term, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high ``````
``````# The `FUN` argument can be used to compute standard errors for fitted values
mod <- glm(am ~ hp + mpg, data = mtcars, family = binomial)

f <- function(x) predict(x, type = "link", newdata = mtcars)
p <- hypotheses(mod, FUN = f)
``````
Term Estimate Std. Error      z Pr(>|z|) 2.5 % 97.5 %   S
b1   -1.098      0.716 -1.534    0.125 -2.50  0.305 3.0
b2   -1.098      0.716 -1.534    0.125 -2.50  0.305 3.0
b3    0.233      0.781  0.299    0.765 -1.30  1.764 0.4
b4   -0.595      0.647 -0.919    0.358 -1.86  0.674 1.5
b5   -0.418      0.647 -0.645    0.519 -1.69  0.851 0.9
b6   -5.026      2.195 -2.290    0.022 -9.33 -0.725 5.5

Columns: term, estimate, std.error, statistic, p.value, conf.low, conf.high, s.value ``````
``````f <- function(x) predict(x, type = "response", newdata = mtcars)
p <- hypotheses(mod, FUN = f)
``````
Term Estimate Std. Error     z Pr(>|z|)   2.5 % 97.5 %   S
b1  0.25005     0.1342 1.863  0.06243 -0.0130 0.5131 4.0
b2  0.25005     0.1342 1.863  0.06243 -0.0130 0.5131 4.0
b3  0.55803     0.1926 2.898  0.00376  0.1806 0.9355 8.1
b4  0.35560     0.1483 2.399  0.01646  0.0650 0.6462 5.9
b5  0.39710     0.1550 2.561  0.01043  0.0932 0.7010 6.6
b6  0.00652     0.0142 0.459  0.64635 -0.0213 0.0344 0.6

Columns: term, estimate, std.error, statistic, p.value, conf.low, conf.high, s.value ``````
``````# Equivalence, non-inferiority, and non-superiority tests
mod <- lm(mpg ~ hp + factor(gear), data = mtcars)
p <- predictions(mod, newdata = "median")
hypotheses(p, equivalence = c(17, 18))``````
``````
Estimate Std. Error    z Pr(>|z|)     S 2.5 % 97.5 %  hp gear p (NonInf)
19.7          1 19.6   <0.001 281.3  17.7   21.6 123    3    0.00404
p (NonSup) p (Equiv)
0.951     0.951

Columns: rowid, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high, mpg, hp, gear, statistic.noninf, statistic.nonsup, p.value.noninf, p.value.nonsup, p.value.equiv ``````
``````mfx <- avg_slopes(mod, variables = "hp")
hypotheses(mfx, equivalence = c(-.1, .1))``````
``````
Term Estimate Std. Error     z Pr(>|z|)    S   2.5 %  97.5 % p (NonInf)
hp  -0.0669      0.011 -6.05   <0.001 29.4 -0.0885 -0.0452    0.00135
p (NonSup) p (Equiv)
<0.001   0.00135

Columns: term, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high, statistic.noninf, statistic.nonsup, p.value.noninf, p.value.nonsup, p.value.equiv ``````
``cmp <- avg_comparisons(mod, variables = "gear", hypothesis = "pairwise")``
``````Warning: The `gear` variable is treated as a categorical (factor) variable, but
the original data is of class numeric. It is safer and faster to convert
such variables to factor before fitting the model and calling `slopes`
functions.

This warning appears once per session.``````
``hypotheses(cmp, equivalence = c(0, 10))``
``````
Term Estimate Std. Error     z Pr(>|z|)   S 2.5 % 97.5 %
(4 - 3) - (5 - 3)    -3.94       2.05 -1.92   0.0543 4.2 -7.95 0.0727
p (NonInf) p (NonSup) p (Equiv)
0.973     <0.001     0.973

Columns: term, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high, statistic.noninf, statistic.nonsup, p.value.noninf, p.value.nonsup, p.value.equiv ``````
``````# joint hypotheses: character vector
model <- lm(mpg ~ as.factor(cyl) * hp, data = mtcars)
hypotheses(model, joint = c("as.factor(cyl)6:hp", "as.factor(cyl)8:hp"))``````
``````

Joint hypothesis test:
as.factor(cyl)6:hp = 0
as.factor(cyl)8:hp = 0

F Pr(>|F|) Df 1 Df 2
2.11    0.142    2   26

Columns: statistic, p.value, df1, df2 ``````
``````# joint hypotheses: regular expression
hypotheses(model, joint = "cyl")``````
``````

Joint hypothesis test:
as.factor(cyl)6 = 0
as.factor(cyl)8 = 0
as.factor(cyl)6:hp = 0
as.factor(cyl)8:hp = 0

F Pr(>|F|) Df 1 Df 2
5.7  0.00197    4   26

Columns: statistic, p.value, df1, df2 ``````
``````# joint hypotheses: integer indices
hypotheses(model, joint = 2:3)``````
``````

Joint hypothesis test:
as.factor(cyl)6 = 0
as.factor(cyl)8 = 0

F Pr(>|F|) Df 1 Df 2
6.12  0.00665    2   26

Columns: statistic, p.value, df1, df2 ``````
``````# joint hypotheses: different null hypotheses
hypotheses(model, joint = 2:3, hypothesis = 1)``````
``````

Joint hypothesis test:
as.factor(cyl)6 = 1
as.factor(cyl)8 = 1

F Pr(>|F|) Df 1 Df 2
6.84  0.00411    2   26

Columns: statistic, p.value, df1, df2 ``````
``hypotheses(model, joint = 2:3, hypothesis = 1:2)``
``````

Joint hypothesis test:
as.factor(cyl)6 = 1
as.factor(cyl)8 = 2

F Pr(>|F|) Df 1 Df 2
7.47  0.00273    2   26

Columns: statistic, p.value, df1, df2 ``````
``````# joint hypotheses: marginaleffects object
cmp <- avg_comparisons(model)
hypotheses(cmp, joint = "cyl")``````
``````

Joint hypothesis test:
cyl 6 - 4 = 0
cyl 8 - 4 = 0

F Pr(>|F|) Df 1 Df 2
1.6    0.219    2   29

Columns: statistic, p.value, df1, df2 ``````