Supported models¶
The tests of the package examine the residuals of a least-squares fit for a variance that is not constant. They accept the models whose residuals are those of a least-squares fit, and refuse the others when they are called, before they compute anything, each with one message. This page says which test accepts which class of model, and why; the rules, and the messages, are in What every test returns, under Supported models and Inputs every test refuses.
The table was measured, not written from the code: every exported test was
called as in tests/testthat/helper-test-recipes.R, on a fit of each class to
the 120 observations of contract_data(), on 0.15.0 and on the development
version. A cell in bold changed in 0.16.0.
The classes, and why¶
One line for each class and each answer in the table.
| Class | Answer | Why |
|---|---|---|
lm |
yes | Its residuals are least-squares residuals, the ones the null distributions of the tests are derived for. |
lm(..., weights = w) |
yes | lm() states that the error variance is \(\sigma^2 / w_i\); the tests read the Pearson residuals \(\sqrt{w_i}\, e_i\), the residuals of the unweighted regression of \(\sqrt{w_i}\, y_i\) on \(\sqrt{w_i}\, x_i\), which have constant variance when the weights are right. |
| no: weighted | performQuantileRegressionTest() refits the model without the weights, which would test another model. |
|
no: not fitWLS() |
performVarianceFormTest() tests the variance function fitWLS() estimated; weights given by hand have none to test. |
|
An lm with a zero weight |
no: zero weight | The observation is not part of the fit, and its residual is an artificial zero that the test would count as an observation. |
| yes | performRESETTest() compares two weighted least-squares fits, which both leave the observation out: its value is that of the fit to the observations with positive weight. |
|
Gaussian glm, identity link |
yes | A least-squares fit: its coefficients, fitted values and residuals are those of lm(), up to rounding, and every perform*Test() gives the result of the lm (see A Gaussian glm is a least-squares fit below), when the two decide the rank of the design alike. performWhiteTestStreaming(), performHarrisonMcCabeTest() and performVarianceFormTest() refused every glm until 0.16.0, and bootstrapTestStatistic() until 0.17.0, which bootstraps it as the lm it is, with its prior weights. |
Gaussian glm with prior weights |
yes | Its prior weights, prior.weights, are the weights of lm(..., weights = w), and the tests read them. Its weights are the working weights of the last iteration of iteratively reweighted least squares, \(w_i (d\mu_i / d\eta_i)^2 / V(\mu_i)\), which for this family and link are the prior weights; the tests do not read them. |
no: not fitWLS() |
performVarianceFormTest() refuses prior weights given to glm() as it refuses weights given to lm(): they have no variance function to test. |
|
Gaussian glm with a zero prior weight |
no: zero weight | As for the lm. Before 0.16.0 most tests read no weights for a glm and tested the artificial zero. |
Binomial, Poisson or any other glm |
no: not least squares | The variance of its residuals depends on the mean by construction, so a test of constant variance tests nothing. |
survey::svyglm() |
no: survey | Its residuals are scaled by the sampling weights, which are not precision weights: a homoscedastic model is rejected whenever they vary with the regressors. runSurveyHeteroTests() fits the model by least squares to the data of the design instead. |
plm::plm() |
no: not lm |
The panel tests, performPesaranTest() and performBPRandomEffectsTest(), take the pooled lm of the panel and the columns of data that name the units and the periods. A plm fit is not an lm. |
| A rank-deficient fit | yes | An aliased column, a linear combination of the others, does not change the column space of the design, so the residuals and fitted values are those of the model fitted without it. Since 0.16.0 the tests drop the aliased columns from the design they build and take their degrees of freedom from the rank: the value is that of the model fitted without them. |
| no | A test that refuses the model without the aliased columns, for one of the reasons above, refuses the rank-deficient one with the same message. | |
| yes, not the reduced value | performVarianceFormTest(form = "power") takes the logarithms of every column of the design, the aliased ones included; the logarithm of an aliased column is not a combination of the logarithms of the others, so the value is not that of the model without the aliased columns. It does not depend on the order of the terms, as the value of that model does. With the exponential form, the default, the value is that of the model without them. |
|
An NA from an empty cell |
yes | The dummy of a cell of an interaction that no observation falls in is aliased: as for any rank-deficient fit. |
| yes, since 0.17.0 | The squares of the dummies are collinear: performWhiteTestStreaming() drops them, as performWhiteTest() does, and gives the value of the model fitted without the aliased column. Until 0.17.0 it stopped, as it did on that model. |
|
Gaussian mgcv::gam() |
yes | A glm by class. Without smooth terms it is the least-squares fit of its design, and the tests give the value of the Gaussian glm. Its residuals carry no names: since 0.16.0 the tests built on the model context match the rows of data to its observations by the row names of its model frame, where Glejser's, Park's, Szroeter's, Harrison-McCabe's and Hartley's tests, the five group tests (Levene's, Brown-Forsythe's, Fligner-Killeen's, Bartlett's and O'Brien's), the panel tests (Pesaran's and the Breusch-Pagan random-effects test, and so runPanelTests()) and the scatter diagnostic matched them by position and returned a wrong value on data in another order than the fit; the other tests that read a column of data (the streaming tests) still do until their step of the model context. |
Gaussian mgcv::gam() with smooth terms |
as today | A smooth term is penalised unless it is fixed (s(x, fx = TRUE)), and a penalised fit is not the least-squares fit of its design. White's, the Breusch-Pagan, Koenker's, the rank permutation, the high-dimensional, Glejser's, Park's, Szroeter's, Harrison-McCabe's, Hartley's and the spatial tests, the five group tests, the two panel tests and the scatter diagnostic test it as before 0.16.0; whether the tests take such a fit is an open decision, settled for every test together in the last step of the model context, with MASS::rlm(). White's value on such a fit changes slightly in 0.16.0, with the correction of its degrees of freedom: the squares and products of a smooth basis are nearly collinear, the auxiliary regression of 0.15.0 lost a column to its intercept without counting it, and the test now gives the value of lm(e^2 ~ Z) and lmtest::bptest() with the same terms (46.05 for 45.92, on 60 degrees of freedom, on gam(y ~ s(x1) + x2) of the test matrix). |
| no: smooth terms | Since 0.16.0 RESET, Goldfeld-Quandt, the quantile regression test and the studentized Breusch-Pagan statistic refuse it until then, fixed smooths included: each fits the design of the fit again, by least squares or by quantile regression, which would test a regression the model is not. RESET and the studentized statistic returned a value before; Goldfeld-Quandt and the quantile test stopped on the smooth term, which they evaluated outside mgcv. Since 0.17.0 performWhiteTestBootstrap() refuses it too, as each replicate refits the design by least squares; its refit from the formula stopped on the smooth term before. bootstrapTestStatistic() refuses every gam, as before. |
|
MASS::rlm() |
as today | An lm by class, so 37 tests accept it, as before 0.16.0, and test its M-estimation residuals as if they were least-squares residuals. Whether that is a test of anything is an open decision (below). |
no: weighted, no: not fitWLS(), no: refit differs |
Its case weights, all 1 unless given, are read as weights; bootstrapTestStatistic() refits each replicate by least squares, which does not reproduce an M-estimate. |
|
fitWLS() |
yes | A weighted lm whose weights were estimated. The reference distributions take the weights as known, so they are approximate; performVarianceFormTest() accounts for the estimation. |
fitWLS() of a Gaussian glm |
yes | Since 0.16.0 it is the lm that fitWLS() returns for the equivalent lm, with the call of that lm, and is tested as that. Before, it kept the class and the call of the glm without its family, which summary() could not read and every test refused; fitWLS() refuses any other glm, and a survey::svyglm() fit, now. |
| A model with an offset | yes | The residuals of the fit include the offset, and the tests read them (see Offsets below). |
| yes, since 0.16.0 | RESET, the quantile regression test and the studentized Breusch-Pagan statistic left any offset out of a refit, and GQ an offset given as an argument, or any offset on a weighted fit. They refused such a model in the development of 0.16.0 (decided 2026-10-17), until the offset fix, the second step of the model context, made them read the offset from the fit (Offsets below). |
Every test also refuses a coefficient that is infinite, NaN, or NA without
the fit being rank-deficient, and data that lack rows or variables of the
fit, or whose rows cannot be shown to be those of the fit. Anything that is
not an lm or a glm, a plm fit among them, is refused by every test with
one message, which names the class received and points to the pooled lm the
panel tests take.
Which model without the aliased columns¶
The model fitted without the aliased columns is the one lm() keeps: its
decomposition keeps a column unless it is a combination of the columns before
it, so of an aliased set the column that comes last, in the order of the
terms, is left out (in y ~ x1 + x2 + x_sum, with x_sum = x1 + x2, it is
x_sum; in y ~ x_sum + x1 + x2, it is x2). Most statistics depend only on
the space the columns span, and are the same whichever column is left out.
These depend on which:
performWhiteTest(), and soperformWhiteTestRobust(),performWhiteTestStreaming()andperformWhiteTestBootstrap(), when the cross products are left out (cross_products = FALSE,method = "reduced", or more regressors thanmax_interactions): the squares are those of the columns kept. With the cross products, the default, they span the same space either way.performHighDimensionalTest()when it keeps fewer principal components than there are columns.
Offsets¶
An offset, given as offset = o or written as offset(o), is part of the fit,
and most tests read the residuals of the fit, which include it: on a model
with an offset they give the value of the same model fitted to the response
minus the offset. Four left it out of a refit, and returned a value that is
not that of the model. Decided on 2026-10-17, they refused exactly the offsets
they left out, in the development of 0.16.0, until the offset fix made them
correct. That fix is the second step of the model context: they read the
response, the design, the weights and the total offset from the fit, and every
refit carries the offset.
| Test | Before the fix | Since 0.16.0 |
|---|---|---|
performRESETTest() |
It refitted the model augmented with powers of the fitted values without the offset, so the two fits were not nested. | The nested F test of the model with its offset against the model augmented with the powers of its fitted values, \(X\hat\beta + o\), fitted with the same offset and weights (decided 2026-10-18). It is not RESET of the model of y - o, which augments that model with the powers of \(X\hat\beta\) alone. |
performGQTest() |
It refitted each segment of an unweighted fit from the formula, which evaluated an offset() term again but left out an argument; on a weighted fit it refitted with lm.wfit() and no offset. |
Each segment is fitted to its rows of the design, the response and the offset of the fit: the value of the model of y - o. |
performQuantileRegressionTest() |
quantreg::rq() was fitted to the formula, which left the offset out. |
The quantile regressions are fitted to the response minus the offset, on the design of the fit: the model of y - o, since the offset shifts every conditional quantile as it shifts the mean. |
performStudentizedBPTest(), performBPTestRobust() with studentize = TRUE (its default), the registered "student_bp" |
The studentized statistic refitted the design without the offset. | The refit carries the offset: Koenker's statistic of the model, as performKoenkerTest() and performBPTestRobust(studentize = FALSE) give it. |
An offset that is zero everywhere changes nothing. runDiagnostics(), which
runs RESET, returns for a model with an offset. The tests built on the fitted values
(the Cook-Weisberg, Spearman, spread-level and Davidian-Carroll tests, and
Harvey's with auxiliary = "fitted") read \(X\hat\beta\) plus the offset, as
the fit defines it, so their value is not that of the model of y - o, by
design.
RESET with a zero weight¶
Decided on 2026-10-17: performRESETTest() keeps accepting a zero weight,
the one exception to the refusal of a zero weight. Its two fits are weighted
least squares, which leave the observation out, and its F statistic and
degrees of freedom are those of the fit to the observations with positive
weight.
A Gaussian glm is a least-squares fit¶
Every perform*Test() function accepts a glm with the Gaussian family and
the identity link, and gives it the value of the lm with the same prior
weights. Until 0.16.0 performWhiteTestStreaming(),
performHarrisonMcCabeTest() and performVarianceFormTest() refused every
glm; this section is why they need not, and
tests/testthat/test-model-eligibility.R is the evidence.
bootstrapTestStatistic() refused every glm until 0.17.0, as it refits each
replicate by least squares, which would drop a family and a link; by the same
argument it bootstraps this one as the lm it is, with its prior weights,
and still refuses a glm of any other family or link (N8 of the design of the
model context).
The fit. With prior weights \(w_i\), all 1 when none are given, such a
glm states that the \(y_i\) are independent and normal, with mean
\(x_i^\top \beta\) and variance \(\phi / w_i\): the normal linear model that
lm(..., weights = w) fits, with \(\sigma^2 = \phi\). glm() fits it by
maximum likelihood, and the log-likelihood
is maximised in \(\beta\) by weighted least squares. The algorithm of glm(),
iteratively reweighted least squares, regresses the working response
\(z_i = \eta_i + (y_i - \mu_i)\, d\eta_i / d\mu_i\) on \(x_i\) with the working
weights \(w_i (d\mu_i / d\eta_i)^2 / V(\mu_i)\) (Nelder and Wedderburn, 1972;
McCullagh and Nelder, 1989, section 2.5). With the identity link
\(d\mu / d\eta = 1\), and for the Gaussian family \(V(\mu) = 1\), so
\(z_i = y_i\) and the working weights are the prior weights, whatever the
current estimate: the first step is the weighted least-squares fit, and it is
a fixed point. In the terms of Green (1984, section 1.2): Newton-Raphson
converges in one step from any start when the log-likelihood is quadratic in
\(\beta\), as it is here; iteratively reweighted least squares is Fisher
scoring, Newton-Raphson with the information replaced by its expectation;
and for the identity link, the canonical link of the Gaussian family, the
information \(X^\top W X / \phi\) does not depend on \(y\), so it equals its
expectation and scoring is Newton-Raphson, which converges in one step.
glm.fit() takes a second iteration to see that the deviance no longer
changes, which moves the fitted values by rounding only. McCullagh and
Nelder (1989) treat the normal linear model as this generalized linear model
in their chapter 3, Models for continuous data with constant variance
(section 3.6, Estimation; section 3.8, Algorithms for least squares).
So the glm and lm(..., weights = w) have the same design matrix \(X\)
(model.matrix()), response and model frame; the same coefficients, fitted
values \(\hat\mu = X \hat\beta\) and response residuals \(e = y - \hat\mu\), up
to rounding (about \(10^{-14}\) in the tests); the same weights, as the prior
weights of the glm, prior.weights, are the weights of the lm, which
the tests read, and its working weights, weights, equal them up to
rounding (glm.fit() stores the squares of their square roots, which
differ from them by up to about \(2 \times 10^{-15}\)); the same rank and
residual degrees of freedom, when the two decide the rank alike (below);
and the same estimate of the error variance, as the dispersion
\(\hat\phi = \sum_i w_i e_i^2 / (n - p)\) is \(\hat\sigma^2\). Its deviance
residuals, which residuals() returns, are
\(\operatorname{sign}(e_i) \sqrt{w_i e_i^2} = \sqrt{w_i}\, e_i\), the Pearson
residuals of the lm, which the tests read.
The rank. lm() decides the rank of the design in its QR
decomposition with the tolerance tol = 1e-7; glm.fit() with
min(1e-7, epsilon / 1000), which is 1e-11 with the default
epsilon = 1e-8 of glm.control(). A column that is a combination of the
others to within that margin is aliased by the lm and kept by the glm,
and the glm then has the residuals, the rank and the test values of
lm(..., tol = 1e-11), not those of the default lm. With
x3 = x1 + 1e-9 * rnorm(120) added to contract_data() (seed 5), the lm
aliases x3 and the glm does not: Harrison-McCabe gives 0.3184 for the
lm and 0.3199 for the glm (that of lm(..., tol = 1e-11)), Koenker
9.04 on 2 degrees of freedom against 9.25 on 3, and the White streaming test
refuses the glm, whose auxiliary regression is then rank-deficient. The
equivalence above holds when the two decide the rank alike, as they do
unless a column is that close to a combination of the others; the behaviour
is not changed. Harrison-McCabe takes the rank of the fit, decided at the
fit's tolerance, since 0.16.0: its residuals are those of the fit of rank 4,
and its null distribution was computed from the design at the default
tolerance, of rank 3, which gave the glm above a p-value of 0.002288 for
0.002273 with its own rank.
The tests. A test is a statistic of \((X, y, w, e)\), and possibly of an
ordering of the observations or of the fitted values, with a null
distribution derived under the assumptions of the linear model. The glm
has the same \((X, y, w, e)\) and states the same model, normal errors
included, so the statistic, its null distribution and the p-value are the
same. That holds for a test whose code reads only those quantities, or the
quantities of the lm they equal, and never one a glm holds with another
value or not at all: summary(), whose result for a glm reports a
dispersion and no R-squared; $weights read as prior weights; the
deviance; the family. For the three tests:
| Test | Statistic and null distribution | What it reads | What had to change |
|---|---|---|---|
performHarrisonMcCabeTest() |
The share \(b\) of \(\sum_i \tilde e_i^2\) in the first \(m\) observations in the order of order_by, with \(\tilde e_i = \sqrt{w_i}\, e_i\); exact under normal errors of variance \(\sigma^2 / w_i\), from the residual-maker of \(\sqrt{w_i}\, x_i\) in that order. |
The Pearson residuals (the deviance residuals of the glm), model.matrix(), the prior weights, the ordering column. |
It read the weights with rprior_weights(), which returns none for a glm, so a weighted glm would have had the unweighted design under weighted residuals. It reads rleast_squares_weights(), the prior weights of an lm or of a Gaussian glm. |
performWhiteTestStreaming() |
\(n R^2\) of the regression of \(\tilde e_i^2\) on \(x_i\), their squares and cross products, accumulated in chunks; \(\chi^2\) under a constant variance (White, 1980). | The Pearson residuals; the model.matrix() of each chunk, from the terms, contrasts and xlevels of the fit, which a glm holds as an lm does. |
Nothing in the statistic. The checks it runs read the R-squared of summary(), which a glm does not report, and stopped on a glm with "missing value where TRUE/FALSE needed": that is why it refused every glm. They read the R-squared of the least-squares fit now (below). |
performVarianceFormTest() |
The F test of the added terms in the regression of the squared standardized residuals of the weighted refit on the score direction of the variance function, fitted to \(\log e_i^2\) of the unweighted fit (Wooldridge, 1990, 1991). | $residuals, which for a glm are its working residuals, \(y_i - \hat\mu_i\) for the identity link, the residuals of the lm; model.frame(), model.matrix(), model.offset(); the weights, to refuse those that did not come from fitWLS(). |
It read the weights with rprior_weights(), so it would have taken a weighted glm for an unweighted one. It reads rleast_squares_weights(), and refuses a weighted glm as it refuses a weighted lm. |
Once the glm is accepted, the code of the three reads none of its
dispersion, its QR decomposition, its working weights or its family. The
checks they run read its residual degrees of freedom, for a warning, which
are those of the lm, and compute the R-squared below with summary.lm(),
which reads its working residuals and weights: for this family and link,
the response residuals and the prior weights. The sources of the tests
define them for the linear
regression model fitted by least squares: White (1980) for the disturbances
of a linear regression model, Harrison and McCabe (1979) for ordinary
least-squares residuals, which Harrison (1981), whom the package follows,
restates, and Wooldridge (1990, 1991) for models of conditional means and
variances, of which the least-squares fit and its weighted refit are one. A
Gaussian glm with the identity link is that model, fitted by that
estimator; the weighted forms are the package's own, and apply to the glm
as to the lm.
The checks of the model. Every test refuses a near-perfect fit,
\(R^2 > 0.999\), with "Model appears perfectly explained". The checks read
\(R^2\) from summary(), which reports none for a glm, so until 0.16.0 a
near-perfect Gaussian glm escaped the refusal the same lm met, in 30
tests. They read the \(R^2\) of the least-squares fit now: for the glm,
summary.lm() applied to it, which reads its fitted values, residuals,
weights and offset, those of the lm, so it reports what summary() of the
lm reports, in every version of R. (Since R 4.3.0 summary.lm() takes the
offset out of the fitted values; before, it did not, and \(1 - D / D_0\), the
deviance of the glm over its null deviance, which takes it out, gave
another value for a model with an offset on R 4.1.) Five tests do not run the
check and give the lm and the glm a value: the spread-level, Pesaran,
Breusch-Pagan random effects, Davidian-Carroll and RESET tests.
fitWLS(). performVarianceFormTest() tests the variance function of a
fitWLS() fit, and refits any other model as fitWLS() would. fitWLS()
of a Gaussian glm is the lm that fitWLS() returns for the equivalent
lm, with the prior weights of a weighted glm recorded as the weights of
the model it refitted and the call of that lm, stats::lm() without the
arguments only glm() takes, so that update() fits an lm again. The test
gives the two the same value.
Prior weights of 1. A glm fitted with weights that are all 1 has the
prior.weights of a glm fitted without weights, as glm() records no
weights as weights of 1. Its model frame tells the two apart, as it holds a
(weights) column, which model.weights() reads, but the tests read the
weights of a glm from prior.weights (rleast_squares_weights()), so
they take it for an unweighted fit, where lm(..., weights = rep(1, n)) is a
weighted one. The two tests that refuse a weighted fit therefore accept the
glm and refuse the lm: performVarianceFormTest(), whose weights must
come from fitWLS(), since 0.16.0, when it accepts a Gaussian glm; and
performQuantileRegressionTest(), which refits without the weights, since
0.15.0. So does runHeteroTests() with tests = "variance_form", which
stops on the lm, and with tests = "quantile_regression", which falls
back on another test for the lm. bootstrapTestStatistic() refuses every
glm, so the two are not compared there. The behaviour is kept.
References:
- Green, P. J. (1984). Iteratively reweighted least squares for maximum likelihood estimation, and some robust and resistant alternatives. Journal of the Royal Statistical Society, Series B, 46(2), 149--192. doi:10.1111/j.2517-6161.1984.tb01288.x
- Harrison, M. J. (1981). A comparison of the bounds, beta-approximate, and exact variants of two tests for heteroscedasticity based on ordinary least squares residuals. The Economic and Social Review, 12(4), 235--252.
- Harrison, M. J., & McCabe, B. P. M. (1979). A test for heteroscedasticity based on ordinary least squares residuals. Journal of the American Statistical Association, 74(366a), 494--499. doi:10.1080/01621459.1979.10482544
- McCullagh, P., & Nelder, J. A. (1989). Generalized Linear Models (2nd ed.). Chapman & Hall. The section numbers and titles above are those of its table of contents.
- Nelder, J. A., & Wedderburn, R. W. M. (1972). Generalized linear models. Journal of the Royal Statistical Society, Series A, 135(3), 370--384. doi:10.2307/2344614
- White, H. (1980). A heteroskedasticity-consistent covariance matrix estimator and a direct test for heteroskedasticity. Econometrica, 48(4), 817--838. doi:10.2307/1912934
- Wooldridge, J. M. (1990). A unified approach to robust, regression-based specification tests. Econometric Theory, 6(1), 17--43. doi:10.1017/S0266466600004898
- Wooldridge, J. M. (1991). On the application of robust, regression-based diagnostics to models of conditional means and conditional variances. Journal of Econometrics, 47(1), 5--46. doi:10.1016/0304-4076(91)90076-P
The table¶
| Test | lm | lm, weights | lm, a zero weight | Gaussian glm | Gaussian glm, weights | Gaussian glm, a zero weight | binomial glm | Poisson glm | svyglm, Gaussian | svyglm, binomial | plm | rank-deficient lm | rank-deficient lm, weights | rank-deficient Gaussian glm | NA from an empty cell | MASS::rlm | fitWLS() | lm, offset = o | lm, + offset(o) | weighted lm, + offset(o) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
performWhiteTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performWhiteTestStreaming() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | error, as reduced | as today | yes | yes | yes | yes |
performWhiteTestRobust() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performBPTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performBPTestStreaming() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performBreuschPaganTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performBPTestRobust() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performGQTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performKoenkerTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performKoenkerTestStreaming() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performParkTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performStudentizedBPTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performWhiteTestBootstrap() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performSzroeterTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performHarrisonMcCabeTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performWildBootstrapTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performQuantileRegressionTest() |
yes | no: weighted | no: weighted | yes | no: weighted | no: weighted | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | no: weighted | yes | yes | no: weighted | no: weighted | yes | yes | no: weighted |
performRankPermutationTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performHighDimensionalTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performSpatialHeteroTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performSpearmanTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performLeveneTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performGlejserTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performBrownForsytheTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performFlignerKilleenTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performBartlettTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performHarveyTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performArchLMTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performMcLeodLiTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performHartleyFmaxTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performOBrienTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performCookWeisbergTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performNCVTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performSpreadLevelTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performPesaranTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performBPRandomEffectsTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performDavidianCarrollTest() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performVarianceFormTest() |
yes | no: not fitWLS() | no: not fitWLS() | yes | no: not fitWLS() | no: not fitWLS() | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | no: not fitWLS() | yes | yes | no: not fitWLS() | yes | yes | yes | no: not fitWLS() |
performRESETTest() |
yes | yes | yes | yes | yes | yes | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
performScatterDiagnostic() |
yes | yes | no: zero weight | yes | yes | no: zero weight | no: not least squares | no: not least squares | no: survey | no: survey | no: not lm | yes | yes | yes | yes | as today | yes | yes | yes | yes |
bootstrapTestStatistic() |
yes | yes | no: zero weight | no: any glm | no: any glm | no: any glm | no: any glm | no: any glm | no: any glm | no: any glm | no: not lm | yes | yes | no: any glm | yes | no: refit differs | yes | yes | yes | yes |
performBreuschPaganTest(), performStudentizedBPTest() and
rbootstrap_test_statistic() are deprecated names; bootstrapTestStatistic()
was given performKoenkerTest(). On MASS::rlm() the studentized
Breusch-Pagan statistic of performStudentizedBPTest() and of
performBPTestRobust() refits the design by least squares, so it tests the
least-squares fit (9.04 in this design, the value of the lm), where
performKoenkerTest() tests the residuals of the M-estimate (8.74).
The routes¶
The runners and the registry call the tests, and inherit what they refuse:
runHeteroTests()andrunDiagnostics()stop with the refusal of the first test.datawhose rows cannot be matched to the fit are refused with no fallback. Since 0.16.0 every fallback refuses what the test it stands in for refuses because of the model or the rows and variables ofdata, so no name holds a test computed regardless of them. A test refused for a reason of its own, such as the quantile regression test on a weighted fit, still falls back on another test under its name, taggedattr(, "extras")$status == "fallback"(an open decision for 1.0.0, in the roadmap).- The registry names,
cachedTest(),runHeteroTestsParallel()andtest_factory$run_test()call the same tests.test_factoryleaves a rank-deficient fit to a function of the package, whoever registered it, and refuses it, as before 0.16.0, for a function defined outside the package, such as one a user writes. runPanelTests()andrunTimeSeriesTests()refuse anything but anlmor aglmwith the message of the tests, then call them.runHeteroTests()tests a tidymodels workflow on the model frame of its engine's fit, withdata = NULL. Givendata, such as the data the workflow was fitted to, it refuses them when they lack the variables of that fit, which names its response..y, and says to passdata = NULL.runSurveyHeteroTests()fits the model by least squares to the data of a design, and is never given asvyglm()fit.runMultivariateTests()runs Box's M test on data and a grouping; a test of a model run through it is given the data in place of a model, and refuses them.checkModel()checks the class of a model only,lmorglm: it accepts every class in the table butplm.
Not covered¶
performVIFDiagnostic(), performInfluenceDiagnostics() and the plots are
diagnostics of the fit, not tests of its variance, and accept any lm or
glm.
Open decisions¶
MASS::rlm(): keep accepting it, as above, or refuse it as 0.15.0 refused aglmthat is not a least-squares fit. Deferred on 2026-10-17 to the work on the model context; it is accepted as before until then.