Robust Standard Errors

Dr. Lucy D’Agostino McGowan

What are Robust Standard Errors?

The Problem: Standard OLS assumes homoskedasticity (constant variance)

\[\text{Var}(\varepsilon_i | X) = \sigma^2 \text{ for all } i\]

Reality: Often \(\text{Var}(\varepsilon_i | X) = \sigma_i^2\) varies across observations

Solution: Heteroskedasticity-robust standard errors (also called “sandwich” or “Huber-White” standard errors) remain valid even when variances differ

The Problem: Heteroskedasticity

What is Heteroskedasticity?

Heteroskedasticity: The variance of errors depends on \(X\) \[\text{Var}(\varepsilon_i | X_i) = \sigma_i^2 \neq \sigma^2\]

Visualizing Heteroskedasticity

Right panel: The spread increases as X increases

Why Does Heteroskedasticity Matter?

Good news: OLS estimator \(\hat{\beta}\) is still unbiased and consistent

Bad news: The usual standard error formula is wrong!

Standard OLS variance formula assumes: \[\text{Var}(\hat{\beta}) = \sigma^2(X^TX)^{-1}\]

Problem: This formula assumes constant \(\sigma^2\), but we have varying \(\sigma_i^2\)

Consequences of Using Wrong SE

Using standard SEs with heteroskedasticity leads to:

  1. Invalid hypothesis tests (wrong p-values)
  2. Invalid confidence intervals (wrong coverage)
  3. Misleading inference (false positives or negatives)

The coefficient is fine, but we can’t trust our uncertainty estimates!

The Solution: Robust Standard Errors

The Correct Variance Formula

With heteroskedasticity, the true variance of \(\hat{\beta}\) is: \[\text{Var}(\hat{\beta}) = (X^TX)^{-1} \left(\sum_{i=1}^n X_i X_i^T \sigma_i^2\right) (X^TX)^{-1}\]

Problem: We don’t know the true \(\sigma_i^2\)

Solution: Estimate each \(\sigma_i^2\) with the squared residual \(\hat{\varepsilon}_i^2\)

The Sandwich Estimator

Robust variance estimator (HC0): \[\widehat{\text{Var}}(\hat{\beta}) = (X^TX)^{-1} \left(\sum_{i=1}^n X_i X_i^T \hat{\varepsilon}_i^2\right) (X^TX)^{-1}\]

The Sandwich Estimator

Called the “sandwich” because of its structure: \[\underbrace{(X^TX)^{-1}}_{\text{bread}} \underbrace{\left(\sum X_i X_i^T \hat{\varepsilon}_i^2\right)}_{\text{meat}} \underbrace{(X^TX)^{-1}}_{\text{bread}}\]

Why “Robust”?

This estimator is robust to heteroskedasticity:

  • If errors are homoskedastic: Robust SE ≈ Standard SE (asymptotically)
  • If errors are heteroskedastic: Robust SE is correct, Standard SE is wrong

Big picture: Robust SEs work whether or not you have heteroskedasticity

Variants of Robust Standard Errors

Several versions exist, with different finite-sample adjustments:

HC0 (Original): \(\widehat{\text{Var}}(\hat{\beta}) = (X^TX)^{-1} \sum X_i X_i^T \hat{\varepsilon}_i^2 (X^TX)^{-1}\)

HC1: Multiply by \(\frac{n}{n-k}\) for degrees of freedom

HC2: Weight by \((1-h_{ii})^{-1}\) where \(h_{ii}\) is leverage

HC3: Weight by \((1-h_{ii})^{-2}\) (more conservative)

In practice: Use HC1 or HC3; differences usually small with large \(n\)

Computing Robust Standard Errors in R

# Generate heteroskedastic data
set.seed(1)
n <- 100
x <- runif(n, 0, 10)
y <- 2 + 3*x + rnorm(n, sd = 0.5 + 0.4*x)

# Fit OLS
model <- lm(y ~ x)

# Standard SEs
summary(model)$coefficients
            Estimate Std. Error   t value    Pr(>|t|)
(Intercept) 1.702826 0.56627540  3.007063 3.35136e-03
x           3.065759 0.09725122 31.524122 4.23507e-53
# Robust SEs (need sandwich package)
library(sandwich)
library(lmtest)

coeftest(model, vcov = vcovHC(model, type = "HC1"))

t test of coefficients:

            Estimate Std. Error t value  Pr(>|t|)    
(Intercept)  1.70283    0.39848  4.2733 4.469e-05 ***
x            3.06576    0.10096 30.3647 < 2.2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Comparing Standard vs Robust SEs

# Create comparison
standard_se <- summary(model)$coefficients[2, 2]
robust_se <- sqrt(vcovHC(model, type = "HC1")[2, 2])

data.frame(
  Type = c("Standard", "Robust"),
  SE = c(standard_se, robust_se),
  Ratio = c(1, robust_se/standard_se)
)
      Type         SE    Ratio
1 Standard 0.09725122 1.000000
2   Robust 0.10096455 1.038183

In this example: Robust SE is larger (standard SE underestimates uncertainty)

Alternative: Weighted Least Squares (WLS)

What is WLS?

Idea: If we know the variance structure, we can use it to get more efficient estimates

Suppose we know \(\text{Var}(\varepsilon_i | X_i) = \sigma^2 w_i\) for known weights \(w_i\)

WLS: Transform the model by \(1/\sqrt{w_i}\): \[\frac{y_i}{\sqrt{w_i}} = \frac{X_i}{\sqrt{w_i}}\beta + \frac{\varepsilon_i}{\sqrt{w_i}}\]

Result: Transformed errors have constant variance!

WLS Estimator

WLS minimizes weighted sum of squared residuals: \[\hat{\beta}_{WLS} = \arg\min_\beta \sum_{i=1}^n \frac{1}{w_i}(y_i - X_i\beta)^2\]

Solution: \[\hat{\beta}_{WLS} = (X^TW^{-1}X)^{-1}X^TW^{-1}y\] where \(W = \text{diag}(w_1, \ldots, w_n)\)

Properties of WLS

When weights are correct (\(w_i = \sigma_i^2/\sigma^2\)):

  1. \(\hat{\beta}_{WLS}\) is unbiased
  2. \(\hat{\beta}_{WLS}\) is BLUE (Best Linear Unbiased Estimator)
  3. \(\hat{\beta}_{WLS}\) is more efficient than OLS
  4. Standard SEs are valid (no need for robust SEs)

WLS Example

# True weights (in practice, we'd need to estimate these)
true_weights <- (0.5 + 0.4*x)^2

# Fit WLS
model_wls <- lm(y ~ x, weights = 1/true_weights)

# Compare coefficients
data.frame(
  Method = c("OLS", "WLS"),
  Coefficient = c(coef(model)[2], coef(model_wls)[2]),
  SE = c(summary(model)$coefficients[2, 2],
         summary(model_wls)$coefficients[2, 2])
)
  Method Coefficient         SE
1    OLS    3.065759 0.09725122
2    WLS    3.045419 0.07054892

WLS has smaller standard error (more efficient)

Comparing WLS and Robust SEs

Approach 1: WLS with Correct Weights

Setup: Use WLS with correct weights \(w_i = \sigma_i^2/\sigma^2\)

Advantages:

  • Most efficient estimator (smallest variance among unbiased estimators).
  • Standard inference procedures are valid.
  • No need for robust SEs

Approach 1: WLS with Correct Weights

Setup: Use WLS with correct weights \(w_i = \sigma_i^2/\sigma^2\)

Requirements:

  • Must know the correct weights
  • Weights must be correctly specified

Approach 2: OLS with Robust SEs

Setup: Use OLS and compute robust standard errors

Advantages:

  • Don’t need to know variance structure
  • More flexible (works with any heteroskedasticity pattern).
  • Robust to weight misspecification

Approach 2: OLS with Robust SEs

Setup: Use OLS and compute robust standard errors

Disadvantage:

  • Less efficient than WLS (larger variance)

Efficiency Comparison

Which estimator has smaller variance?

WLS with correct weights has smaller variance than OLS

Simulation: Efficiency Comparison

# Simulation to compare variances
set.seed(1)
n_sim <- 1000
n <- 100

beta_ols <- numeric(n_sim)
beta_wls <- numeric(n_sim)

for(i in 1:n_sim) {
  x <- runif(n, 0, 10)
  w <- (0.5 + 0.4*x)^2
  y <- 2 + 3*x + rnorm(n, sd = sqrt(w))
  
  beta_ols[i] <- coef(lm(y ~ x))[2]
  beta_wls[i] <- coef(lm(y ~ x, weights = 1/w))[2]
}

# Compare variances
data.frame(
  Method = c("OLS", "WLS"),
  Mean = c(mean(beta_ols), mean(beta_wls)),
  Variance = c(var(beta_ols), var(beta_wls)),
  Efficiency = c(1, var(beta_ols)/var(beta_wls))
)
  Method     Mean    Variance Efficiency
1    OLS 3.003783 0.011435733    1.00000
2    WLS 3.002931 0.005519922    2.07172

Visualizing the Efficiency Gain

WLS distribution is tighter (has smaller variance)

When is Inference Valid?

Validity of WLS Inference

WLS inference is valid when:

  1. Weights are correctly specified: \(w_i = \sigma_i^2/\sigma^2\) exactly
  2. Other assumptions hold: Linearity, independence, etc.

Problem: If weights are wrong, WLS inference is invalid

Validity of WLS Inference

Example: Using \(w_i = x_i\) when true variance is \(\sigma_i^2 = \exp(x_i)\)

  • WLS estimator is still consistent but not efficient
  • Standard errors are wrong
  • Hypothesis tests maybe wrong

When Weights Are Wrong

# True variance structure: exponential in x
set.seed(1)
x <- runif(100, 0, 2)
true_var <- exp(x)
y <- 2 + 3*x + rnorm(100, sd = sqrt(true_var))

# Wrong weights: linear in x
wrong_weights <- x

# Fit WLS with wrong weights
model_wrong_wls <- lm(y ~ x, weights = 1/wrong_weights)

# Standard SEs are wrong!
summary(model_wrong_wls)$coefficients
            Estimate Std. Error   t value     Pr(>|t|)
(Intercept) 1.609030  0.1725209  9.326583 3.504868e-15
x           3.383816  0.2432085 13.913230 6.153096e-25

These standard errors are not reliable because weights are misspecified

Validity of Robust SE Inference

Robust SE inference is valid when:

  1. Large sample size: Robust SEs are asymptotically valid
  2. Correct model specification: Need correct \(E[Y|X]\)
  3. Independence: Observations are independent
  4. No severe leverage points: Extreme \(X\) values can cause problems

Key advantage: Don’t need to know variance structure!

Asymptotic Validity

Important caveat: Robust SEs are asymptotically valid

  • Need “large enough” sample size
  • Can underestimate uncertainty in small samples
  • Various corrections (HC2, HC3) help with small samples

Why Prefer Robust SEs Despite Lower Efficiency?

Reason 1: Unknown Variance Structure

In practice, we rarely know the true weights!

Problem with WLS:

  • Need to model \(\sigma_i^2\) as function of \(X\)
  • If model is wrong, inference is invalid
  • Hard to know if model is correct

Reason 1: Unknown Variance Structure

In practice, we rarely know the true weights!

Robust SEs:

  • No need to model variance structure
  • Valid for any heteroskedasticity pattern

Example: Modeling the Variance

Suppose we think variance depends on \(x\), so we try: \[\sigma_i^2 = \exp(\alpha_0 + \alpha_1 x_i)\]

Steps to implement WLS:

  1. Fit OLS and get residuals \(\hat{\varepsilon}_i\)
  2. Regress \(\log(\hat{\varepsilon}_i^2)\) on \(x\) to estimate \(\alpha_0, \alpha_1\)
  3. Compute weights \(\hat{w}_i = \exp(\hat{\alpha}_0 + \hat{\alpha}_1 x_i)\)
  4. Fit WLS using these weights

Reason 2: Robustness to Misspecification

Robust SEs protect against model misspecification

WLS with wrong weights:

  • Estimator still consistent
  • But SEs are wrong
  • Tests have wrong size.
  • CIs have wrong coverage

Reason 2: Robustness to Misspecification

Robust SEs protect against model misspecification

OLS with robust SEs:

  • If variance model is wrong, no problem!
  • Inference still valid (asymptotically)

Simulation: Misspecified Weights

# Simulation: coverage of confidence intervals
set.seed(1)
n_sim <- 1000
n <- 100
coverage_wls_wrong <- 0
coverage_robust <- 0

for(i in 1:n_sim) {
  x <- runif(n, 0, 2)
  true_var <- exp(x)  # True variance
  y <- 2 + 3*x + rnorm(n, sd = sqrt(true_var))
  
  # WLS with wrong weights (linear instead of exponential)
  wrong_weights <- x
  model_wls <- lm(y ~ x, weights = 1/wrong_weights)
  ci_wls <- confint(model_wls)[2,]
  coverage_wls_wrong <- coverage_wls_wrong + (ci_wls[1] <= 3 & ci_wls[2] >= 3)
  
  # OLS with robust SEs
  model_ols <- lm(y ~ x)
  se_robust <- sqrt(vcovHC(model_ols, type = "HC1")[2,2])
  ci_robust <- coef(model_ols)[2] + c(-1.96, 1.96) * se_robust
  coverage_robust <- coverage_robust + (ci_robust[1] <= 3 & ci_robust[2] >= 3)
}

data.frame(
  Method = c("WLS (wrong weights)", "OLS + Robust SE"),
  Coverage = c(coverage_wls_wrong/n_sim, coverage_robust/n_sim),
  Target = c(0.95, 0.95)
)
                   Method Coverage Target
2.5 % WLS (wrong weights)    0.715   0.95
          OLS + Robust SE    0.929   0.95

WLS with wrong weights: Coverage far from 95%! Robust SEs: Coverage close to nominal level

Reason 3: Simplicity and Transparency

Robust SEs are simpler:

  • No need to specify variance model
  • Fewer modeling choices

WLS requires:

  • Choosing functional form for variance
  • Estimating variance model
  • Potential for specification error

Reason 4: Avoid Optimization Over SE

Researcher degrees of freedom:

With WLS, researchers might:

  • Try different variance models.
  • Pick the one that gives desired results.
  • “Optimize” standard errors

Robust SEs prevent this:

  • One standard approach
  • Less flexibility for p-hacking
  • More credible inference

When Might You Prefer WLS?

Despite the advantages of robust SEs, use WLS when:

  1. You truly know the weights (e.g., aggregated data with known group sizes)
  2. Efficiency is critical (small sample, need every bit of precision)
  3. Variance structure is simple and obvious (e.g., repeated measurements)

Example: Survey data with known sampling weights