Viés em Diferenças em Diferenças
Sim, eu nunca achei que eu ia chegar a isso. Mas cá estamos: um post sobre viés em diferenças em diferenças. Esse é um tópico relativamente falado em econometria e com uns exemplos legais, então eu decidi fazer esse post.
Sempre que a gente tem dados em painel, a reação pavloviana é dizer “efeitos fixos”. A ideia é que efeitos fixos capturam a heterogenidade não observada e isso potencialmente resolve problemas de viés de seleção.
O problema é quando nem todo mundo é tratado ao mesmo tempo. Curiosamente, o efeito fixo usual não funciona nesse caso - ou seja, o estimador é viesado. Mas a solução é extremamente simples e nos lembra que nem sempre o estimador usual funciona, mas uma pequena variação pode funcionar.
Se você precisa de um exemplo de tratamento que não é todo mundo ao mesmo tempo, talvez o melhor exemplo seja vacinação de covid: primeiro, os mais idosos foram vacinados e os mais jovens foram vacinados meses depois.
Para entender o problema, a gente vai fazer simulações - previsivelmente. A gente vai usar a linguagem de potential outcome aqui e então seja a variável de tratado ou não , o resultado se for tratado e se não for tratado e a gente observa:
O efeito de tratamento é e a gente só observa . Como a gente está simulando, a gente pode salvar o efeito do tratamento salvando e . Dos muitos efeitos de tratamento possíveis, diferenças em diferenças recupera o efeito de tratamento sobre os tratados.
A gente vai usar o R pra aproveitar o pacote plm e eu vou usar paralelização porque eu sou impaciente:
Eu nunca tinha feito nenhuma simulação gerando dados em painel - mentira, eu fiz uma vez na graduação, então não conta. Eu pensei bastante em como estruturar isso e achei melhor quebrar em uma função que gera dados pra um indíviduo e uma função que gera o painel a partir dessa função. Primeiro, a função que gera dados pra um indivíduo. A função vai ter vários inputs: um id
, que diz qual o número que identifica o indvíduo; t
me diz quantos períodos eu observo; common shock
é só um choque em comum pra todos os indvíduos na hora que eu gerar o painel, e que vai ser responsabilidade do efeito fixo de tempo de remover; cohort
é a coisa crítica aqui e me diz quando o indivíduo vai ser tratado se ele for tratado; treat_effect
é o tamanho do efeito de tratamento, que é o que nos interessa; thres
requer um pouquinho mais de explicação. A gente vai adotar o seguinte esquema: se uma variável aleatória estiver acima de thres
, a unidade é tratada; senão, a unidade não é tratada. A gente assume que não é observado:
Da maneira que o código está escrito, tem duas maneiras de não ser tratado: ou a sua cohort
é zero ou a sua variável está abaixo do limiar. Eu vou escrever a função que gera o painel de maneira que ninguém nunca tem cohort = 0
:
Da maneira que painel1
está escrito, todo mundo tem o mesmo thres
e o mesmo efeito de tratamento. Isso não é ruim porque tira uma variação e permite a gente focar na variação de ter vários períodos. Vamos olhar o que acontece quando a gente roda isso uma vez, com 4 períodos e 500 indivíduos:
O efeito de tratamento é a média da variável ATT, que é 1.1543809 e é bem perto do que a gente colocou no código. O efeito de tratamento estimado é 3.1549142, que é o dobro do valor verdadeiro.
Vamos fazer umas mil simulações pra ver o que acontece. Eu vou escrever uma função que me retorna o efeito de tratamento e o coeficiente estimado e ai eu vou usar o map paralelizado, future_map
pra fazer as simulações multicore (no ano 2023, quem tem tempo para rodar as simulações sem ser em paralelo?):
Vamos fazer um histograma disso:
Tudo parece bem aqui: o histograma está centrado em zero e parece ter só uma pequena assimetria. O problema maior é quando a gente tem efeitos de tratamento que mudam conforme a data que o indivíduo é tratado. A gente vai alterar um pouquinho a função painel1
pra permitir diferentes efeitos de tratamento em cada período e diferentes probabilidades de ser alocado a cada período (é pra isso que a gente tem um novo argumento na função, prob
):
Vamos fazer igualzinho acima:
O efeito de tratamento é a média da variável ATT, que é 1.7545035, enquanto o efeito de tratamento estimado é 4.1412855. Vamos criar outra função que faz a simulação:
O efeito de tratamento estimado não está centrado em 0. Na média o nosso viés é negativo, então a gente está subestimando o efeito de tratamento verdadeiro.
Como resolver isso? O problema é que a gente está trabalhando com as variáveis erradas. Na regressão, a gente está definindo um único efeito de tratamento. Mas, o código que simula usa diferentes efeitos de tratamento. Então, até do ponto de vista de recuperar os efeitos de tratamento, nós gostaríamos de recuperar o efeito de tratamento para quem é tratado no período 1 em diante, do período 2 em diante etc. O que acontece é que o estimador de diferenças em diferenças usual faz uma combinação linear desses efeitos de tratamento que não necessariamente somam um nem são positivas, então a gente obtém um estimador que não faz sentido:
Vamos fazer a simulação:
Agora a gente tem três efeitos de tratamento, vamos ver qual a média:
## Dd1 Dd2 Dd3
## 2.9996215 1.9975379 0.9994349
Vamos fazer um histograma, e pra ficar fácil de vizualizar eu vou plottar desvios do efeito de tratamento estimados dos efeitos de tratamento que a gente estabeleceu no código:
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
A média dos efeitos de tratamento pra cada coorte é bem próximo do que a gente estabeleceu e os histogramas são bem comportados. É fácil a gente construir qualquer estimador a partir disso,por exemplo, a gente pode fazer uma média ponderada pela probabilidade de pertencer a cada coorte. Isso exigira reescrever o código um pouquinho porque nenhuma das funções entrega a proporção em cada coorte. Esse post já está longo o bastante e então fica como exercício para o leitor.
É claro, nada desse post é original: o problema é do paper do Chaisemartin (Two-Way Fixed Effects Estimators with Heterogeneous Treatment Effects) e a solução veio de um paper do Wooldridge.