SynthControl.jl

Synthetic control methods in Julia
Author nilshg
Popularity
13 Stars
Updated Last
1 Year Ago
Started In
February 2019

SynthControl.jl

Julia package for synthetic control methods, implementing the technique described in Abadie et al. (2010)

The package is at alpha stage - there's a bare bones implementation that can be used to obtain results and plot them, as well as an implementation of a placebo test, but no formal inference.

UPDATE 17/1/2020 - the package is currently being rewritten with a more generic interface for specifying treatment patterns that will simplify the implementation of different types of synthetic control estimators; the main functionality is currently still operational, but docs are being rewritten. Refer to the tests for a bare bones guide on how to fit & plot a SCM in the current implementation

Installation

The package is currently unregistered, installation therefore works directly from the repo:

pkg> add "https://github.com/nilshg/SynthControl.jl"

Usage

The package includes example data borrowed from the CER Brexit study:

julia> using SynthControl

julia> df = load_brexit()
897×3 DataFrame
│ Row │ country        │ quarter    │ realgdp │
│     │ String         │ Date       │ Float64 │
├─────┼────────────────┼────────────┼─────────┤
│ 1   │ Australia      │ 2009-01-01 │ 1.04    │
│ 2   │ Austria        │ 2009-01-01 │ -1.53   │
│ 3   │ Belgium        │ 2009-01-01 │ -1.15   │
⋮
│ 894 │ Sweden         │ 2018-07-01 │ 22.48   │
│ 895 │ Switzerland    │ 2018-07-01 │ 14.35   │
│ 896 │ United Kingdom │ 2018-07-01 │ 15.72   │
│ 897 │ United States  │ 2018-07-01 │ 19.32   │

The package defines a SynthControlModel type, instances of which can be constructed from a DataFrame, specifying the column holding the outcome variable of interest, the time and group (ID) dimension, the treatment start period and the treated group/observation. Currently, only one treatment unit can be specified.

The example data set includes quarterly GDP for a number of OECD countries, and we are interested in estimating the impact of the Brexit vote in Q2 2016 on GDP in the UK:

julia> s_model = SynthControlModel(df, :realgdp, :country, :quarter, "United Kingdom", Date(2016, 7, 1))

Synthetic Control Model
    Outcome variable: realgdp
    Time dimension: quarter with 39 unique values
    Treatment period: 2016-07-01
    ID variable: country with 23 unique values
    Treatment ID: United Kingdom

    Model is not fitted

The output indicates that the model is not fitted, that is we have at this stage only defined the basic model structure. We can fit the model using the fit! function, which will modify our SynthControlModel in place:

julia> fit!(s_model)

Synthetic Control Model
    Outcome variable: realgdp
    Time dimension: quarter with 39 unique values
    Treatment period: 2016-07-01
    ID variable: country with 23 unique values
    Treatment ID: United Kingdom
    Model is fitted
    Impact estimates: [-0.712, -0.525, -0.426, -0.753, -1.218, -1.451, -1.816, -2.223, -1.761]

The reported impact estimates are the difference between observed outcome variable and estimated outcome in the absence of treatment - a negative value therefore means the treatment is expected to have reduced the outcome variable compared to the counterfactual.

The package also defines a plot recipe which allows to visualise the estimated impact:

julia> using Plots

julia> plot(s_model)

Sample output

To do:

  • Inference
  • Matching on specific covariates
  • Multiple treatment units
  • Documentation
  • Expand testset
  • Consider dropping DataFrames dependency in favour of Tables
  • Include Augmented Synthetic Control