在predict.lm()中使用聚类协方差矩阵

时间:2010-09-24 19:01:53

标签: r

我正在分析一个数据集,其中数据聚集在几个组(区域中的城镇)中。数据集如下所示:

R> df <- data.frame(x = rnorm(10), 
                     y = 3*rnorm(x), 
                     groups = factor(sample(c('0','1'), 10, TRUE)))
R> head(df)
        x     y groups
1 -0.8959  1.54      1
2 -0.1008 -2.73      1
3  0.4406  0.44      0
4  0.0683  1.62      1
5 -0.0037 -0.20      1
6 -0.8966 -2.34      0

我希望我的lm()估计值考虑到组内的类内相关性,为此我使用函数cl()来获取lm()并返回强健的聚类协方差矩阵(原始{{ 3}}):

cl  <- function(fm, cluster) {
  library(sandwich)
  M <- length(unique(cluster))   
  N <- length(cluster)              
  K <- fm$rank                   
  dfc <- (M/(M-1))*((N-1)/(N-K-1))
  uj  <- apply(estfun(fm), 2, function(x) tapply(x, cluster, sum));
  vcovCL <- dfc * sandwich(fm, meat = crossprod(uj)/N)
  return(vcovCL)
}

现在,

output <- lm(y ~ x, data = df)
clcov <- cl(output, df$groups)
coeftest(output, clcov, nrow(df) - 1)

给了我需要的估计。现在的问题是我想使用模型进行预测,我需要使用新的协方差矩阵clcov来计算预测的标准误差。也就是说,我需要

predict(output, se.fit = TRUE)

但使用clcov代替vcov(output)。像vcov() <-这样的东西是完美的。

当然,我可以编写自己的函数来做预测,但我只是想知道是否有更实用的方法允许我使用签名lm的方法(如arm :: sim)。 / p>

2 个答案:

答案 0 :(得分:5)

预测中的se.fit不是使用vcov矩阵计算的,而是使用qr分解和残差方差。这也适用于vcov()函数:它将来自summary.lm()的未缩放的cov矩阵与残差方差一起使用,并使用那些。并且,从QR分解再次计算未缩放的cov矩阵。

所以我担心答案是“不,除了编写自己的功能之外别无选择”。您无法真正设置vcov矩阵,因为它在需要时会重新计算。然而,编写自己的函数是相当微不足道的。

predict.rob <- function(x,clcov,newdata){
    if(missing(newdata)){ newdata <- x$model }
    m.mat <- model.matrix(x$terms,data=newdata)
    m.coef <- x$coef
    fit <- as.vector(m.mat %*% x$coef)
    se.fit <- sqrt(diag(m.mat%*%clcov%*%t(m.mat)))
    return(list(fit=fit,se.fit=se.fit))
}

我没有使用predict()函数来避免不必要的计算。无论如何,它不会过多地缩短代码。


另外,在stats.stackexchange.com

上可以更好地询问这样的问题

答案 1 :(得分:5)

我稍微修改了上面的代码,以便与预测函数更加一致 - 这样你就不会在newdata数据框中输入结果的值

predict.rob <- function(x,clcov,newdata){
if(missing(newdata)){ newdata <- x$model }
tt <- terms(x)
Terms <- delete.response(tt)
m.mat <- model.matrix(Terms,data=newdata)
m.coef <- x$coef
fit <- as.vector(m.mat %*% x$coef)
se.fit <- sqrt(diag(m.mat%*%clcov%*%t(m.mat)))
return(list(fit=fit,se.fit=se.fit))}