library(dplyr)library(readr)library(stringr)library(ggplot2)library(tidyr)library(sjlabelled)library(ggrepel)library(scales)library(ggpubr)library(plm)library(lmtest)library(sjPlot)library(DT)library(magrittr)library(foreign)library(dataverse)library(Synth) # Pacotes especificos para a última análise#install.packages("remotes")#remotes::install_github("kylebutts/did2s")library(did2s)
2 Exemplo 1: Replicação de Card e Krueger (1994)
O estudo tem como objetivo identificar o efeito do aumento do salário-mínimo nos empregos. A hipótese levantada pela literatura é que um aumento no salário-mínimo leva a um aumento do desemprego. A partir de um desenho quase-experimental com uso de DiD, Card e Krueger (1994) demonstraram o contrário, que o aumento do salário-mínimo levou a uma redução do desemprego. Em 1992, o estado americano de Nova Jersey (NJ) aumentou o salário-mínimo de $4,25 para $5,05 por hora, abrindo espaço para testar a teoria. Como controle, os pesquisadores utilizaram o estado vizinho da Pennsylvania (PA), em que não houve alteração na política. Foram conduzidos surveys em ambos os estados antes e depois da aplicação da política em NJ, sendo representativo dos restaurantes de fast-food. Vale destacar que esse desenho é um quase-experimento pois as unidades não são iguais e o tratamento não foi aplicado de forma aleatória.
O primeiro passo para a análise é limpar e transformar os dados. O banco de dados foi baixado diretamente do site dos autores e transformado em um formato necessário para realizar as análises em DiD. O formato final do banco é estruturado da seguinte forma:
Code
# Criar arquivo e diretório temporáriotfile_path <-tempfile()tdir_path <-tempdir()# Download zip filedownload.file("http://davidcard.berkeley.edu/data_sets/njmin.zip", destfile = tfile_path)# Unzipunzip(tfile_path, exdir = tdir_path)# Ler o codebookcodebook <-read_lines(file =paste0(tdir_path, "/codebook"))# Criando um vetor com o nome das variáveisvariable_names <- codebook %>%`[`(8:59) %>%# Nome das variáveis a partir do elemento 8 (planilha)`[`(-c(5, 6, 13, 14, 32, 33)) %>%# Removendo elementos sem nome de variáveisstr_sub(1, 8) %>%# Selecionando apenas as variáveis com 8 elementosstr_squish() %>%# Removendo espaço em brancostr_to_lower() # Transformando todos os nomes em letras minusculas# Criando um vetor com o nome das variáveisvariable_labels <- codebook %>%`[`(8:59) %>%# Nome das variáveis a partir do elemento 8 (planilha)`[`(-c(5, 6, 13, 14, 32, 33)) %>%# Removendo elementos sem nome de variáveissub(".*\\.[0-9]", "", .) %>%`[`(-c(5:10)) %>%# Elementos que serão combinadosstr_squish() # Removendo espaço em branco# Regiãovariable_labels[41] <-"region of restaurant"# Lendo os dados "cru"data_raw <-read_table2(paste0(tdir_path, "/public.dat"),col_names =FALSE)# Adicionando o nome das variáveisdata_mod <- data_raw %>%select(-X47) %>%# Removendo colunas vazias`colnames<-`(., variable_names) %>%# Nomeando as variáveismutate_all(as.numeric) %>%# Tratar todas as variáveis como númericasmutate(sheet =ifelse(sheet ==407& chain ==4, 408, sheet)) # Duplicando o id 407# Dados processados em formato widedata_mod <- data_mod %>%# Label dos valores de chain mutate(chain =case_when(chain ==1~"bk", chain ==2~"kfc", chain ==3~"roys", chain ==4~"wendys")) %>%# Label dos valores de statemutate(state =case_when(state ==1~"New Jersey", state ==0~"Pennsylvania")) %>%# Dummy de regiãomutate(region =case_when(southj ==1~"southj", centralj ==1~"centralj", northj ==1~"northj", shore ==1~"shorej", pa1 ==1~"phillypa", pa2 ==1~"eastonpa")) %>%# Label dos valores de mealsmutate(meals =case_when(meals ==0~"none", meals ==1~"free meals", meals ==2~"reduced price meals", meals ==3~"both free and reduced price meals")) %>%# Label dos valores de meals2mutate(meals2 =case_when(meals2 ==0~"none", meals2 ==1~"free meals", meals2 ==2~"reduced price meals", meals2 ==3~"both free and reduced price meals")) %>%# Label dos valores de status2 mutate(status2 =case_when(status2 ==0~"refused second interview", status2 ==1~"answered 2nd interview", status2 ==2~"closed for renovations", status2 ==3~"closed permanently", status2 ==4~"closed for highway construction", status2 ==5~"closed due to Mall fire")) %>%mutate(co_owned =if_else(co_owned ==1, "yes", "no")) %>%mutate(bonus =if_else(bonus ==1, "yes", "no")) %>%mutate(special2 =if_else(special2 ==1, "yes", "no")) %>%mutate(type2 =if_else(type2 ==1, "phone", "personal")) %>%select(-southj, -centralj, -northj, -shore, -pa1, -pa2) %>%# Incluindo dummies de regiãomutate(date2 = lubridate::mdy(date2)) %>%# Convertendo a datarename(open2 = open2r) %>%# Inserindo nome da onda 1rename(firstinc2 = firstin2) %>%# Inserindo nome da onda 1 sjlabelled::set_label(variable_labels) # Adicionando as labels guardadas# Variáveis estruturaisstructure <- data_mod %>%select(sheet, chain, co_owned, state, region)# Variáveis da onda 1wave1 <- data_mod %>%select(-ends_with("2"), -names(structure)) %>%mutate(observation ="February 1992") %>%bind_cols(structure) # Variáveis da onda 2wave2 <- data_mod %>%select(ends_with("2")) %>%rename_all(~str_remove(., "2")) %>%mutate(observation ="November 1992") %>%bind_cols(structure) # Banco de dados finalcard_krueger_1994 <-bind_rows(wave1, wave2) %>%select(sort(names(.))) %>%# Ordenando as colunas por ordem alfabética sjlabelled::copy_labels(data_mod) # Restaurando a label das variáveiscard_krueger_1994_mod <- card_krueger_1994 %>%mutate(emptot = empft + nmgrs +0.5* emppt,pct_fte = empft / emptot *100) |>select(c(observation, state, emptot, everything()))set.seed(12361)sample_n(card_krueger_1994_mod, 5) |>tab_df(title ="Estrutura do banco")
Estrutura do banco
observation
state
emptot
bonus
chain
co_owned
date
empft
emppt
firstinc
hrsopen
inctime
meals
ncalls
nmgrs
nregs
nregs11
open
pctaff
pentree
pfry
psoda
region
sheet
special
status
type
wage_st
pct_fte
November 1992
New Jersey
22.50
NA
wendys
no
1992-11-17
10
17
0.13
12.50
14
reduced price meals
1
4
2
2
10.50
NA
1.05
0.98
1.05
northj
165
no
answered 2nd interview
phone
5.05
44.44
February 1992
Pennsylvania
20.50
yes
roys
yes
NA
10
15
0.17
16.00
13
reduced price meals
0
3
5
3
6.00
0
0.73
0.90
1.05
eastonpa
496
NA
NA
NA
5.00
48.78
February 1992
New Jersey
24.00
no
roys
no
NA
10
20
NA
12.50
26
none
0
4
5
3
9.00
NA
NA
NA
NA
centralj
135
NA
NA
NA
NA
41.67
February 1992
New Jersey
25.50
no
roys
yes
NA
15
15
NA
17.00
17
reduced price meals
0
3
4
4
6.00
NA
1.06
NA
1.02
northj
306
NA
NA
NA
NA
58.82
February 1992
New Jersey
6.50
no
kfc
no
NA
0
7
0.75
12.00
NA
both free and reduced price meals
1
3
3
2
11.00
40
2.45
1.06
1.06
northj
73
NA
NA
NA
4.25
0.00
Nesse caso, nossa variável de tempo é \(observation\), nossa variável que especifica o estado é \(state\) e nossa variável dependente é \(emptot\). Para argumentar a existencia de tendencias paralelas, os autores utilizam a distribuição de salários dentro de fast foods pelos estados. Os histogramas a seguir mostram o percentual de restaurantes por valor do valor de sálario em ambos os estados estudados:
Code
hist.feb <- card_krueger_1994_mod %>%filter(observation =="February 1992") %>%ggplot(aes(wage_st, fill = state)) +geom_histogram(aes(y=c(..count..[..group..==1]/sum(..count..[..group..==1]), ..count..[..group..==2]/sum(..count..[..group..==2]))*100),alpha=0.5, position ="dodge", bins =23) +labs(title ="Fevereiro 1992", x="Distribuição do salário", y ="Percentual de restaurantes", fill ="") +scale_fill_grey()hist.nov <- card_krueger_1994_mod %>%filter(observation =="November 1992") %>%ggplot(aes(wage_st, fill = state)) +geom_histogram(aes(y=c(..count..[..group..==1]/sum(..count..[..group..==1]), ..count..[..group..==2]/sum(..count..[..group..==2]))*100),alpha =0.5, position ="dodge", bins =23) +labs(title ="Novembro 1992", x="Distribuição do salário", y ="Percentual de restaurantes", fill="") +scale_fill_grey()ggarrange(hist.feb, hist.nov, ncol =2, common.legend =TRUE, legend ="bottom")
Antes de usar uma abordagem de DiD com modelos de regressão OLS, podemos tentar calcular a diferença das diferenças nas médias a partir de uma abordagem de First Differences (FD). Assim, o ATT (Avarage Treatment Effect) é obtido subtraindo as médias do grupo tratamento antes e depois da intervenção pelas médias do grupo controle antes e depois da intervenção.
# Calculando as médias pelo grupodifferences <- card_krueger_1994_mod %>%group_by(observation, state) %>%summarise(emptot =mean(emptot, na.rm =TRUE))# Grupo tratado (NJ) antes do tratamentonjfeb <- differences[1,3]# Grupo controle (PA) antes do tratamentopafeb <- differences[2,3]# Grupo tratado (NJ) depois do tratamentonjnov <- differences[3,3]# Grupo controle (PA) depois do tratamentopanov <- differences[4,3]# Calculando o ATTATT <- (njnov-njfeb)-(panov-pafeb)print(paste("ATT = ", round(ATT, 3)))
[1] "ATT = 2.754"
Assim, o efeito causal apontado pelo calculo de DiD a partir de FD é de um aumento de 2,754 pontos no emprego. Plotando visualmente:
Code
# Calculando o outcome do contrafactualnj_counterfactual <-tibble(observation =c("February 1992","November 1992"), state =c("New Jersey (Counterfactual)","New Jersey (Counterfactual)"),emptot =as.numeric(c(njfeb, njfeb-(pafeb-panov))) ) # Pontos para a ocorrência da intevençãointervention <-tibble(observation =c("Intervention", "Intervention", "Intervention"),state =c("New Jersey", "Pennsylvania", "New Jersey (Counterfactual)"),emptot =c(19.35, 22.3, 19.35) ) # Unindo os bancosdid_plotdata <-bind_rows(differences, nj_counterfactual, intervention)# Plotdid_plotdata %>%mutate(label =if_else(observation =="November 1992", as.character(state), NA_character_)) %>%ggplot(aes(x=observation,y=emptot, group=state)) +geom_line(aes(color=state), size=1.2) +geom_vline(xintercept ="Intervention", linetype="dotted", color ="black", size=1.1) +scale_color_brewer(palette ="Accent") +scale_y_continuous(limits =c(17,24)) + ggrepel::geom_label_repel(aes(label = label),nudge_x =0.5, nudge_y =-0.5,na.rm =TRUE) +guides(color=FALSE) +labs(x="", y="FTE Employment (mean)") +annotate("text",x ="November 1992",y =19.6,label ="{Difference-in-Differences}",angle =90,size =3 )+theme_bw()
Agora, estimaremos este modelo por meio de uma regressão OLS simples: \[Y = \beta_0 + \beta_1 Time + \beta_2 Treated + \beta (Time \times Treated) +\epsilon\]
Code
# Criando as dummies de tempo e tratamentocard_krueger_1994_mod <-mutate(card_krueger_1994_mod,time =ifelse(observation =="November 1992", 1, 0),treated =ifelse(state =="New Jersey", 1, 0) )# Estimando o modelo OLSdid_model <-lm(emptot ~ time + treated + time:treated, data = card_krueger_1994_mod)did_model|>tab_model()
#full-time employees
Predictors
Estimates
CI
p
(Intercept)
23.33
21.23 – 25.44
<0.001
time
-2.17
-5.14 – 0.81
0.154
treated
-2.89
-5.23 – -0.55
0.016
time × treated
2.75
-0.56 – 6.07
0.103
Observations
794
R2 / R2 adjusted
0.007 / 0.004
O modelo aponta que o ATT do aumento do salário mínimo é de um aumento de 2,75, contudo, o resultado não é estatisticamente significante. Contudo, devemos avaliar se os dados estão corretamente estimados por meio de testes, a fim de avaliar se o modelo deve incorporar efeitos fixos ou aleatórios e o uso de erros robustos devido a heterosedasticidade. Primeiramente, vamos testar se devemos usar um modelo de Efeitos Fixos por meio de um teste F:
Code
# Defindo os dados em painelpanel <-pdata.frame(card_krueger_1994_mod, "sheet")# Construindo o modelo within (Efeitos Fixos)EF <-plm(emptot ~ time + treated + time:treated, data = panel, model ="within")# Construindo o modelo pooled (Equivalente a OLS)PO <-plm(emptot ~ time + treated + time:treated, data = panel,model ="pooling")# Teste F, lembrar que EF vem sempre primeiropFtest(EF,PO)
F test for individual effects
data: emptot ~ time + treated + time:treated
F = 3.3237, df1 = 408, df2 = 382, p-value < 2.2e-16
alternative hypothesis: significant effects
O teste aponta para a existencia de efeitos específicos, \(\alpha_i\), logo, devemos utilizar um modelo de efeitos fixos ou aleatórios. Para definir qual dos dois modelos, realizaremos o teste de Hausman
Code
# Construindo o modelo random (Efeitos Aleatórios)EA <-plm(emptot ~ time + treated + time:treated, data = panel,model ="random")# Teste de Hausman, lembrar que EF vem sempre primeirophtest(EF,EA)
Hausman Test
data: emptot ~ time + treated + time:treated
chisq = 0.63463, df = 2, p-value = 0.7281
alternative hypothesis: one model is inconsistent
O resultado aponta para o uso de Efeitos Fixos no lugar de Efeitos Aleatórios. Não precisamos testar efeitos de tempo, pois o painel é composto por apenas dois pontos no tempo que são capturados pelo tempo. Assim, estimamos o modelo com Efeitos Fixos:
Code
EF |>tab_model()
emptot
Predictors
Estimates
CI
p
time [2]
-2.28
-4.32 – -0.25
0.028
time [2] × treated
2.75
0.48 – 5.02
0.018
Observations
794
R2 / R2 adjusted
0.015 / -1.045
Observamos que houve uma redução dos erros padrões, que agora apontam significancia estatistica para o resultado. Agora avaliaremos se existe heterocedasticidade nos resultados. Podemos fazer isso pela análise gráfica:
Code
plot <-tibble(fitted(EF),resid(EF))ggplot(data = plot, aes(x =`fitted(EF)`, y =`resid(EF)`^2)) +geom_point() +labs(title ="Resíduos ao quadrado") +geom_smooth(method ="loess", se =FALSE)+theme_bw()
A análise visual aponta para a existencia de heterocedasticidade nos dados. Vamos conduzir um teste de Breusch-Pagan para avaliar se isso se confirma:
Code
bptest(EF, studentize=F)
Breusch-Pagan test
data: EF
BP = 15.526, df = 3, p-value = 0.001418
Confirmando a análise gráfica, o teste aponta para a existência de heterocedasticidade dos dados. Assim, aplicaremos uma matrix de correção de Arellano para obter os erros padrões robustos.
Code
# Obtendo os erros padrões robustosARL <-vcovHC(EF, method ="arellano")EF.ARL <- EF; EF.ARL$vcov <- ARLtab_model(EF, EF.ARL,dv.labels =c("Modelo sem erros padrões robustos","Modelo com erros padrões robustos"), show.se = T,show.ci = F,digits =4)
Modelo sem erros padrões robustos
Modelo com erros padrões robustos
Predictors
Estimates
std. Error
p
Estimates
std. Error
p
time [2]
-2.2833
1.0355
0.028
-2.2833
1.2449
0.067
time [2] × treated
2.7500
1.1544
0.018
2.7500
1.3342
0.040
Observations
794
794
R2 / R2 adjusted
0.015 / -1.045
0.015 / -1.045
Assim, estimamos o efeito do tratamento com os erros padrões corretos, indicando significancia estatística a um p-valor menor que 0,05. Nesse modelo, contudo não é possível testar a existência de tendências paralelas por termos apenas dois períodos no tempo.
3 Exemplo 2: Replicação de Fraser et al (2020)
O segundo exemplo foca em como o processo de organização social impacta a emissão de gás carbono. A teoria aponta que o aumento da organização social levaria a uma redução na emissão de gás carbono. Assim, o estudo mobilizou dados de diferentes cidades na região de Tóquio, avaliando sua capacidade de organização social e a classificando em alta (1) e baixa (0). Assim, utilizaremos a DiD para estimar o efeito ao longo do tempo. A base de dados a ser utilizada segue a seguinte estrutura:
Code
#Limpando os arquivos do exemplo anteriorrm(list=ls())# Carregando os dadosSys.setenv("DATAVERSE_SERVER"="dataverse.harvard.edu")# Importando o banco de dados do Havard Dataversedat <-get_dataframe_by_name(filename ="dataset.tab",dataset ="10.7910/DVN/E8PEW7")# Limpando as cidadesdat <- dat %>%# Selecionando apenas as cidades na região de Tokyofilter(pref =="Tokyo") %>%# Calculando a emissão de carbono em kilotons por 1000 residentesmutate(emissions = emissions / pop *1000) %>%# Calculando a densidade populacionalmutate(pop_density = pop / area_inhabitable) %>%# Criando uma contagem anual de 1, 2, 3, 4, etc.mutate(counter = year -min(year)) %>%# Criando um tratamento se a cidade é ou foi uma cidade com alta capacidade e a contando como tratada pelo resto do periodomutate(treat =if_else(fin_str_index >median(fin_str_index), 1, NA_real_)) %>%group_by(muni_code) %>%fill(treat, .direction ="up") %>%mutate(treat =if_else(is.na(treat), 0, treat)) %>%ungroup() %>%# Garantidno um fator para efeitos fixosmutate(year =factor(year),muni_code =factor(muni_code)) %>%# Selecionando apenas as variáveis de interesse:select( muni, # nome do município muni_code, # código único de cinco dígitos para identificação de cada cidade year, # ano counter, # número de anos passados desde 2005 (0, 1, 2, ...), emissions, # emissões em quilotons por 1.000 habitantes treat, # Alta capacidade de organização (1/0) fin_str_index, # capacidade governamental (numérica) e um conjunto de covariáveis que também podem influenciar as emissões, incluindo: pop_density, # densidade populacional income_per_capita, # renda per capita pop_age_65_plus, # % de pessoas com 65 anos ou mais pop_college, # % com ensino superior completo value_agr_mill, # produção agrícola em milhões de ienes por habitante value_manuf_mill, # produção industrial em milhões de ienes por habitante value_commerce_mill # produção comercial em milhões de ienes por habitante)set.seed(12361)sample_n(dat, 5) |>tab_df(title ="Estrutura do banco")
Estrutura do banco
muni
muni_code
year
counter
emissions
treat
fin_str_index
pop_density
income_per_capita
pop_age_65_plus
pop_college
value_agr_mill
value_manuf_mill
value_commerce_mill
Tokyo-to Tama-shi
13224
2005
0
3.86
1
1.22
74.01
1758.41
15.75
22.97
0.00
0.15
1.64
Tokyo-to Chuo-ku
13102
2005
0
33.35
0
0.52
96.94
2985.35
16.26
38.18
0.21
1.03
429.50
Tokyo-to Sumida-ku
13107
2008
3
5.53
1
0.56
180.08
1785.14
21.31
16.60
0.22
1.46
7.13
Tokyo-to Koto-ku
13108
2010
5
5.29
1
0.53
115.38
1941.81
19.11
21.25
0.22
0.66
10.17
Tokyo-to Arakawa-ku
13118
2017
12
4.09
1
0.50
208.92
1796.20
23.05
15.34
0.34
0.43
2.79
Sendo \(muni\) o nome do município, \(municode\) o código do múnicipio, \(year\) o ano da observação, \(counter\) a passagem de ano a partir de 2005, que servirá como variável de exposição e indicará o aumento do efeito ao longo do tempo, \(emissions\) é a variável dependente e \(treat\) é a variável que indica se o grupo tem ou não uma alta organização social. O restante das variáveis são controles que a literatura aponta como importantes para a emissão de gás carbono pela população. O gráfico a seguir
Code
# Identificação de tendencias paralelasdat |>group_by(year,treat) |>summarise(media =mean(emissions)) |>mutate(treat =as.factor(treat)) |>ggplot(aes(x = year, y = media, group = treat, color = treat))+geom_path()+labs(title ="Variação da emissão ao longo do tempo", y ="Emissão de carbono em quilotons por 1000 habitantes", x ="Ano", color ="Tratamento")+theme_bw()
Primeiramente, estimaremos o modelo naive (sem controles), a fim de ver como a variável dependente pode ser afetada pelo modelo. Diferente do modelo anteriror, essa especificação conta que o efeito aumenta com o passar do tempo de forma regular. A especificação do modelo pode ser dada por:
naive <-lm(emissions ~ treat * counter, data = dat)naive |>tab_model()
emissions
Predictors
Estimates
CI
p
(Intercept)
11.77
8.81 – 14.73
<0.001
treat
-5.70
-9.46 – -1.93
0.003
counter
0.70
0.24 – 1.17
0.003
treat × counter
-0.53
-1.09 – 0.02
0.061
Observations
744
R2 / R2 adjusted
0.083 / 0.079
Sem controles, o modelo indica que não existem efeitos da organização social sobre a emissão de gás carbonico. Porém, veremos se esse resultado se mantem após a inserção dos controles apontados pela literatura. O novo modelo possui as seguintes especificações: \[Y = \beta_0 + \beta_1 Counter + \beta_2 Treat + \beta (Counter \times Treat)+ \beta_3 PopDensity+ \beta_4 IncomePerCapita+ \beta_5 PopAge65Plus+ \beta_7 PopCollege + \beta_7 ValueAgrMill + \beta_8 CommerceMill + \beta_9 ValueManufMill +\epsilon\]
Code
PO <- dat %>%plm(formula = emissions ~I(treat * counter) + treat + counter + pop_density + income_per_capita + pop_age_65_plus + pop_college + value_agr_mill + value_commerce_mill + value_manuf_mill, model ="pooling", index =c("muni_code", "year"))PO |>tab_model()
Dependent variable
Predictors
Estimates
CI
p
(Intercept)
13.94
9.39 – 18.49
<0.001
treat * counter
-0.88
-1.21 – -0.56
<0.001
treat
-3.46
-5.60 – -1.32
0.002
counter
1.09
0.80 – 1.37
<0.001
pop density
-0.07
-0.08 – -0.05
<0.001
income per capita
-0.00
-0.00 – -0.00
0.018
pop age 65 plus
-0.36
-0.46 – -0.25
<0.001
pop college
0.39
0.24 – 0.55
<0.001
value agr mill
18.89
12.43 – 25.34
<0.001
value commerce mill
0.08
0.07 – 0.08
<0.001
value manuf mill
0.72
0.47 – 0.98
<0.001
Observations
744
R2 / R2 adjusted
0.741 / 0.737
O modelo aponta que o ATT da organização social é de uma redução da emissão de 0,88 quilotons de gás carbono por ano, sendo esse resultado estatisticamente significante. Contudo, devemos avaliar se os dados estão corretamente estimados por meio de testes, a fim de avaliar se o modelo deve incorporar efeitos fixos ou aleatórios e o uso de erros robustos devido a heterosedasticidade. Primeiramente, vamos testar se devemos usar um modelo de Efeitos Fixos por meio de um teste F:
Code
FE <- dat %>%plm(formula = emissions ~I(treat * counter) + treat + counter + pop_density + income_per_capita + pop_age_65_plus + pop_college + value_agr_mill + value_commerce_mill + value_manuf_mill, model ="within", index =c("muni_code", "year"))pFtest(FE, PO)
F test for individual effects
data: emissions ~ I(treat * counter) + treat + counter + pop_density + ...
F = 84.889, df1 = 61, df2 = 672, p-value < 2.2e-16
alternative hypothesis: significant effects
O teste aponta para a existencia de efeitos específicos, \(\alpha_i\), logo, devemos utilizar um modelo de efeitos fixos ou aleatórios. Para definir qual dos dois modelos, realizaremos o teste de Hausman
Code
RE <- dat %>%plm(formula = emissions~I(treat * counter) + treat + counter + pop_density + income_per_capita + pop_age_65_plus + pop_college + value_agr_mill + value_commerce_mill + value_manuf_mill, model ="random", index =c("muni_code", "year"))phtest(FE, RE)
Hausman Test
data: emissions ~ I(treat * counter) + treat + counter + pop_density + ...
chisq = 35.357, df = 10, p-value = 0.0001085
alternative hypothesis: one model is inconsistent
O resultado aponta para o uso de Efeitos Fixos no lugar de Efeitos Aleatórios. Não precisamos testar efeitos de tempo, pois o painel é composto por apenas dois pontos no tempo que são capturados pelo tempo.
F test for twoways effects
data: emissions ~ I(treat * counter) + treat + counter + pop_density + ...
F = 2.3142, df1 = 10, df2 = 662, p-value = 0.01118
alternative hypothesis: significant effects
O teste dá suporte para efeitos específicos de tempo. Assim, estimamos o modelo com Efeitos Fixos em Twoways:
Code
TWFE |>tab_model()
Dependent variable
Predictors
Estimates
CI
p
treat * counter
-0.48
-0.62 – -0.35
<0.001
treat
0.70
-0.48 – 1.88
0.244
pop density
-0.09
-0.18 – 0.01
0.068
income per capita
0.00
0.00 – 0.00
0.007
pop age 65 plus
-0.06
-0.31 – 0.19
0.655
pop college
-0.60
-1.02 – -0.17
0.006
value agr mill
1.63
-7.57 – 10.84
0.728
value commerce mill
0.04
0.02 – 0.05
<0.001
value manuf mill
0.52
0.20 – 0.83
0.001
Observations
744
R2 / R2 adjusted
0.104 / -0.005
O modelo apontou para um efeito significativo do tratamento ao longo do tempo, indicando uma redução de 0,48 quilotons de carbono por ano. Após a seleção do modelo adequado, testamos os resultados em busca de heterossedasticidade do modelo.
Code
plot <-tibble(fitted(TWFE),resid(TWFE))ggplot(data = plot, aes(x =`fitted(TWFE)`, y =`resid(TWFE)`^2)) +geom_point() +labs(title ="Resíduos ao quadrado") +geom_smooth(method ="loess", se =FALSE)+theme_bw()
A análise visual aponta para a existencia de heterocedasticidade nos dados. Vamos conduzir um teste de Breusch-Pagan para avaliar se isso se confirma:
Code
bptest(TWFE, studentize=F)
Breusch-Pagan test
data: TWFE
BP = 2504.1, df = 10, p-value < 2.2e-16
Confirmando a análise gráfica, o teste aponta para a existência de heterocedasticidade dos dados. Assim,novamente aplicaremos uma matrix de correção de Arellano para obter os erros padrões robustos.
Code
# Obtendo os erros padrões robustosARL <-vcovHC(TWFE, method ="arellano")TWFE.ARL <- TWFE; TWFE.ARL$vcov <- ARLtab_model(TWFE, TWFE.ARL,dv.labels =c("Modelo sem erros padrões robustos","Modelo com erros padrões robustos"), show.se = T,show.ci = F,digits =4)