I need heteroscedasticity robust standard errors for a multivariate linear model (MLM) with weights. In R we usually use sandwich::vcovHC
with type "HC0"
to get the White variance-covariance matrix. But while this works for univariate models with weights or MLMs without weights, it doesn't seem to support MLMs with weights.
Example
fit1 <- lm(cbind(X1, X2) ~ . - w, dat)
sandwich::vcovHC(fit1, type='HC0') ## unweighted MLM, works
fit2 <- lm(cbind(X1, X2) ~ . - w, dat, weights=w)
sandwich::vcovHC(fit2, type='HC0') ## weighted MLM, fails
# Error in SSD.mlm(object) : 'mlm' objects with weights are not supported
However, since it does work for the weighted univariate case,
fit31 <- lm(X1 ~ . - X2 - w, dat, weights=w)
lmtest::coeftest(fit31, sandwich::vcovHC(fit31, type='HC0'))
fit32 <- lm(X2 ~ . - X1 - w, dat, weights=w)
lmtest::coeftest(fit32, sandwich::vcovHC(fit32, type='HC0'))
there should be an easy way to implement this for MLMs.
In the source code, the error boils down to computing the "matrix of residual sums of squares and products."
stats:::SSD.mlm(fit2)
# Error in stats:::SSD.mlm(fit2) :
# 'mlm' objects with weights are not supported
Statistics
stats:::SSD.mlm
essentially calculates crossprod(object$residuals)
―the crossproduct of the residuals,
$$r = Y - \hat{Y}\quad (1)$$
$$SSD=r'r \quad(2)$$
but it is obviously programmed to stop if there are weights in the MLM object.
I don't understand why sandwich:::vcovHC.mlm
was not implemented for MLMs with weights, since it was possible for MLMs without weights. Do I assume correctly that it would not be sufficient to simply adapt equation (2) for the case with weights, because that would have been too easy to implement?
So my question is, how can we adapt the code, or which equations do we need to adapt the code for MLMs?
A solution would be very valuable because we could compute robust errors for tens of thousands of regressions at once instead of running a loop for hours.
Data:
set.seed(42); n <- 2 + 2; m <- 10
dat <- data.frame(matrix(rnorm(m*n), m, n))
dat$w <- runif(nrow(dat))