Aula de laboratório - Efeitos Fixos

Autor

Rafael Bressan

Data de Publicação

4 de outubro de 2023

Organizando dados em painel

\(y_{it}=\beta_0+\beta_1 x_{it}+v_{it};\) com \(t=1,\ldots , T\) e \(i=1,\ldots , n\). Denotamos \(nT=N\), o número total de observações do painel.

Dados em painel são melhor organizados no formato “longo” onde cada linha corresponde a uma combinação de \(i\) e \(t\). Nós temos de definir qual das variáveis corresponde a \(i\) e qual será representante de \(t\). Podemos fazer isso com o pacote plm.

library(plm)
library(fixest)
library(wooldridge)

data(crime4)

Os dados crime4 já estão organizados no formato longo, e possui as variáveis indicando o indivíduo (county) e o tempo (year). O painel é balanceado. Neste caso podemos transformar os dados em painel indicando estas colunas para o argumento index.

crime4_p <- pdata.frame(crime4, index = c("county", "year"))
pdim(crime4_p)
Balanced Panel: n = 90, T = 7, N = 630

Cálculos típicos de painel

Uma vez com os dados organizados em painel, o pacote plm fornece uma série de funções úteis para fazer as transformações que são típicas em econometria de dados em painel: lag, diferença, between e within.

crime4_p$cr_l <- plm::lag(crime4_p$crmrte) # Vários pacotes possuem `lag`
crime4_p$cr_d <- diff(crime4_p$crmrte) # Diff usa base
crime4_p$cr_B <- plm::Between(crime4_p$crmrte)
crime4_p$cr_W <- plm::Within(crime4_p$crmrte)

head(crime4_p[, c("county", "year", "crmrte", "cr_l", "cr_d", "cr_B", "cr_W")])
     county year    crmrte      cr_l         cr_d       cr_B          cr_W
1-81      1   81 0.0398849        NA           NA 0.03574136  0.0041435414
1-82      1   82 0.0383449 0.0398849 -0.001539998 0.03574136  0.0026035437
1-83      1   83 0.0303048 0.0383449 -0.008040100 0.03574136 -0.0054365567
1-84      1   84 0.0347259 0.0303048  0.004421100 0.03574136 -0.0010154567
1-85      1   85 0.0365730 0.0347259  0.001847100 0.03574136  0.0008316429
1-86      1   86 0.0347524 0.0365730 -0.001820602 0.03574136 -0.0009889587

Modelo em primeira diferença

Agora que temos um painel de dados devidamente organizados, podemos fazer uso destes dados para rodas as regressões. Começaremos com um modelo do efeito do desemprego na taxa de crimes.

data(crime2)
crime2_p <- pdata.frame(crime2, index = 46) # Balanceado com n=46, T=2
# Manualmente calcular as diferenças e fazer a regressão
crime2_p$dcrmrte <- diff(crime2_p$crmrte)
crime2_p$dunem <- diff(crime2_p$unem)
manual_reg <- lm(dcrmrte ~ dunem, data = crime2_p)
# Especificar um modelo em PD no `plm`
fd_reg <- plm(crmrte ~ unem, data = crime2_p, model = "fd")

Apresentando os resultados das regressões

modelsummary::msummary(list(manual_reg, fd_reg),
    gof_map = c("nobs", "r.squared")
)
 (1)   (2)
(Intercept) 15.402 15.402
(4.702) (4.702)
dunem 2.218
(0.878)
unem 2.218
(0.878)
Num.Obs. 46 46
R2 0.127 0.127

Efeitos Fixos

O estimador de efeito fixo estima os parâmetros através da transformação within e então faz uma regressão pooled sobre estes dados transformados. O pacote plm pode fazer a transformação e a regressão de uma só vez, ou podemos fazer manualmente.

data("wagepan")
wagepan_p <- pdata.frame(wagepan, index = c("nr", "year"))
pdim(wagepan_p)
Balanced Panel: n = 545, T = 8, N = 4360
# Usando plm
fe_plm <- plm(lwage ~ married + union + educ,
    data = wagepan_p,
    model = "within"
)
summary(fe_plm)
Oneway (individual) effect Within Model

Call:
plm(formula = lwage ~ married + union + educ, data = wagepan_p, 
    model = "within")

Balanced Panel: n = 545, T = 8, N = 4360

Residuals:
     Min.   1st Qu.    Median   3rd Qu.      Max. 
-4.116348 -0.137546  0.016979  0.180612  1.555540 

Coefficients:
        Estimate Std. Error t-value  Pr(>|t|)    
married 0.241684   0.017673 13.6750 < 2.2e-16 ***
union   0.070044   0.020724  3.3798 0.0007326 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Total Sum of Squares:    572.05
Residual Sum of Squares: 543.54
R-Squared:      0.049837
Adj. R-Squared: -0.086221
F-statistic: 99.9981 on 2 and 3813 DF, p-value: < 2.22e-16
# Manualmente
wagepan_p$wi_lwage <- Within(wagepan_p$lwage)
wagepan_p$wi_married <- Within(wagepan_p$married)
wagepan_p$wi_union <- Within(wagepan_p$union)
wagepan_p$wi_educ <- Within(wagepan_p$educ)

fe_lm <- lm(wi_lwage ~ wi_married + wi_union - 1,
    data = wagepan_p
)
summary(fe_lm)

Call:
lm(formula = wi_lwage ~ wi_married + wi_union - 1, data = wagepan_p)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.1163 -0.1375  0.0170  0.1806  1.5555 

Coefficients:
           Estimate Std. Error t value Pr(>|t|)    
wi_married  0.24168    0.01653  14.620  < 2e-16 ***
wi_union    0.07004    0.01938   3.613 0.000306 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.3532 on 4358 degrees of freedom
Multiple R-squared:  0.04984,   Adjusted R-squared:  0.0494 
F-statistic: 114.3 on 2 and 4358 DF,  p-value: < 2.2e-16

Efeitos fixos com fixest

fe_fix <- feols(lwage ~ married + union + educ | nr, data = wagepan)
The variable 'educ' has been removed because of collinearity (see $collin.var).
summary(fe_fix)
OLS estimation, Dep. Var.: lwage
Observations: 4,360 
Fixed-effects: nr: 545
Standard-errors: Clustered (nr) 
        Estimate Std. Error  t value  Pr(>|t|)    
married 0.241684   0.021992 10.98973 < 2.2e-16 ***
union   0.070044   0.025152  2.78482 0.0055422 ** 
... 1 variable was removed because of collinearity (educ)
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
RMSE: 0.353081     Adj. R2: 0.497484
                 Within R2: 0.049837

O fixest é muito útil pois pode fazer regressões com múltiplos efeitos fixos. Por exemplo, se quisermos utilizar um modelo para investigar a mudança dos retornos de educação no salário ao longo do tempo, supondo que exista heterogeneidade não-observada tanto no indivíduo, quanto no ano, podemos fazer a seguinte regressão.

fe_many <- feols(lwage ~ married + union + i(year, educ, ref = "1980") | nr + year,
    data = wagepan
)
summary(fe_many)
OLS estimation, Dep. Var.: lwage
Observations: 4,360 
Fixed-effects: nr: 545,  year: 8
Standard-errors: Clustered (nr) 
                Estimate Std. Error  t value   Pr(>|t|)    
married         0.054820   0.021209 2.584818 0.01000226 *  
union           0.082978   0.023036 3.602178 0.00034448 ***
year::1981:educ 0.011585   0.012199 0.949720 0.34267651    
year::1982:educ 0.014790   0.011795 1.253934 0.21040449    
year::1983:educ 0.017118   0.013086 1.308128 0.19138251    
year::1984:educ 0.016584   0.013844 1.197907 0.23147482    
year::1985:educ 0.023709   0.013590 1.744535 0.08163060 .  
year::1986:educ 0.027412   0.014732 1.860785 0.06331391 .  
year::1987:educ 0.030433   0.013500 2.254377 0.02456948 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
RMSE: 0.329841     Adj. R2: 0.559841
                 Within R2: 0.00989 

O pacote também produz gráficos para estas regressões com interações.

iplot(fe_many)

Comparando diversos modelos

Vamos usar os dados de salários para checar as variáveis constantes no tempo e constantes no indivíduo para o painel. Após, estimaremos modelos de MQO, Efeitos Aleatórios e Efeitos Fixos e investigar o modelo mais adequado.

pvar(wagepan_p)
no time variation:       nr black hisp educ wi_educ 
no individual variation: year d81 d82 d83 d84 d85 d86 d87 wi_educ 
# Converte year para factor
wagepan_p$year <- factor(wagepan_p$year)
# Faz as regressões
reg_ols <- plm(lwage ~ educ + black + hisp + exper + I(exper^2) + married + union + year,
    data = wagepan_p,
    model = "pooling"
)
reg_re <- plm(lwage ~ educ + black + hisp + exper + I(exper^2) + married + union + year,
    data = wagepan_p,
    model = "random"
)
reg_fe <- plm(lwage ~ exper + I(exper^2) + married + union + year,
    data = wagepan_p,
    model = "within"
)
# Show results
modelsummary::msummary(list(OLS = reg_ols, EA = reg_re, EF = reg_fe),
    coef_map = c(
        "educ", "black", "hisp", "exper",
        "I(exper^2)", "married", "union"
    )
)
OLS EA EF
educ 0.091 0.092
(0.005) (0.011)
black -0.139 -0.139
(0.024) (0.048)
hisp 0.016 0.022
(0.021) (0.043)
exper 0.067 0.106 0.132
(0.014) (0.015) (0.010)
I(exper^2) -0.002 -0.005 -0.005
(0.001) (0.001) (0.001)
married 0.108 0.064 0.047
(0.016) (0.017) (0.018)
union 0.182 0.106 0.080
(0.017) (0.018) (0.019)
Num.Obs. 4360 4360 4360
R2 0.189 0.181 0.181
R2 Adj. 0.187 0.178 0.061
AIC 5996.0 3283.7 2671.7
BIC 6098.1 3385.8 2741.9
RMSE 0.48 0.35 0.33

Teste de Hausman

Para escolher qual modelo utilizar é importante entender as hipóteses que cada um assume sobre a heterogeneidade não observada. O Pooled MQO assume inexistência de heterogeneidade, enquanto que o modelo de Efeitos Aleatórios assume que este heterogeneidade não está correlacionada com nenhum regressor. Ambas as hipóteses são pouco factíveis em inúmeros casos práticos e, portanto, o estimador de Efeito Fixo é muito utilizado pelos econometristas empíricos.

Ainda assim, se o pesquisador achar necessário, existe o teste formal de Haussman para decidir entre EA ou EF. O pacote plm implementa este teste com a função phtest.

phtest(reg_fe, reg_re)

    Hausman Test

data:  lwage ~ exper + I(exper^2) + married + union + year
chisq = 31.707, df = 10, p-value = 0.000448
alternative hypothesis: one model is inconsistent

Neste caso rejeitamos a H0 que ambos os modelos são consitentes. Como EF é sempre consistente dada a correta especificação, é o caso de rejeitarmos a hipótese de consistência do modelo EA. Portanto, neste caso, devemos utilizar o modelo de efeitos fixos.