Breusch–Pagan Test for Heteroscedasticity

I discuss the Breusch–Pagan test, a simple hypothesis test for heteroscedasticity in linear models. I also implement the test in Python and demonstrate that it can detect heteroscedasticity in a toy example.

At a high-level, various tests for heteroscedasticity in ordinary least squares (OLS) follow the same basic logic. The main idea is that the scedasticity of the OLS residuals will resemble the scedasticity of the true errors. This is because the OLS estimator is consistent (β^\hat{\boldsymbol{\beta}} converges in probability to β\boldsymbol{\beta}) regardless of scedasticity. Put differently, the proof that $\hat{\boldsymbol{\beta}}$ is consistent does not depend on the standard homoscedasticity assumption. Thus, any heteroscedasticity in the true error terms should be detectable in the residuals, which estimate the errors. These tests, then, are ultimately hypothesis tests applied to the OLS residuals (Greene, 2003).

The goal of this post is to understand a simple test for heteroscedasticity, the Breusch–Pagan test, which exemplifies this process. I’ll first discuss the main idea and then demonstrate the test on a toy problem.

Main idea

The basic idea of the Breusch–Pagan test is as follows. Suppose we run a linear regression,

yn=β0+βxn+εn,(1) y_n = \beta_0 + \boldsymbol{\beta}^{\top} \mathbf{x}_n + \varepsilon_n, \tag{1}

where we assume that each εn\varepsilon_n is identically and normally distributed with mean zero and variance one. Now let’s express the variance of each datum as a function of some function f()f(\cdot), which does not depend on nn:

σn2=f(α0+αxn).(2) \sigma_n^2 = f(\alpha_0 + \boldsymbol{\alpha}^{\top} \mathbf{x}_n). \tag{2}

Here, α=[α1αP]\boldsymbol{\alpha} = \begin{bmatrix} \alpha_1 & \dots & \alpha_P \end{bmatrix}^{\top} is a PP-vector of coefficients which are independent of the coefficients β\boldsymbol{\beta}. Why are we doing this? We’d like to test for heteroscedasticity. We can say that the null hypothesis is that the model has homoscedasticity, and this would require that

H0:α1=α2==αP=0.(3) \textsf{H}_0 : \alpha_1 = \alpha_2 = \dots = \alpha_P = 0. \tag{3}

In other words, if we have homoscedasticity, than the conditional variance of each error term would not depend on nn or xn\mathbf{x}_n, i.e.

V[εnX]=σn2=f(α0).(4) \mathbb{V}[\varepsilon_n \mid \mathbf{X}] = \sigma_n^2 = f(\alpha_0). \tag{4}

The null hypothesis (Equation 33) implies that σn2\sigma_n^2 is a constant.

So performing the Breusch–Pagan test amounts to the following: fit the linear model in Equation 11; estimate the error terms’ variances using the squared residuals; run a second regression to estimate α\boldsymbol{\alpha} in Equation 22; and finally check if α\boldsymbol{\alpha} is “close enough” to 0\mathbf{0}.

In detail

To make “close enough” a precise claim, we should perform a hypothesis test. To do that, we need to prove that some statistic of the regression implied by Equation 22 has a well-behaved distribution, such that we can compute pp-values. Proving this is the main result in (Breusch & Pagan, 1979).

To state Breusch and Pagan’s result, let ene_n denote the nn-th residual, the OLS estimate of εn\varepsilon_n. Now define the estimated residual variance as

σ^ε2=1Nn=1Nen2.(5) \hat{\sigma}_{\varepsilon}^2 = \frac{1}{N} \sum_{n=1}^N e_n^2. \tag{5}

This is just the residual sum of squares since ene_n has mean zero. Now define gng_n as

gn=en2σ^ε2.(6) g_n = \frac{e_n^2}{\hat{\sigma}_{\varepsilon}^2}. \tag{6}

In words, gng_n is the proportion of the residual variance that is explained by the nn-th sample. Now fit a linear regression with the original data X\mathbf{X} as the predictors and g=[g1gN]\mathbf{g} = \begin{bmatrix} g_1 & \dots & g_N \end{bmatrix}^{\top} as the response:

gn=α0+αxn+un.(7) g_n = \alpha_0 + \boldsymbol{\alpha}^{\top} \mathbf{x}_n + u_n. \tag{7}

Finally, compute the explained sum of squares from this second regression. Breusch and Pagan showed that, when the null hypothesis is true, one-half of this explained sum of squares is asymptotically distributed as χ2\chi^2 with (P1)(P-1) degrees of freedom.

Given that the response variables g\mathbf{g} should be mean centered, the explained sum of squares is just

n=1Ngng^n=gg^,(8) \sum_{n=1}^N g_n \hat{g}_n = \mathbf{g}^{\top} \hat{\mathbf{g}}, \tag{8}

where g^=Xα^\hat{\mathbf{g}} = \mathbf{X} \hat{\boldsymbol{\alpha}}. This means we can compute the desired quantity as

LM=12[gX(XX)1Xg].(9) \text{LM} = \frac{1}{2} \left[ \mathbf{g}^{\top} \mathbf{X} (\mathbf{X}^{\top} \mathbf{X})^{-1} \mathbf{X}^{\top} \mathbf{g} \right]. \tag{9}

since α^=(XX)1Xg\hat{\boldsymbol{\alpha}} = (\mathbf{X}^{\top} \mathbf{X})^{-1} \mathbf{X}^{\top} \mathbf{g}. This is traditionally denoted “LM” because the Breusch–Pagan test is a Lagrange multiplier test or score test.

To summarize, we simply run both regressions, compute LM\text{LM} in Equation 99, and then test the null hypothesis,

H0:LMχP12.(10) \textsf{H}_0 : \text{LM} \sim \chi_{P-1}^2. \tag{10}

We can then accept or reject the null hypothesis for our specific confidence level.

Example and implementation

In a previous post on OLS with heteroscedasticity, I gave a simple example of data on which OLS estimated incorrect tt-statistics.

from   numpy.random import RandomState
import statsmodels.api as sm

rng   = RandomState(seed=0)
x     = rng.randn(1000)
beta  = 0.01
noise = rng.randn(1000) + x*rng.randn(1000)
y     = beta * x + noise

ols = sm.OLS(y, x).fit()
print(f'{ols.params[0]:.4f}')   # beta  : -0.1634
print(f'{ols.tvalues[0]:.4f}')  # t-stat: -3.7863

Let’s revisited this example, and see if the Breusch–Pagan test can detect heteroscedasticity in advance. Here is a simple Python implementation of the test (for univariate data), fit using the OLS result and predictors in the example above:

from scipy.stats import chi2

def breusch_pagan(resid, x):
    g     = resid**2 / np.mean(resid**2)
    ols   = sm.OLS(g, sm.add_constant(x)).fit()
    beta  = ols.params[1]
    g_hat = x * beta
    lm    = 0.5 * g.T @ g_hat
    pval  = chi2(1).pdf(lm)
    return lm, pval

lm, pval = breusch_pagan(ols.resid, x)
print(f'{lm:.4f}')                    # 7.7365
print(f'{pval:.4f}')                  # 0.0030
print(f'Reject null? {pval < 0.05}')  # True

We can see that the Breusch–Pagan test rejects the null hypothesis of homoscedasticity using a 95%95\% confidence level (Figure 11).

Figure 1. The χP12\chi^2_{P-1} distribution (P=1)P = 1), along with the value of the Breusch–Pagan test statistic (Equation 99) for the example data (red dashed line). Since this test result is unlikely (pp-value of 3%3\%), we reject the null hypothesis of homoscedasticity.
  1. Greene, W. H. (2003). Econometric analysis. Pearson Education India.
  2. Breusch, T. S., & Pagan, A. R. (1979). A simple test for heteroscedasticity and random coefficient variation. Econometrica: Journal of the Econometric Society, 1287–1294.