Skip to content

Bootstrap White test

Source: R/additional_tests.R · Help: ?performWhiteTestBootstrap

Approximates the finite-sample distribution of White's LM statistic by resampling the fitted residuals, refitting the model, and recalculating the test statistic across many bootstrap replications.

Usage

performWhiteTestBootstrap(
  model,
  data = NULL,
  B = 999,
  parallel = FALSE,
  n_cores = NULL,
  reestimate_weights = NULL
)

Arguments

model
A fitted stats::lm object representing the mean specification to be diagnosed.
data
A base::data.frame (or object coercible to one) containing the variables referenced by model. It must include the observations used to fit model and will be checked for missing values. When NULL, the default, the model frame of model is used. It holds the terms of the model rather than its variables (log(x) rather than x), so a model that transforms a variable needs data, as does a model with an offset() term, and so may a fit whose weights or offset argument is a column of the data, which the model frame holds as (weights) or (offset).
B
Integer scalar giving the number of bootstrap replications. Defaults to 999. The p-value is (1 + #) / (B_eff + 1), where B_eff is the number of replicates whose statistic is finite (B when every replicate succeeds), so a test at level alpha is exact only when alpha * (B_eff + 1) is an integer: with 999 it is at the 5% and 1% levels, and with 1000, the default before 0.15.0, at neither.
parallel
Logical scalar; if TRUE the replicates are computed in parallel, by forked workers (parallel::mclapply()) where the platform can fork and on a socket cluster (parallel::makeCluster()) elsewhere. See Parallel replicates.
n_cores
Optional integer number of worker processes when parallel = TRUE. Defaults to parallel::detectCores() - 1. The result does not depend on it.
reestimate_weights
Whether each replicate estimates the weights of a fitWLS() fit again from the variance function fitWLS() recorded on it. NULL, the default, does so for a fitWLS() fit and holds the weights fixed for any other model. FALSE holds them fixed, as every call did before 0.15.0. TRUE is an error for a model that fitWLS() did not return, or on which it fell back to equal weights. Each replicate regenerates the response and holds the design fixed, so a variance regressor that uses a variable of the response which the right-hand side of the model does not use, such as y or x for I(y / x) ~ z, or that is the response term itself, as ~ . gives, cannot be estimated again: NULL then holds the weights fixed, with a warning, and TRUE is an error. Giving the response as a column of the data, as in r ~ z, says which variables stay. See Weighted fits.

Value

A htest object reporting both the asymptotic White statistic and its bootstrap p-value. The returned object also stores the simulated test statistics in boot_statistics for further inspection.

Details

For a fitted model \(\hat{y} = X\hat{\beta}\), the algorithm proceeds as follows:

  1. Compute White's LM statistic \(n R^2\) from the auxiliary regression on squares and cross-products of the regressors.
  2. Generate \(B\) bootstrap samples by resampling the centred residuals with replacement, forming \(y^{*(b)} = \hat{y} + \hat{e}^{*(b)}\).
  3. Refit the model to each bootstrap sample and recompute White's statistic \(T^{*(b)}\) using the same auxiliary specification.
  4. Estimate the bootstrap p-value as \(\hat{p} = (1 + \sum_{b} I\{T^{*(b)} \ge T_{\text{obs}}\}) / (B_{\text{eff}} + 1)\), where \(b\) runs over the \(B_{\text{eff}}\) replicates whose statistic is finite, so the p-value is never zero.

The bootstrap distribution offers improved size control for moderate sample sizes or high-dimensional designs where the chi-squared approximation may be inaccurate. When parallel = TRUE the resampling step exploits available CPU cores to reduce computation time.

Parallel replicates

With parallel = TRUE replicate i draws its random numbers from stream i of a L'Ecuyer-CMRG generator (parallel::nextRNGStream()), seeded by one number drawn from the session's generator. A call made after set.seed() therefore returns the same result each time, whatever the number of workers and whether they are forked or run on a socket cluster. It does not return the result of the same call with parallel = FALSE, which draws every replicate from the session's generator, as it did before 0.15.0: the two are bootstraps of the same data with different draws, and each is valid. Before 0.15.0 a seeded call with parallel = TRUE gave a different result each time, and on Windows more than one worker was an error.

Weighted fits

A fit with weights \(w_i\) is ordinary least squares on \(\sqrt{w_i}\, y_i\) and \(\sqrt{w_i}\, x_i\), whose errors have constant variance under the null hypothesis, and the bootstrap is carried out in that regression. What is resampled is its residuals, the Pearson residuals \(\sqrt{w_i}\, e_i\). When the model has an intercept they are centred, as the residuals of an unweighted fit with an intercept are, because the weighted regression has no constant column. Each draw is divided by \(\sqrt{w_i}\) to return it to the scale of the observation it is added to, and each replicate is refitted with the weights, so performWhiteTest() computes its statistic from the Pearson residuals as it does for the fit supplied. With equal weights the result is that of the unweighted fit.

Weighted or not, each replicate is refitted with an offset the model was given as an argument, lm(..., offset = o); an offset written in the formula, offset(o), is evaluated again from the data of the replicate. A transformed response, such as log(y) in log(y) ~ x, is regenerated on the scale the model uses, and the refit reads it in place of log(y).

Weights given to the fit are known, and they are held fixed in every replicate. On a fit returned by fitWLS() they were estimated from the same data, and since 0.15.0 they are estimated again in each replicate by default (reestimate_weights): the replicate is fitted as the model fitWLS() was given, the variance function fitWLS() recorded is fitted again to its residuals, on the same regressors and with the same form, and the replicate is refitted with the weights it gives, so that performWhiteTest() sees a fitWLS() fit of the replicate. A replicate whose variance function cannot be fitted, where fitWLS() would fall back to equal weights, counts as a failed replicate, and the p-value is computed from the replicates that remain; a warning gives the number that failed.

In inst/validation/weighted-fits-size.R, the data have standard deviation \(\exp(0.3 x)\), the variance function is correctly specified, the errors are normal, there are 150 observations and B = 499. At the 5% level the test then rejected 0.064 of the time when it held the weights of fitWLS() fixed, as every call did before 0.15.0 and reestimate_weights = FALSE still does. It rejected 0.0415 when it estimated them again, just below the release gate's interval, 0.042 to 0.058, and 0.054 with the true weights. The section on weighted fits in performWildBootstrapTest() has the larger error of Koenker's statistic.

References

Efron, B., & Tibshirani, R. J. (1993). An Introduction to the Bootstrap. Chapman & Hall/CRC.

Davidson, R., & MacKinnon, J. G. (2006). The power of bootstrap and asymptotic tests. Journal of Econometrics, 133(2), 421–441. doi:10.1016/j.jeconom.2005.02.002

See also

performWhiteTest() for the classical statistic and performWhiteTestRobust() for enriched diagnostics.

Examples

# The bootstrap needs at least 50 observations, so mtcars (32) is too small.
set.seed(42)
n <- 120
sim <- data.frame(x = runif(n, 1, 5))
sim$y <- 1 + 2 * sim$x + rnorm(n, sd = 0.3 + 0.6 * sim$x)
mod <- lm(y ~ x, data = sim)
performWhiteTestBootstrap(mod, sim, B = 199)


# More replications give a smoother p-value estimate
performWhiteTestBootstrap(mod, sim, B = 499)

# parallel = TRUE runs the replicates on n_cores workers, forked where the
# platform can fork and on a socket cluster elsewhere. Two is the most
# R CMD check --as-cran allows, and the result does not depend on it.
set.seed(42)
performWhiteTestBootstrap(mod, sim, B = 199, parallel = TRUE, n_cores = 2)