Método de Controle Sintético

O método de controle sintético é um dos métodos utilizados em inferência causal. Essa área da estatística procura desenvolver métodos que possam reproduzir, ou chegar o mais próximo possível, inferência estatística de causalidade em dados observacionais. Este método em específico pode ser utilizado quando se existe uma série de tempo sobre uma variável de interesse em unidades que sofreram uma intervenção, chamado aqui de tratamento, e unidades similares que não sofreram intervenção. Vejamos o exemplo que iremos utilizar nesta análise:

Programa de redução de crime em Seattle

A cidade de Seattle nos Estados Unidos implementou um programa cujo objetivo era a redução do crime em vizinhanças. Nesse caso, esse programa foi implementado em algumas vizinhanças apenas, para que fosse possível avaliar a efetividade desse método quando comparado com as vizinhanças cujo método não foi implementado.

No entanto, existem diferenças importantes entre essas vizinhanças e os resultados de uma avaliação entre vizinhanças tratadas (que receberam o programa) x vizinhanças controle (que não receberam o programa) deve levar em consideração essas características prévias. Por exemplo: uma vizinhança que tinha uma escolaridade maior média da população e que recebeu o tratamento não pode ser comparada diretamenta com uma vizinhança de escolaridade menor média da população que não foi tratada, pois a escolaridade média pode ser uma variável que influencia a criminalidade.

O método de controle sintético busca comparar uma vizinhança que recebeu o tratamento com um conjunto de vizinhanças que não recebeu o tratamento mas que possuem um conjunto semelhante de características da vizinhança que recebeu o tratamento.

Essa seleção de vizinhanças que serão parte do grupo controle pode ser feita de forma manual, através de conhecimento especialista (cujo método aplicado se simplifica a diferenças-em-diferenças), ou através de um conjunto de variáveis que descrevem essa vizinhança. Cada vizinhança candidata ao controle receberá um peso que será proporcional ao quão semelhante cada vizinhança é à vizinhança que recebeu o tratamento, desta forma, eliminando o componente de subjetividade de seleção das vizinhanças de controle.

Por fim, esta análise é baseada no tutorial de Jacquelyn Fede postado no Kaggle.

Pacote microsynth e Base de Dados

O pacote utilizado para o método de controle sintético (Synthetic Control Method) é o microsynth e a base de dados utilizada será seattledmi, que vem com esse pacote:

library(microsynth)
data(seattledmi)
df = seattledmi

library(skimr) # Este pacote auxilia na descrição de conjunto de dados
skim(df)
Data summary
Name df
Number of rows 154272
Number of columns 22
_______________________
Column type frequency:
numeric 22
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
ID 0 1 5.30e+14 3.43e+07 5.3e+14 5.30e+14 5.3e+14 5.30e+14 5.30e+14 ▆▇▂▁▁
time 0 1 8.50e+00 4.61e+00 1.0e+00 4.75e+00 8.5e+00 1.22e+01 1.60e+01 ▇▆▆▆▆
Intervention 0 1 0.00e+00 3.00e-02 0.0e+00 0.00e+00 0.0e+00 0.00e+00 1.00e+00 ▇▁▁▁▁
i_robbery 0 1 3.00e-02 2.00e-01 0.0e+00 0.00e+00 0.0e+00 0.00e+00 7.00e+00 ▇▁▁▁▁
i_aggassau 0 1 3.00e-02 1.80e-01 0.0e+00 0.00e+00 0.0e+00 0.00e+00 5.00e+00 ▇▁▁▁▁
i_burglary 0 1 4.30e-01 1.24e+00 0.0e+00 0.00e+00 0.0e+00 0.00e+00 5.40e+01 ▇▁▁▁▁
i_larceny 0 1 2.70e-01 8.30e-01 0.0e+00 0.00e+00 0.0e+00 0.00e+00 5.70e+01 ▇▁▁▁▁
i_felony 0 1 1.00e-01 3.90e-01 0.0e+00 0.00e+00 0.0e+00 0.00e+00 1.40e+01 ▇▁▁▁▁
i_misdemea 0 1 1.00e-01 4.10e-01 0.0e+00 0.00e+00 0.0e+00 0.00e+00 2.40e+01 ▇▁▁▁▁
i_drugsale 0 1 1.00e-02 1.10e-01 0.0e+00 0.00e+00 0.0e+00 0.00e+00 4.00e+00 ▇▁▁▁▁
i_drugposs 0 1 2.00e-02 1.60e-01 0.0e+00 0.00e+00 0.0e+00 0.00e+00 7.00e+00 ▇▁▁▁▁
any_crime 0 1 1.48e+00 3.81e+00 0.0e+00 0.00e+00 0.0e+00 2.00e+00 2.40e+02 ▇▁▁▁▁
i_drugs 0 1 3.00e-02 2.00e-01 0.0e+00 0.00e+00 0.0e+00 0.00e+00 9.00e+00 ▇▁▁▁▁
TotalPop 0 1 6.11e+01 8.01e+01 0.0e+00 1.90e+01 4.7e+01 7.40e+01 2.77e+03 ▇▁▁▁▁
BLACK 0 1 4.89e+00 1.64e+01 0.0e+00 0.00e+00 0.0e+00 4.00e+00 6.71e+02 ▇▁▁▁▁
HISPANIC 0 1 4.08e+00 9.74e+00 0.0e+00 0.00e+00 1.0e+00 4.00e+00 2.47e+02 ▇▁▁▁▁
Males_1521 0 1 2.50e+00 1.70e+01 0.0e+00 0.00e+00 1.0e+00 2.00e+00 1.27e+03 ▇▁▁▁▁
HOUSEHOLDS 0 1 2.86e+01 4.02e+01 0.0e+00 8.00e+00 2.0e+01 3.10e+01 8.51e+02 ▇▁▁▁▁
FAMILYHOUS 0 1 1.22e+01 1.31e+01 0.0e+00 4.00e+00 1.0e+01 1.60e+01 2.00e+02 ▇▁▁▁▁
FEMALE_HOU 0 1 2.08e+00 3.72e+00 0.0e+00 0.00e+00 1.0e+00 3.00e+00 7.50e+01 ▇▁▁▁▁
RENTER_HOU 0 1 1.49e+01 3.43e+01 0.0e+00 1.00e+00 4.0e+00 1.10e+01 5.67e+02 ▇▁▁▁▁
VACANT_HOU 0 1 2.52e+00 1.01e+01 0.0e+00 0.00e+00 1.0e+00 2.00e+00 3.57e+02 ▇▁▁▁▁

Em geral, o conjunto de dados parece bem limpo, sem dados faltantes e apenas com dados numéricos, necessários para a análise. Em seguida, só para ajudar o entendimento dos dados, vamos realizar uma matriz de correlações:

library(corrplot)
corr <- cor(df)
corrplot(corr, method='circle', order='hclust')

As colunas que começam com i_ são índices de criminalidade como venda de drogas, uso de drogas, furto/roubo, etc. Outras variáveis descrevem a vizinhança como por exemplo HOUSEHOLD (número de casas), BLACK (número de residentes afro-americanos), RENTER_HOU (número de casa alugadas), VACANT_HOU (número de casas desocupadas), entre outros.

Dados que já entendemos melhor o conjunto de dados, vamos prosseguir com a análise dos dados.

Análise dos Dados

Etapa 1: Definir os tipos de variáveis

Neste etapa, precisamos definir dois grupos de variáveis:

  1. Variáveis de interesse, ou resposta: neste caso serão os índices de criminalidade.
  2. Covariáveis descritivas: as demais variáveis que descrevem as vizinhanças. Estas serão utilizadas para construir os pesos que comporão o controle sintético.
# Para variável resposta, vamos selecionar apenas uma para simplificar:
resposta = c("any_crime")

# Para covariável, temos que adicionar todas:
covariaveis = c("TotalPop", "BLACK", "HISPANIC","Males_1521","HOUSEHOLDS",
             "FAMILYHOUS","FEMALE_HOU","RENTER_HOU","VACANT_HOU")

Note também que temos três variáveis importantes que ainda não comentamos:

  1. time: que mede as variáveis ao longo to tempo.
  2. ID: uma identificação numérica arbitrária da vizinhança.
  3. Intervention: coluna que indica as vizinhanças que receberam o programa de redução de crime.

O código abaixo mostra um resumo da quantidade de vizinhanças totais, quando e quantas receberam o programa:

library(tidyverse)
library(ggplot2)

df %>%
  count(time, Intervention) %>%
  pivot_wider(names_from = Intervention, values_from = n) %>%
  knitr::kable()
time 0 1
1 9642 NA
2 9642 NA
3 9642 NA
4 9642 NA
5 9642 NA
6 9642 NA
7 9642 NA
8 9642 NA
9 9642 NA
10 9642 NA
11 9642 NA
12 9642 NA
13 9603 39
14 9603 39
15 9603 39
16 9603 39

Note que até o período de tempo 12, nenhuma vizinhança tinha recebido o programa contra crime. A partir do tempo 13, 39 vizinhanças passaram a ter o programa contra crime e temos 9603 vizinhanças para utilizar na seleção de controle sintético.

Etapa 2: Rodar o modelo

Em seguida, podemos rodar o modelo baseado nas informações acima.

mod1 <- microsynth(df,
                   idvar = "ID", # Coluna indicadora da vizinhança
                   timevar = "time", # Coluna indicadora de tempo
                   intvar = "Intervention", # Coluna indicadora de tratamento
                   start.pre = 1, # Tempo de início do estudo
                   end.pre = 12, # Tempo de pré-intervenção
                   end.post = 16, # Tempo de fim dos dados
                   match.out = resposta, # Nome das variáveis resposta 
                   match.covar = covariaveis, # Nome das covariáveis
                   result.var = resposta, 
                   omnibus.var = resposta,
                   test="twosided"
)

Vamos observar os resultados por partes. Nesta primeira saída, vamos verificar o balanceamento:

mod1$w$Summary
             Targets Weighted.Control All.scaled
Intercept         39               39       39.0
TotalPop        2994             2994     2384.7
BLACK            173              173      190.5
HISPANIC         149              149      159.3
Males_1521        49               49       97.4
HOUSEHOLDS      1968             1968     1113.6
FAMILYHOUS       519              519      475.2
FEMALE_HOU       101              101       81.2
RENTER_HOU      1868             1868      581.9
VACANT_HOU       160              160       98.4
any_crime.12     272              272       65.3
any_crime.11     227              227       64.2
any_crime.10     183              183       55.7
any_crime.9      176              176       53.2
any_crime.8      228              228       55.8
any_crime.7      246              246       55.8
any_crime.6      200              200       52.8
any_crime.5      270              270       50.7
any_crime.4      250              250       57.3
any_crime.3      236              236       58.9
any_crime.2      250              250       51.5
any_crime.1      242              242       55.1

Esta primeira tabela indica a qualidade da seleção de pesos. Para todas as covariáveis e para a variável resposta antes do período de intervenção, são apresentadas as médias por grupos de tratamento e controle. Dessa forma, é possível verificar o balanceamento das covariáveis entre grupos e verificar se os pesos foram estimados de forma a encontrar grupos balanceados. Neste caso encontramos um match exato, mostrando números idênticos entre grupo controle e tratamento. Para verificar os pesos de cada vizinhança, podemos utilizar o código abaixo:

mod1$w$Weights %>%
  data.frame(.) %>%
  mutate(
    peso_igual_zero = ifelse(Main == 0, "sim", "nao")
  ) %>%
  count(peso_igual_zero)
  peso_igual_zero    n
1             nao 1398
2             sim 8244

Essa informação é interessante: do total de possíveis vizinhanças controle (9603), apenas 1398 tiveram peso acima de zero. Isso significa que 8244 vizinhanças não contribuíram em nada com o valor do controle. Isso pode acontecer para o caso de vizinhanças que sejam muito diferentes das vizinhanças tratadas para aquele grupo de covariáveis.

Finalmente, vamos verificar qual foi o tamanho do efeito e o gráfico final:

mod1$Results
$`16`
          Trt  Con Pct.Chng Linear.pVal Linear.Lower Linear.Upper
any_crime 788 1006   -0.217      0.0137       -0.338      -0.0723
plot_microsynth(
  mod1,
  all = NULL # Não mostrar a tendência geral.
)

Ao dia 16, a diferença para any_crime foi de 21.6% inferior ao grupo tratado com o programa anti-crime, indicando que a iniciativa foi bem sucedida e estatisticamente significativa (p-value = 0.014) a 5% de significância.

Note também que antes do período de intervenção (linha vertical tracejada em vermelho), o grupo tratamento e o grupo controle sintético tiveram comportamento bem semelhante, indicando um ótimo ajuste dos pesos do grupo de controle sintético.