R中的标准错误聚类(手动或在plm中)

机器算法验证 r 面板数据 标准错误 固定效应模型 聚集标准错误
2022-02-08 15:31:01

我试图了解标准错误“聚类”以及如何在 R 中执行(在 Stata 中这很简单)。plm在 RI 中使用或编写我自己的函数均未成功。我将使用包中的diamonds数据ggplot2

我可以用任何一个虚拟变量做固定效果

> library(plyr)
> library(ggplot2)
> library(lmtest)
> library(sandwich)
> # with dummies to create fixed effects
> fe.lsdv <- lm(price ~ carat + factor(cut) + 0, data = diamonds)
> ct.lsdv <- coeftest(fe.lsdv, vcov. = vcovHC)
> ct.lsdv

t test of coefficients:

                      Estimate Std. Error  t value  Pr(>|t|)    
carat                 7871.082     24.892  316.207 < 2.2e-16 ***
factor(cut)Fair      -3875.470     51.190  -75.707 < 2.2e-16 ***
factor(cut)Good      -2755.138     26.570 -103.692 < 2.2e-16 ***
factor(cut)Very Good -2365.334     20.548 -115.111 < 2.2e-16 ***
factor(cut)Premium   -2436.393     21.172 -115.075 < 2.2e-16 ***
factor(cut)Ideal     -2074.546     16.092 -128.920 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 

或者通过对左侧和右侧进行去意义(这里没有时间不变的回归器)并校正自由度。

> # by demeaning with degrees of freedom correction
> diamonds <- ddply(diamonds, .(cut), transform, price.dm = price - mean(price), carat.dm = carat  .... [TRUNCATED] 
> fe.dm <- lm(price.dm ~ carat.dm + 0, data = diamonds)
> ct.dm <- coeftest(fe.dm, vcov. = vcovHC, df = nrow(diamonds) - 1 - 5)
> ct.dm

t test of coefficients:

         Estimate Std. Error t value  Pr(>|t|)    
carat.dm 7871.082     24.888  316.26 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 

我无法用 复制这些结果plm,因为我没有“时间”索引(即,这不是真正的面板,只是可能在错误术语中有共同偏差的集群)。

> plm.temp <- plm(price ~ carat, data = diamonds, index = "cut")
duplicate couples (time-id)
Error in pdim.default(index[[1]], index[[2]]) : 

cluster我还尝试使用 Stata 对其选项的解释(在此处解释)使用聚类标准误差编写自己的协方差矩阵,即解决其中 , si 聚类数,是残差对于第观察,是预测变量的行向量,包括常数(这也显示为 Wooldridge横截面和面板数据中的方程(7.22)

V^cluster=(XX)1(j=1ncujuj)(XX)1
uj=cluster jeixinceiithxi)。但是下面的代码给出了非常大的协方差矩阵。考虑到我拥有的集群数量很少,这些值是否非常大?鉴于我无法plm在一个因素上进行集群,我不确定如何对我的代码进行基准测试。

> # with cluster robust se
> lm.temp <- lm(price ~ carat + factor(cut) + 0, data = diamonds)
> 
> # using the model that Stata uses
> stata.clustering <- function(x, clu, res) {
+     x <- as.matrix(x)
+     clu <- as.vector(clu)
+     res <- as.vector(res)
+     fac <- unique(clu)
+     num.fac <- length(fac)
+     num.reg <- ncol(x)
+     u <- matrix(NA, nrow = num.fac, ncol = num.reg)
+     meat <- matrix(NA, nrow = num.reg, ncol = num.reg)
+     
+     # outer terms (X'X)^-1
+     outer <- solve(t(x) %*% x)
+ 
+     # inner term sum_j u_j'u_j where u_j = sum_i e_i * x_i
+     for (i in seq(num.fac)) {
+         index.loop <- clu == fac[i]
+         res.loop <- res[index.loop]
+         x.loop <- x[clu == fac[i], ]
+         u[i, ] <- as.vector(colSums(res.loop * x.loop))
+     }
+     inner <- t(u) %*% u
+ 
+     # 
+     V <- outer %*% inner %*% outer
+     return(V)
+ }
> x.temp <- data.frame(const = 1, diamonds[, "carat"])
> summary(lm.temp)

Call:
lm(formula = price ~ carat + factor(cut) + 0, data = diamonds)

Residuals:
     Min       1Q   Median       3Q      Max 
-17540.7   -791.6    -37.6    522.1  12721.4 

Coefficients:
                     Estimate Std. Error t value Pr(>|t|)    
carat                 7871.08      13.98   563.0   <2e-16 ***
factor(cut)Fair      -3875.47      40.41   -95.9   <2e-16 ***
factor(cut)Good      -2755.14      24.63  -111.9   <2e-16 ***
factor(cut)Very Good -2365.33      17.78  -133.0   <2e-16 ***
factor(cut)Premium   -2436.39      17.92  -136.0   <2e-16 ***
factor(cut)Ideal     -2074.55      14.23  -145.8   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 

Residual standard error: 1511 on 53934 degrees of freedom
Multiple R-squared: 0.9272, Adjusted R-squared: 0.9272 
F-statistic: 1.145e+05 on 6 and 53934 DF,  p-value: < 2.2e-16 

> stata.clustering(x = x.temp, clu = diamonds$cut, res = lm.temp$residuals)
                        const diamonds....carat..
const                11352.64           -14227.44
diamonds....carat.. -14227.44            17830.22

这可以在R中完成吗?这是计量经济学中相当常见的技术(本讲座中有一个简短的教程),但我无法在 R 中弄清楚它。谢谢!

4个回答

截至 2021 年 12 月的编辑

现在在 R 中获取聚集标准错误的最简单方法可能是通过包中的felm函数lfe或包中的feols函数fixest

原始答案和一些后续编辑

对于使用plm框架按组聚类的 White 标准错误,请尝试

coeftest(model.plm, vcov=vcovHC(model.plm,type="HC0",cluster="group"))

model.plmplm 模型在哪里。

另请参阅此链接

http://www.inside-r.org/packages/cran/plm/docs/vcovHC或 plm 包文档

编辑:

对于双向聚类(例如组和时间),请参见以下链接:

http://people.su.se/~ma/clustering.pdf

这是 plm 包的另一个有用指南,专门解释了聚集标准错误的不同选项:

http://www.princeton.edu/~otorres/Panel101R.pdf

集群和其他信息,尤其是关于 Stata 的信息,可以在这里找到:

http://www.kellogg.northwestern.edu/faculty/petersen/htm/papers/se/se_programming.htm

编辑2:

以下是比较 R 和 stata 的示例:http ://www.richard-bluhm.com/clustered-ses-in-r-and-stata-2/

此外,这multiwayvcov可能会有所帮助。这篇文章提供了一个有用的概述:http ://rforpublichealth.blogspot.dk/2014/10/easy-clustered-standard-errors-in-r.html

从文档中:

library(multiwayvcov)
library(lmtest)
data(petersen)
m1 <- lm(y ~ x, data = petersen)

# Cluster by firm
vcov_firm <- cluster.vcov(m1, petersen$firmid)
coeftest(m1, vcov_firm)
# Cluster by year
vcov_year <- cluster.vcov(m1, petersen$year)
coeftest(m1, vcov_year)
# Cluster by year using a formula
vcov_year_formula <- cluster.vcov(m1, ~ year)
coeftest(m1, vcov_year_formula)

# Double cluster by firm and year
vcov_both <- cluster.vcov(m1, cbind(petersen$firmid, petersen$year))
coeftest(m1, vcov_both)
# Double cluster by firm and year using a formula
vcov_both_formula <- cluster.vcov(m1, ~ firmid + year)
coeftest(m1, vcov_both_formula)

经过大量阅读,我找到了在lm框架内进行集群的解决方案。

Mahmood Arai有一篇出色的白皮书,其中提供了有关lm框架中聚类的教程,他使用自由度校正而不是我上面的混乱尝试。他在这里为单向和双向聚类协方差矩阵提供了他的函数

最后,虽然内容不是免费提供的,但Angrist 和 Pischke 的Mostly Harmless Econometrics中有一个关于聚类的部分非常有用。


2015 年 4 月 27 日更新以添加博客文章中的代码。

api=read.csv("api.csv") #create the variable api from the corresponding csv
attach(api) # attach of data.frame objects
api1=api[c(1:6,8:310),] # one missing entry in row nr. 7
modell.api=lm(API00 ~ GROWTH + EMER + YR_RND, data=api1) # creation of a simple linear model for API00 using the regressors Growth, Emer and Yr_rnd.

##creation of the function according to Arai:
clx <- function(fm, dfcw, cluster) {
    library(sandwich)
    library(lmtest)
    library(zoo)
    M <- length(unique(cluster))
    N <- length(cluster)
    dfc <- (M/(M-1))*((N-1)/(N-fm$rank)) # anpassung der freiheitsgrade
    u <- apply(estfun(fm),2, function(x) tapply(x, cluster, sum))
    vcovCL <-dfc * sandwich (fm, meat = crossprod(u)/N) * dfcw
    coeftest(fm, vcovCL)
}

clx(modell.api, 1, api1$DNUM) #creation of results.

在 R 中计算聚类标准误的最简单方法是使用修改后的汇总函数。

lm.object <- lm(y ~ x, data = data)
summary(lm.object, cluster=c("c"))

在 lm 框架内有一篇关于集群的优秀文章。该站点还为单向和双向聚类提供了修改后的摘要功能。你可以在这里找到函数和教程

如果您没有time索引,则不需要:plm将自己添加一个虚构的索引,除非您要求,否则不会使用它。所以这个电话应该有效

> x <- plm(price ~ carat, data = diamonds, index = "cut")
 Error in pdim.default(index[[1]], index[[2]]) : 
  duplicate couples (time-id) 

除了它没有,这表明你遇到了plm. (此错误现已在 SVN 中修复。您可以从此处安装开发版本。)

但既然这无论如何都是一个虚构的time索引,我们可以自己创建它:

diamonds$ftime <- 1:NROW(diamonds)  ##fake time

现在这有效:

x <- plm(price ~ carat, data = diamonds, index = c("cut", "ftime"))
coeftest(x, vcov.=vcovHC)
## 
## t test of coefficients:
## 
##       Estimate Std. Error t value  Pr(>|t|)    
## carat  7871.08     138.44  56.856 < 2.2e-16 ***
## ---
## Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

重要提示:默认情况下vcovHC.plm()plm将估计由 SE 组聚类的 Arellano。不同于估计的内容(例如原始问题中的vcovHC.lm()SE ),即没有聚类的异方差一致的 SE。 sandwichvcovHC


一个单独的方法是坚持lm虚拟变量回归和multiwayvcov包。

library("multiwayvcov")
fe.lsdv <- lm(price ~ carat + factor(cut) + 0, data = diamonds)
coeftest(fe.lsdv, vcov.= function(y) cluster.vcov(y, ~ cut, df_correction = FALSE))
## 
## t test of coefficients:
## 
##                      Estimate Std. Error t value  Pr(>|t|)    
## carat                 7871.08     138.44  56.856 < 2.2e-16 ***
## factor(cut)Fair      -3875.47     144.83 -26.759 < 2.2e-16 ***
## factor(cut)Good      -2755.14     117.56 -23.436 < 2.2e-16 ***
## factor(cut)Very Good -2365.33     111.63 -21.188 < 2.2e-16 ***
## factor(cut)Premium   -2436.39     123.48 -19.731 < 2.2e-16 ***
## factor(cut)Ideal     -2074.55      97.30 -21.321 < 2.2e-16 ***
## ---
## Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

在这两种情况下,您都会得到按组聚类的 Arellano (1987) SE。multiwayvcov软件包是 Arai 原始聚类功能的直接且重要的演变。

您还可以查看两种方法生成的方差-协方差矩阵,得出相同的方差估计carat

vcov.plm <- vcovHC(x)
vcov.lsdv <- cluster.vcov(fe.lsdv, ~ cut, df_correction = FALSE)
vcov.plm
##          carat
## carat 19165.28
diag(vcov.lsdv)
##                carat      factor(cut)Fair      factor(cut)Good factor(cut)Very Good   factor(cut)Premium     factor(cut)Ideal 
##            19165.283            20974.522            13820.365            12462.243            15247.584             9467.263