Clustering di errori standard in R (manualmente o in plm)


33

Sto cercando di capire l'errore standard "clustering" e come eseguire in R (è banale in Stata). Nel RI non hanno avuto successo usando plmo scrivendo la mia funzione. Userò i diamondsdati dalggplot2 pacchetto.

Posso fare effetti fissi con entrambe le variabili fittizie

> 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 

o per de-significando entrambi i lati sinistro e destro (qui non ci sono regressori invarianti di tempo) e correggendo i gradi di libertà.

> # 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 

Non posso replicare questi risultati con plm, perché non ho un indice "time" (cioè, questo non è in realtà un pannello, solo cluster che potrebbero avere una propensione comune nei loro termini di errore).

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

Ho anche cercato di codice mia matrice di covarianza con errore standard cluster utilizzando spiegazione Stata della loro clusteropzione ( spiegato qui ), che è quello di risolvere V c l u s t e r = ( X ' X ) - 1 ( n c Σ j = 1 u j u j ) ( X X ) - 1 dove u j = c l u s

V^cluSter=(X'X)-1(Σj=1ncuj'uj)(X'X)-1
, n c si il numero di cluster, e i è il residuo per l'osservazione i t h e x i è il vettore di riga dei predittori, inclusa la costante (questo appare anche come equazione (7.22 ) nellasezione trasversale e nei dati del panel diWooldridge). Ma il codice seguente fornisce matrici di covarianza molto grandi. Questi valori molto grandi sono dati dal numero limitato di cluster che ho? Dato che non riescoa fare cluster su un fattore, non sono sicuro di come confrontare il mio codice.uj=ΣcluSter jeio*XionceioiothXioplm
> # 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

Questo può essere fatto in R? È una tecnica abbastanza comune in econometria (c'è un breve tutorial in questa lezione ), ma non riesco a capirlo in R. Grazie!


7
@ricardh, maledici tutti gli economisti per non aver verificato se il termine che vogliono usare sia già usato nelle statistiche. Cluster in questo contesto significa gruppo ed è totalmente estraneo all'analisi dei cluster, ecco perché rseek ti ha dato risultati non correlati. Quindi ho rimosso il tag di clustering. Per l'analisi dei dati del pannello, consultare il pacchetto plm . Ha una bella vignetta, quindi potresti trovare quello che vuoi. Per quanto riguarda la tua domanda non è chiaro cosa vuoi. All'interno degli errori standard del gruppo?
mpiktas,

@ricardh, sarebbe di grande aiuto se potessi collegarti ad un manuale di Stata in cui questa clusteropzione è spiegata. Sono sicuro che sarebbe possibile replicare in R.
mpiktas il

2
+1 per quel commento. gli economisti colonizzano la terminologia come un matto. Anche se a volte è difficile scegliere il cattivo. Ii ha impiegato un po 'di tempo, ad esempio fino a quando ho capito che factornon aveva nulla a che fare con, factanalma si riferisce a variabili classificate. Comunque il cluster in R si riferisce all'analisi del cluster, k- mean è solo IL metodo di partizionamento: statmethods.net/advstats/cluster.html . Non capisco la tua domanda, ma immagino anche che il cluster non abbia nulla a che fare con esso.
hans0l0,

@mpiktas, @ ran2 - Grazie! Spero di aver chiarito la domanda. In breve, perché esiste il "clustering di errori standard" se si tratta solo di effetti fissi, che esistevano già?
Richard Herron,

1
La funzione cluster.vcov nel pacchetto "multiwayvcov" fa quello che stai cercando.

Risposte:


29

Per gli errori bianchi standard raggruppati per gruppo con il plmframework provare

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

dove model.plm un modello plm.

Vedi anche questo link

http://www.inside-r.org/packages/cran/plm/docs/vcovHC o la documentazione del pacchetto plm

MODIFICARE:

Per il clustering bidirezionale (ad es. Gruppo e ora), consultare il seguente collegamento:

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

Ecco un'altra utile guida per il pacchetto plm che spiega specificamente le diverse opzioni per gli errori standard cluster:

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

Il clustering e altre informazioni, in particolare per Stata, sono disponibili qui:

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

MODIFICA 2:

Ecco alcuni esempi che mettono a confronto R e stata: http://www.richard-bluhm.com/clustered-ses-in-r-and-stata-2/

Inoltre, multiwayvcovpotrebbe essere utile. Questo post offre una panoramica utile: http://rforpublichealth.blogspot.dk/2014/10/easy-clustered-standard-errors-in-r.html

Dalla documentazione:

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)

per me coeftest(model.plm, vcov=vcovHC(model.plm,type="HC0")) oltre a coeftest(model.plm, vcov=vcovHC(model.plm,type="HC0",cluster="group"))produrre risultati identici. Sai perché è così?
Peter Pan,

1
Il link people.su.se/~ma/clustering.pdf non funziona più. Ti ricordi il titolo della pagina?
MERose

8

Dopo molte letture, ho trovato la soluzione per fare il clustering all'interno del lmframework.

C'è un eccellente white paper di Mahmood Arai che fornisce un tutorial sul clustering nel lmframework, che fa con correzioni del grado di libertà invece dei miei disordinati tentativi sopra. Egli fornisce le sue funzioni per entrambe le matrici di covarianza il clustering una e due vie qui .

Infine, anche se il contenuto non è disponibile gratuitamente, Angrist e di Pischke Mostly Harmless Econometria ha una sezione sul clustering che è stato molto utile.


Aggiornamento il 27/04/2015 per aggiungere il codice dal post del blog .

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.

1
Il documento di Arai non è più online. Potete fornire il link effettivo?
MERose,

@MERose - Siamo spiacenti! Purtroppo non possiamo allegare pdf! Ho trovato questo post sul blog che confronta il codice. Modificherò questa risposta per includere il codice.
Richard Herron,

Questo potrebbe essere una versione aggiornata del white paper: Mahmood Arai, Cluster-errori standard robusti che utilizzano R .
gung - Ripristina Monica

4

Il modo più semplice per calcolare gli errori standard cluster in R è utilizzare la funzione di riepilogo modificata.

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

C'è un eccellente post sul clustering all'interno del framework lm. Il sito fornisce anche la funzione di riepilogo modificata per il clustering a una o due vie. Puoi trovare la funzione e il tutorial qui .


1

Se non hai un timeindice, non ne hai bisogno: plmne aggiungerà uno fittizio da solo e non verrà utilizzato se non lo chiedi. Quindi questa chiamata dovrebbe funzionare :

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

Solo che non lo fa, il che suggerisce che hai riscontrato un bug plm. (Questo bug è stato risolto in SVN. È possibile installare la versione di sviluppo da qui .)

Ma dato che questo sarebbe timecomunque un indice fittizio , possiamo crearlo da soli:

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

Ora funziona:

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

Nota importante : vcovHC.plm()in plmstima per impostazione predefinita Arellano raggruppato per gruppo SE. Che è diverso da quello che vcovHC.lm()in sandwichvaluterà (ad esempio le vcovHCSE nella domanda iniziale), che è SE eteroschedasticità coerente senza il clustering.


Un approccio separato a questo è attenersi alle lmregressioni variabili fittizie e al pacchetto 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

In entrambi i casi otterrai gli Arellano (1987) SE con raggruppamento per gruppo. Ilmultiwayvcov pacchetto è un'evoluzione diretta e significativa delle funzioni di clustering originali di Arai.

Puoi anche osservare la matrice di varianza-covarianza risultante da entrambi gli approcci, producendo la stessa stima di varianza per 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 

Si prega di vedere questo link: multiwayvcov è ammortizzato: sites.google.com/site/npgraham1/research/code
HoneyBuddha
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.