-
-
Notifications
You must be signed in to change notification settings - Fork 50
Expand file tree
/
Copy path32-synthetic-control.Rmd
More file actions
1218 lines (815 loc) · 57.5 KB
/
Copy path32-synthetic-control.Rmd
File metadata and controls
1218 lines (815 loc) · 57.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Synthetic Control {#sec-synthetic-control}
The Synthetic Control Method (SCM) is a powerful causal inference tool used when only one treated unit exists, and researchers must construct a synthetic comparison group from a donor pool of untreated units. Introduced by @abadie2003economic and later extended by @abadie2010synthetic, SCM has become a widely used method in policy evaluation and business analytics. See @abadie2021using for a review of the method.
## Why the method exists
The motivating problem is common in applied work. A single state passes a tax reform, a single firm rolls out a new pricing policy, a single country adopts a peg, and the analyst needs to estimate what would have happened in the absence of the intervention. With one treated unit, the comparison-group machinery of [difference-in-differences](#sec-difference-in-differences) is brittle: there is no obvious "control state" or "control firm" that constitutes a clean counterfactual, and any single donor selected is as much a research-design choice as the analysis itself. Synthetic control responds by replacing the *judgment* of a control with a *construction*: rather than selecting one comparable unit, the method builds a weighted average of many, where the weights are chosen so that the synthetic unit tracks the treated unit's outcome and characteristics during the pre-treatment period as closely as possible. The treatment effect is then read off as the gap between the treated unit and its synthetic counterpart after the intervention.
The setting where this approach is most valuable is one in which (i) a clear and discrete policy event is to be evaluated, such as a minimum wage law, a tax reform, or a major advertising campaign, and (ii) there is essentially one unit on the treated side and several plausible controls on the other. Marketing and business applications have multiplied in exactly these settings. @tirunillai2017 use SCM to isolate the effect of offline TV advertising on online chatter; @wang2019mobile estimate how mobile hailing technology shifted drivers' hourly earnings; @guo2020let evaluate the Massachusetts Open Payment Law's effect on physician prescription behavior; and @adalja2023gmo exploit Vermont's GMO-labeling law to ask whether mandatory disclosure changed consumer demand. Each of these has the SCM signature: one treated case, several donor candidates, and a sharp moment of intervention.
## What the method buys you
The distinctive feature of SCM is not just that it provides an answer in this awkward setting, but *what kind* of answer it provides. Three properties are worth highlighting because they help explain the method's appeal.
First, the construction is data-driven rather than judgment-driven. The donor pool's weights are chosen by an optimization that minimizes pre-treatment fit; the analyst cannot tilt the comparison unit toward a preferred outcome. As @arkhangelsky2023large show, when the pre-treatment period is long enough, the resulting estimator delivers asymptotically normal parameters in linear panel models, putting it on the same theoretical footing as DiD.
Second, SCM matches on something stronger than covariates: it matches on pre-treatment *outcomes*. This is what distinguishes it from ordinary [matching methods](#sec-matching-methods), which align units on $X$ and rely on the unobservables to balance implicitly. By forcing the synthetic unit to track the treated unit's outcome trajectory before treatment, SCM absorbs whatever combination of observed and unobserved factors generated that trajectory, at least to the extent they were operating in the donor pool. A Bayesian variant ([Bayesian Synthetic Control]) avoids the restrictive priors of the original formulation [@kim2020bayesian].
Third, the weights are transparent. Every unit of the synthetic comparison comes from an identifiable donor, and the weights themselves carry economic content: they identify which units the algorithm found most useful for reconstructing the treated unit's pre-period. Compared with DiD, this maximizes similarity between treated and control on both observables and (implicitly) unobservables, and removes the discretion of selecting a single comparison group. Compared with a regression-based counterfactual, the convex-combination structure rules out extrapolation: weights live in $[0,1]$ and sum to one, so the synthetic unit cannot exceed the donor pool's convex hull. And because post-intervention outcomes of the donors are never used in constructing the weights, SCM is structurally protected from the kind of specification search that affects more flexible estimators.
The price for these properties is a familiar set of trade-offs. The weights, while transparent, can be difficult to defend on substantive grounds: justifying, say, a 17% contribution from one donor and 23% from another is rarely straightforward. The convex-hull structure assumes the treated unit's pre-treatment characteristics actually lie inside the donor pool's hull; when the treated unit is on the boundary or outside, the method strains and bias can be substantial. And SCM is data-hungry: a long pre-treatment period and a rich donor pool are requirements rather than conveniences. In small samples, those assumptions bind tightly.
------------------------------------------------------------------------
## Assumptions
The synthetic-control machinery rests on a small set of assumptions that, taken together, justify treating a weighted donor pool as a credible counterfactual for the treated unit. Most of these are familiar siblings of the assumptions behind [difference-in-differences](#sec-difference-in-differences) and [matching methods](#sec-matching-methods), and several echo the [SUTVA](#sec-sutva) and [overlap](#sec-overlap-positivity-assumption) requirements that govern observational designs more broadly. The convex-hull requirement, however, is genuinely particular to SCM and tends to be the one that bites in practice. Importantly, these assumptions are not independent; a violation of one usually erodes another, and the diagnostic signatures often overlap.
The first requirement, *good donor pool matching*, is the operational heart of the method.
1. Good Donor Pool Matching
- The synthetic control should closely resemble the treated unit in pre-treatment periods.
- The gap between pre-treatment outcomes of the treated unit and synthetic control should be zero (or very small).
A useful way to read this assumption is as a falsifiable hypothesis rather than a maintained belief: if the pre-treatment fit is visibly poor, the analyst learns immediately that the donor pool cannot reconstruct the treated trajectory, and any post-treatment "effect" is then a mixture of treatment and pre-existing imbalance. The empirical signature is straightforward, namely a non-trivial root mean squared prediction error in the pre-period, frequently visible as parallel-but-shifted paths on a path plot. When the fit is poor, analysts typically reach for one of the [augmented synthetic control](#sec-augmented-synthetic-control) variants or for the [matrix completion estimator](#sec-matrix-completion-estimator), both of which trade some of SCM's transparency for additional bias correction.
2. No Contamination
- Only the treated unit experiences the intervention.
- Control units in the donor pool do not receive treatment.
The no-contamination requirement is SCM's version of [SUTVA](#sec-sutva): the donor pool must consist of units that are genuinely untreated and that are not absorbing spillover from the intervention itself. In practice it fails in two distinct ways. The first is the obvious one, namely that some donor units are themselves treated by similar policies, sometimes even at the same time, which biases the synthetic counterfactual toward the treated trajectory and attenuates the estimated effect. The second is subtler: even if donors are formally untreated, the intervention may leak across borders (think of a state-level minimum wage law that reshapes labor flows in neighboring states, or an advertising campaign whose spillovers contaminate adjacent media markets). When contamination is suspected, the standard hygiene practice is to drop the suspected donors from the pool and re-estimate, comparing the weights and the implied effect to the original specification.
3. No Other Major Changes
- The treatment is the only significant event affecting the treated unit.
The "no other major changes" condition is closely related to the exclusion-style assumptions discussed in [quasi-experimental settings](#sec-quasi-experimental) more generally: SCM cannot tell apart the policy of interest from any other shock that hits the treated unit at roughly the same time. This is why a credible application typically pairs the synthetic-control estimate with a careful narrative ruling out coincident interventions, and why post-period gaps that grow steadily for years should be read with caution as the window for confounding events widens.
4. Convex-Hull (Linearity) Assumption
- The counterfactual outcome of the treated unit can be constructed as a weighted sum of the control units, with weights that are non-negative and sum to one. Equivalently, the treated unit's pre-treatment characteristics must lie within the convex hull of the donor units' pre-treatment characteristics.
- This is stronger than a purely linear combination: it rules out extrapolation outside the donor pool. When the treated unit is on the boundary of, or outside, the convex hull, pre-treatment fit deteriorates and bias can be severe. Relaxations (ridge-penalized SCM, augmented SCM) allow limited negative weights to accommodate treated units that fall outside the hull, at the cost of a bias-variance trade-off.
The convex-hull assumption is the one most likely to fail without the analyst noticing, because failure is masked by the optimizer, which simply returns whatever convex combination minimizes pre-treatment loss even when no good combination exists. The classic empirical signature is a treated unit with extreme pre-treatment values (the wealthiest region, the largest firm, the longest-running campaign) for which all feasible weighted averages fall systematically below or above the treated trajectory. Note how this ties back to assumption (1): poor pre-treatment fit can be a *consequence* of a convex-hull violation rather than a separate problem, which is why "fix the fit" often means "expand or reshape the donor pool" rather than "tune the optimizer". When reshaping is not enough, the [augmented synthetic control](#sec-augmented-synthetic-control) approach allows limited negative weights, while the [synthetic difference-in-differences](#sec-synthetic-difference-in-differences) estimator hybridizes SCM weights with two-way fixed effects to relax both the convex hull and the parallel trends assumptions simultaneously.
5. Exclusion Restriction (Identification Assumption)
- The exclusion restriction holds conditional on pre-treatment outcomes.
The exclusion restriction is the formal counterpart to assumption (3): once the pre-treatment outcome path is matched, the only remaining channel through which donor outcomes inform the treated counterfactual is via the latent factor structure described below, not via residual policy shocks specific to the treated unit. This is what justifies reading the post-period gap as a treatment effect rather than as an unmodeled common shock; it is also what fails when the treated unit and its highest-weight donors share an idiosyncratic exposure that the pre-period happened to absorb.
The `Synth` package provides an algorithm to determine the optimal weight for each control unit such that the synthetic control best resembles the treated unit before treatment.
------------------------------------------------------------------------
## Estimation
The estimation problem boils down to one idea: build a weighted average of untreated units that tracks the treated unit's pre-treatment trajectory, then read the post-treatment gap as the treatment effect. The notation that follows formalises that recipe.
We observe $J + 1$ units over $T$ time periods.
- The first unit ($i = 1$) is treated starting from time $T_0 + 1$.
- The remaining $J$ units serve as the donor pool (potential controls).
- Define:
- $Y_{it}^I$: Outcome for unit $i$ under treatment ($i=1$, for $t \geq T_0 + 1$).
- $Y_{it}^N$: Outcome for unit $i$ in the absence of treatment (counterfactual).
The goal is to estimate the treatment effect:
$$
\tau_{1t} = Y_{1t}^I - Y_{1t}^N
$$
where we observe:
$$
Y_{1t}^I = Y_{1t}
$$
but $Y_{1t}^N$ is unobserved and must be estimated using a synthetic control.
### Constructing the Synthetic Control
To estimate the counterfactual outcome, we create a synthetic control unit, a weighted combination of the untreated donor units. We assign weights $\mathbf{W} = (w_2, \dots, w_{J+1})'$ that satisfy:
- Non-negativity constraint:\
$$ w_j \geq 0, \quad \forall j = 2, \dots, J+1 $$
- Sum-to-one constraint:\
$$ w_2 + w_3 + \dots + w_{J+1} = 1 $$
The optimal weights are found by solving:
$$
\min_{\mathbf{W}} ||\mathbf{X}_1 - \mathbf{X}_0 \mathbf{W}||
$$
where:
- $\mathbf{X}_1$ is a $k \times 1$ vector of pre-treatment characteristics for the treated unit.
- $\mathbf{X}_0$ is a $k \times J$ matrix of pre-treatment characteristics for the donor units.
A common approach is to minimize the weighted sum:
$$
\min_{\mathbf{W}} \sum_{h=1}^{k} v_h (X_{h1} - w_2 X_{h2} - \dots - w_{J+1} X_{hJ+1})^2
$$
where:
- $v_h$ represents the predictive power of each $k$-dimensional pre-treatment characteristic on $Y_{1t}^N$.
- The weights $v_h$ can be chosen either:
- Explicitly by the researcher, or
- Data-driven via optimization.
------------------------------------------------------------------------
### Penalized Synthetic Control
To reduce interpolation bias, the penalized synthetic control method [@abadie2021penalized] modifies the optimization problem:
$$
\min_{\mathbf{W}} ||\mathbf{X}_1 - \sum_{j=2}^{J+1}W_j \mathbf{X}_j ||^2 + \lambda \sum_{j=2}^{J+1} W_j ||\mathbf{X}_1 - \mathbf{X}_j||^2
$$
where:
- $\lambda > 0$ controls the trade-off between fit and regularization:
- $\lambda \to 0$: Standard synthetic control (unpenalized).
- $\lambda \to \infty$: Nearest-neighbor matching (strong penalization).
- This method ensures:
- Sparse and unique solutions for weights.
- Exclusion of dissimilar control units (reducing interpolation bias).
The final synthetic control estimator is:
$$
\hat{\tau}_{1t} = Y_{1t} - \sum_{j=2}^{J+1} w_j^* Y_{jt}
$$
where $Y_{jt}$ is the outcome for unit $j$ at time $t$.
------------------------------------------------------------------------
## Theoretical Considerations
The assumptions in the previous section can feel like a checklist, but they are tied together by a single underlying data-generating story. SCM assumes that the counterfactual outcome follows a factor model [@abadie2010synthetic]:
$$
Y_{it}^N = \mathbf{\theta}_t \mathbf{Z}_i + \mathbf{\lambda}_t \mathbf{\mu}_i + \epsilon_{it}
$$
where:
- $\mathbf{Z}_i$ = Observed characteristics.
- $\mathbf{\mu}_i$ = Unobserved factors.
- $\epsilon_{it}$ = Transitory shocks (random noise).
The factor structure is doing most of the conceptual work here. The term $\mathbf{\theta}_t \mathbf{Z}_i$ collects time-varying returns to observed characteristics, while $\mathbf{\lambda}_t \mathbf{\mu}_i$ encodes the kind of unobserved heterogeneity that ordinarily wrecks comparisons of trends. SCM's appeal relative to [difference-in-differences](#sec-difference-in-differences) flows from this representation: rather than insisting on parallel trends (a constant $\mathbf{\lambda}_t \mathbf{\mu}_i$ differential between treated and control), the method allows time-varying loadings and recovers the counterfactual by matching enough pre-treatment outcomes that the implied $\mathbf{\mu}_i$ of the treated unit equals a weighted average of the donors' loadings. This is why SCM is sometimes positioned as a strict generalization of DiD when the latent-factor representation holds.
To ensure a valid synthetic control, the weights $\mathbf{W}^*$ must satisfy:
$$
\sum_{j=2}^{J+1} w_j^* \mathbf{Z}_j = \mathbf{Z}_1
$$
$$
\sum_{j=2}^{J+1} w_j^* Y_{j1} = Y_{11}, \quad \dots, \quad \sum_{j=2}^{J+1} w_j^* Y_{jT_0} = Y_{1T_0}
$$
This guarantees that the synthetic control closely matches the treated unit in pre-treatment periods. The matching conditions on $\mathbf{Z}$ and on the pre-treatment outcomes are not redundant: matching outcomes alone can be achieved by spurious combinations of donors with offsetting $\mathbf{\mu}_i$, and matching covariates alone leaves the unobserved factors uncontrolled. Together they pin down both the observed-characteristic projection and the latent-factor loading. When this dual matching is feasible, the post-treatment gap identifies $\tau_{1t}$; when it is not, the bias persists into the post-period and contaminates the estimate.
Bias Considerations:
- The accuracy of SCM depends on the ratio of transitory shocks ($\epsilon_{it}$) to pre-treatment periods ($T_0$). In other words, you should have good fit for $Y_{1t}$ for pre-treatment period (i.e., $T_0$ should be large while small variance in $\epsilon_{it}$)
- Good fit in pre-treatment periods (large $T_0$) is crucial.
- If the pre-treatment fit is poor, bias correction methods are required [@arkhangelsky2021synthetic; @abadie2021using; @ben2020varying].
The intuition behind the bias bound is that with finite $T_0$ the estimated weights are themselves random, and noisy pre-treatment outcomes can be matched by a noisy combination of donors that does not in fact equate the latent loadings $\mathbf{\mu}_i$. As $T_0$ grows and the noise variance shrinks, the probability of such a spurious match falls, which is why long pre-periods are not merely desirable but structural to identification. This is also where the connection to other modern panel-data tools becomes most visible: when pre-treatment fit is poor, the [augmented synthetic control](#sec-augmented-synthetic-control) method bolts on an outcome model to absorb the residual bias, the [matrix completion estimator](#sec-matrix-completion-estimator) imputes the entire treated path under a low-rank restriction, and [synthetic difference-in-differences](#sec-synthetic-difference-in-differences) blends weighting with two-way fixed effects to obtain a doubly robust estimator. Each of these can be read as a different answer to the same question: what should one do when the factor model is right in spirit but the standard SCM weights cannot find a clean match?
------------------------------------------------------------------------
## Inference in SCM
Inference in SCM looks unfamiliar to anyone trained on standard regression standard errors, and that is because the usual sampling story does not apply. With one treated unit and a handful of donors, there is no large-sample limit to invoke and no obvious population from which the data were drawn; the design is closer in spirit to the [design-based](#sec-design-based) tradition than to model-based inference. Two facts in particular make the textbook machinery awkward:
1. Undefined sampling mechanism (e.g., only one treated unit).
2. SCM is deterministic, making p-values difficult to interpret.
The first point reflects the structural feature that the analyst typically has the *only* treated case rather than a sample drawn from a population of treated cases. The second is more subtle: given the data, the optimization that produces $\mathbf{W}^*$ is deterministic, so there is no estimation noise of the conventional kind to feed into a sandwich variance estimator. Inference therefore has to come from a different source, namely the comparison of the realized treatment effect against a reference distribution of effects that *could* have been observed under a null of no treatment.
### Permutation (Placebo) Inference
To perform inference:
1. Iteratively reassign the treatment to units in the donor pool.
2. Estimate placebo treatment effects for each synthetic control.
3. Compare the actual treatment effect to the placebo distribution.
The treatment effect is considered statistically significant if it is extreme relative to the placebo distribution. The logic is the same as the [DiD placebo test](#sec-placebo-test-did): if the realized post-period gap is just one draw from the distribution one obtains by pretending each donor was treated, then there is no special evidence for an effect. If, instead, the realized gap is a tail event in that distribution, the null of no effect is implausible.
In practice, two refinements are essential. First, placebo gaps for donors with poor pre-treatment fit dominate the right tail mechanically and need to be filtered out, typically by trimming on the pre-period root mean squared prediction error or by reporting the ratio of post- to pre-period RMSPE rather than the raw gap. Second, the test depends on the donor pool being exchangeable with the treated unit under the null; a donor that is wildly different from the treated unit produces an uninformative placebo even when its fit is acceptable. This connects directly back to the convex-hull discussion in the assumptions section, the same donor-pool composition that drives identification also drives the credibility of inference.
### One-Sided Inference
- Recommended due to the limited number of treated cases.
- The permutation test is more robust than standard p-values.
A one-sided test is usually the honest choice because the analyst typically has a directional hypothesis (the policy reduced crime, the campaign raised sales) and the placebo distribution is sparse in the relevant tail. Two-sided tests require effectively doubling the placebo sample to retain the same power, which is rarely practical with donor pools of fewer than a few dozen units. The permutation test also tends to be more robust than asymptotic p-values precisely because it sidesteps the deterministic-weights problem flagged above; it asks how unusual the observed gap is given the configuration of the data, rather than how unusual it is under a hypothetical sampling distribution. See the broader discussion of [robustness checks](#sec-robustness-checks-quasi-exp) for additional sensitivity analyses that complement the placebo test.
For benchmark distributions (e.g., uniform permutation distributions), see [@firpo2018synthetic].
------------------------------------------------------------------------
## Augmented Synthetic Control Method {#sec-augmented-synthetic-control}
The Augmented Synthetic Control Method (ASCM), introduced by @ben2021augmented, extends the Synthetic Control Method to cases where perfect pre-treatment fit is infeasible. ASCM combines SCM weighting with bias correction through an outcome model, improving estimates when SCM alone fails to match pre-treatment outcomes precisely.
Key Idea:
- Standard SCM requires that the synthetic control closely matches the treated unit in pre-treatment periods.
- When this is not possible, ASCM adjusts for bias using outcome modeling, similar to bias correction in matching estimators.
- ASCM can be seen as a trade-off between SCM and regression-based approaches, incorporating both synthetic control weighting and outcome modeling.
ASCM builds on SCM but relaxes its strong convex hull assumption. Key assumptions:
- No Interference: Treatment affects only the treated unit.
- No Unobserved Time-Varying Confounders: Changes over time should not be correlated with treatment assignment.
- Regularization Controls Extrapolation Bias: Ridge penalty prevents overfitting.
ASCM is recommended when:
1. SCM alone does not provide a good pre-treatment fit.
2. Only one treated unit is available.
3. Auxiliary covariates need to be incorporated.
Advantages of ASCM
1. Handles Poor Pre-Treatment Fit
- Standard SCM fails when the treated unit lies outside the convex hull of donor units.
- ASCM allows negative weights (via ridge regression) to improve fit.
2. Balances Bias and Variance
- Ridge penalty controls extrapolation, reducing overfitting.
3. Flexible Estimation Framework
- Works with auxiliary covariates, extending beyond pure pre-treatment matching.
------------------------------------------------------------------------
Let:
- $J + 1$ units be observed over $T$ time periods.
- The first unit ($i=1$) is treated in periods $T_0 + 1, \dots, T$. - The remaining $J$ units are the donor pool (potential controls).
- Define:
- $Y_{it}^I$: Outcome for unit $i$ under treatment.
- $Y_{it}^N$: Outcome for unit $i$ in the absence of treatment (counterfactual).
The treatment effect of interest:
$$
\tau_{1t} = Y_{1t}^I - Y_{1t}^N
$$
where:
$$
Y_{1t}^I = Y_{1t}
$$
but $Y_{1t}^N$ is unobserved and must be estimated.
ASCM improves SCM by incorporating an outcome model to correct for poor pre-treatment fit. The counterfactual outcome is estimated as:
$$
\hat{Y}^{\text{aug}}_{1T}(0) = \sum_{i=2}^{J+1} w_i Y_{iT} + \left( m_1 - \sum_{i=2}^{J+1} w_i m_i \right)
$$
where:
- $w_i$ are SCM weights chosen to best match pre-treatment outcomes.
- $m_i$ is an outcome model prediction for unit $i$.
- If SCM achieves perfect pre-treatment fit, $m_1 - \sum w_i m_i \approx 0$, and ASCM reduces to standard SCM.
The most common implementation, Ridge ASCM, uses ridge regression to estimate $m_i$, leading to:
$$
\hat{Y}^{\text{aug}}_{1T}(0) = \sum_{i=2}^{J+1} w_i Y_{iT} + \left( X_1 - \sum w_i X_i \right) \beta
$$
where $\beta$ is estimated using ridge regression of post-treatment outcomes on pre-treatment outcomes.
------------------------------------------------------------------------
## Synthetic Control with Staggered Adoption
While traditional SCM focuses on cases with a single treated unit, many real-world policies exhibit staggered adoption, where different units receive treatment at different times.
In staggered adoption designs, policy implementation occurs over multiple time periods across different units (e.g., states, companies, or regions). This presents challenges:
- Traditional SCM limitations: SCM was designed for a single treated unit and does not naturally accommodate multiple adoption times.
- Heterogeneous treatment effects: The impact of the intervention may vary over time or across units.
- Estimation bias: Common approaches such as [Two-Way Fixed Effects](#sec-two-way-fixed-effects) can yield biased results when treatment effects are heterogeneous.
### Partially Pooled Synthetic Control
@ben2022synthetic propose a partially pooled SCM approach, balancing trade-offs between separate SCM for each unit and a fully pooled approach that estimates a single synthetic control for all treated units. The key ideas include:
1. Two imbalance measures:
- Individual unit-level imbalance.
- Aggregate imbalance for the average treated unit.
2. Optimization framework:
- Weights are chosen to minimize a weighted sum of these two imbalance measures.
- This method reduces bias compared to estimating separate SCM models for each unit.
Mathematically, let:
- $Y_{it}$ be the outcome of interest for unit $i$ at time $t$.
- $T_i$ be the treatment adoption time for unit $i$.
- $W_i$ be the synthetic control weight assigned to unit $i$.
Then, for treated unit $j$, the estimated counterfactual is:
$$ \hat{Y}_{jT_j+k} = \sum_{i=1}^{N} \hat{W}_{ij} Y_{iT_j+k} $$
The objective function combines both individual and aggregate balance constraints:
$$ \min_W \lambda \sum_{j} ||Y_{j,\text{pre}} - \sum_i W_{ij} Y_{i,\text{pre}}||^2 + (1-\lambda) ||Y_{\text{treated, pre}} - \sum_i W_i Y_{i,\text{pre}}||^2 $$
where $\lambda$ is a tuning parameter that controls the trade-off between individual and pooled balance.
```{r, eval = FALSE}
# Load necessary library
library(augsynth)
```
------------------------------------------------------------------------
## Generalized Synthetic Control
The Generalized Synthetic Control (GSC) Method extends the synthetic control approach to accommodate multiple treated units and heterogeneous treatment effects while relaxing the [parallel trends assumption](#prior-parallel-trends-test) required in [difference-in-differences](#sec-difference-in-differences). Originally developed by @xu2017generalized, the GSC method integrates interactive fixed effects models, improving efficiency and robustness in time-series cross-sectional (TSCS) data.
### The Problem with Traditional Methods
Traditional causal inference methods such as [DID](#sec-difference-in-differences) require the [parallel trends assumption](#prior-parallel-trends-test): $$
E[Y_{it}(0) | D_i = 1] - E[Y_{it}(0) | D_i = 0] = \text{constant}
$$ which states that in the absence of treatment, the difference in outcomes between treated and control units would have remained constant over time. However, this assumption often fails due to:
- Time-varying unobserved confounders affecting both treatment assignment and outcomes.
- Heterogeneous treatment effects across units and over time.
- Multiple treatment periods where different units adopt the treatment at different times.
To address these limitations, GSC builds on the interactive fixed effects model, which allows for unit-specific and time-specific latent factors that can capture unobserved confounding trends.
### Generalized Synthetic Control Model
Let $Y_{it}$ represent the observed outcome of unit $i$ at time $t$, and define the potential outcomes framework: $$
Y_{it}(d) = \mu_{it} + \delta_{it} d + \varepsilon_{it}, \quad d \in {0,1}
$$ where:
- $\mu_{it}$ represents the latent factor structure of untreated outcomes.
- $\delta_{it}$ is the treatment effect.
- $\varepsilon_{it}$ is the idiosyncratic error term.
Under the interactive fixed effects model, we assume that the untreated outcome follows: $$
\mu_{it} = X_{it} \beta + \lambda_i' f_t
$$ where:
- $X_{it}$ is a vector of observed covariates.
- $\beta$ is a vector of unknown coefficients.
- $\lambda_i$ represents unit-specific factor loadings.
- $f_t$ represents time-specific factors.
The presence of $\lambda_i' f_t$ allows GSC to control for unobserved confounders that vary across time and units, a key advantage over [DID](#sec-difference-in-differences) and traditional [SCM](#sec-synthetic-control).
### Identification and Estimation
To estimate the [Average Treatment Effect on the Treated](#sec-notation-quasi-experimental), we define: $$
\text{ATT}_t = \frac{1}{N_T} \sum_{i \in T} \left[ Y_{it}(1) - Y_{it}(0) \right]
$$ where $N_T$ is the number of treated units. The challenge is that $Y_{it}(0)$ for treated units is counterfactual and must be estimated.
#### Step 1: Estimating Factor Loadings and Latent Factors
Using only control units, we estimate the latent factors and factor loadings: $$
Y_{it} = X_{it} \beta + \lambda_i' f_t + \varepsilon_{it}, \quad i \in C
$$ which can be rewritten in matrix form: $$
Y_C = X_C \beta + \Lambda_C F' + E_C.
$$ The key assumption is that factor loadings and latent factors apply to both treated and control units, ensuring valid counterfactual estimation.
#### Step 2: Imputing Counterfactual Outcomes
For treated units, we estimate: $$
\hat{\lambda}_i = (F_0'F_0)^{-1} F_0' (Y_{i,0} - X_{i,0} \beta)
$$ where $F_0$ and $Y_{i,0}$ denote pre-treatment data. The imputed counterfactuals are then:
$$
\hat{Y}_{it}(0) = X_{it} \beta + \hat{\lambda}_i' \hat{f}_t.
$$
### Bootstrap Procedure for Standard Errors
A key issue in statistical inference with GSC is the estimation of uncertainty. The standard nonparametric bootstrap is biased due to dependent structures in panel data, so we adopt the parametric bootstrap from [@li2023statistical] to correct for bias.
Corrected Bootstrap Algorithm:
1. Estimate the IFE Model using control units.
2. Resample residuals $\hat{\varepsilon}_{it}$ from the fitted model.
3. Generate new synthetic datasets using: $$
Y_{it}^* = X_{it} \hat{\beta} + \hat{\lambda}_i' \hat{f}_t + \varepsilon_{it}^*
$$
4. Re-estimate the model on resampled data and compute bootstrap confidence intervals.
This approach ensures correct coverage probabilities and avoids bias in standard error estimation. Figure \@ref(fig:sc-gsynth-simdata) shows the GSC fit on the bundled `simdata` example.
```{r sc-gsynth-simdata, fig.cap="Generalized synthetic control fit on the bundled gsynth simdata, with two-way fixed effects, cross-validated factor count, and parametric bootstrap standard errors."}
# Load required package
library(gsynth)
# Example data
data("gsynth")
# Fit Generalized Synthetic Control Model
gsc_model <-
gsynth(
Y ~ D + X1 + X2,
data = simdata,
parallel = FALSE,
index = c("id", "time"),
force = "two-way",
CV = TRUE,
r = c(0, 5),
se = T
)
# Summary of results
summary(gsc_model)
# Visualization
plot(gsc_model)
```
------------------------------------------------------------------------
## Bayesian Synthetic Control
The Bayesian Synthetic Control (BSC) approach introduces a probabilistic alternative to traditional synthetic control methods. Unlike the standard SCM, which estimates a single point estimate of treatment effects using a convex combination of control units, BSC incorporates posterior predictive distributions, allowing for proper uncertainty quantification and probabilistic inference.
Bayesian methods offer several advantages over frequentist SCM:
- Probabilistic Treatment Effects: Instead of a single deterministic estimate, Bayesian SCM provides a distribution over possible treatment effects.
- Regularization via Priors: Bayesian approaches allow for the incorporation of shrinkage priors to improve estimation stability in high-dimensional settings.
- Flexibility: The Bayesian framework can accommodate dynamic latent factor models, addressing issues like time-varying heterogeneity.
Two major Bayesian approaches to SCM:
1. Dynamic Multilevel Factor Models [@pang2022bayesian]
2. Bayesian Sparse Synthetic Control [@kim2020bayesian]
### Bayesian Causal Inference Framework
In the traditional SCM, we estimate the counterfactual outcome $Y_{it}(0)$ for treated unit $i$ at time $t$ using a weighted sum of control units:
$$
\hat{Y}_{it}(0) = \sum_{j \neq i} w_j Y_{jt}.
$$
However, this deterministic approach does not quantify uncertainty in the estimation. The Bayesian SCM instead models the counterfactual outcome as a posterior predictive distribution:
$$
P(Y_{it}(0) | Y_{\text{obs}}, \theta),
$$
where $\theta$ represents the parameters of the model (e.g., factor loadings, regression coefficients, latent variables). The Bayesian approach estimates full posterior distributions, allowing us to compute credible intervals instead of relying solely on point estimates.
### Bayesian Dynamic Multilevel Factor Model
The Dynamic Multilevel Factor Model (DM-LFM), proposed by @pang2022bayesian, extends SCM by incorporating latent factor models to correct for unit-specific time trends.
#### Model Specification
Let $Y_{it}$ be the observed outcome for unit $i$ at time $t$. The potential untreated outcome follows:
$$
Y_{it}(0) = X_{it} \beta + \lambda_i' f_t + \varepsilon_{it},
$$
where:
- $X_{it}$ are observed covariates,
- $\beta$ are regression coefficients,
- $\lambda_i$ are unit-specific factor loadings,
- $f_t$ are common latent time factors,
- $\varepsilon_{it} \sim \mathcal{N}(0, \sigma^2)$ is the noise term.
The treatment effect is defined as:
$$
\tau_{it} = Y_{it}(1) - Y_{it}(0).
$$
Under latent ignorability, we assume:
$$
P(T_i | X_i, U_i) = P(T_i | X_i),
$$
where $U_i$ are latent variables extracted from the outcome data.
#### Bayesian Inference Procedure
To estimate treatment effects, we follow these steps:
1. Estimate $\lambda_i$ and $f_t$ using control units.
2. Predict counterfactuals for treated units: $$
\hat{Y}_{it}(0) = X_{it} \hat{\beta} + \hat{\lambda}_i' \hat{f}_t.
$$
3. Obtain the posterior predictive distribution of treatment effects.
This Bayesian approach enables proper credible intervals for causal effects.
### Bayesian Sparse Synthetic Control
@kim2020bayesian propose an alternative Bayesian framework that removes restrictive constraints imposed by standard SCM.
#### Relaxing SCM Constraints
Traditional SCM imposes:
1. Nonnegative weights: $w_j \geq 0$.
2. Convex combination: $\sum_j w_j = 1$.
BSCM relaxes these by allowing negative weights and regularization priors. It models the control unit weights using Bayesian shrinkage priors:
$$
w_j \sim \mathcal{N}(0, \tau^2),
$$
where $\tau^2$ is a regularization parameter. This allows flexible weight selection while preventing overfitting.
#### Bayesian Shrinkage Priors
BSCM incorporates horseshoe priors and spike-and-slab priors to select relevant control units:
- Horseshoe Prior: $$
w_j \sim \mathcal{N}(0, \lambda_j^2), \quad \lambda_j \sim C^+(0,1).
$$
- Spike-and-Slab Prior: $$
w_j \sim \gamma_j \mathcal{N}(0, \sigma_1^2) + (1-\gamma_j) \mathcal{N}(0, \sigma_0^2),
$$ where $\gamma_j \sim \text{Bernoulli}(\pi)$ determines whether a control unit is included.
These priors ensure robust weight selection while controlling for overfitting.
### Bayesian Inference and MCMC Estimation
Both DM-LFM and BSCM are estimated using Markov Chain Monte Carlo (MCMC). Given observed data $Y_{\text{obs}}$, we sample from the posterior:
$$
P(\theta | Y_{\text{obs}}) \propto P(Y_{\text{obs}} | \theta) P(\theta),
$$
where $P(\theta)$ encodes prior beliefs about the parameters.
Common MCMC techniques used:
- Gibbs Sampling for latent factors and regression coefficients.
- Hamiltonian Monte Carlo (HMC) for high-dimensional posteriors.
> Build note: the Bayesian SCM example below uses `rstan`, which requires a working C++ toolchain. On Windows install [Rtools](https://cran.r-project.org/bin/windows/Rtools/); on macOS install the Xcode command-line tools. First-time compilation can take 5-10 minutes. The chunk is set to `eval = FALSE` for exactly this reason, run it manually if you want to reproduce the output.
```{r, eval = FALSE}
# Load necessary libraries
library(rstan)
library(bayesplot)
# Define Bayesian SCM model in Stan
scm_model <- "
data {
int<lower=0> N; // Number of observations
int<lower=0> T; // Time periods
matrix[N, T] Y; // Outcome matrix
}
parameters {
vector[T] f; // Latent factors
vector[N] lambda; // Factor loadings
real<lower=0> sigma; // Noise variance
}
model {
// Priors
f ~ normal(0, 1);
lambda ~ normal(0, 1);
// Likelihood
for (i in 1:N)
Y[i, ] ~ normal(lambda[i] * f, sigma);
}
"
# Compile and fit the model
fit <-
stan(model_code = scm_model, data = list(
N = 50,
T = 20,
Y = matrix(rnorm(1000), 50, 20)
))
# Summarize results
print(fit)
```
## Using Multiple Outcomes to Improve the Synthetic Control Method
Typically, SCM constructs a weighted combination of untreated control units to approximate the counterfactual outcome of the treated unit. However, standard SCM is limited to a single outcome variable, which can lead to biased estimates when multiple correlated outcomes are available.
In their work, @sun2023using propose a novel extension of SCM that leverages multiple outcome variables to improve causal inference by:
1. Using a common set of synthetic control weights across all outcomes rather than estimating separate weights for each outcome.
2. Reducing bias using a low-rank factor model, which exploits shared latent structures across outcomes.
### Standard Synthetic Control Method
Let $Y_{itk}$ denote the observed outcome for unit $i$ at time $t$ for outcome $k$, where $i = 1, \dots, N$, $t = 1, \dots, T$, and $k = 1, \dots, K$. The potential outcomes framework assumes:
$$
Y_{itk}(d) = \mu_{itk} + \delta_{itk} d + \varepsilon_{itk}, \quad d \in {0,1}
$$
where:
- $\mu_{itk}$ represents the latent structure of untreated outcomes.
- $\delta_{itk}$ is the treatment effect.
- $\varepsilon_{itk} \sim \mathcal{N}(0, \sigma^2)$ is random noise.
For unit $i=1$ (the treated unit), the observed outcome follows:
$$
Y_{1tk} = Y_{1tk}(0) + D_{1t} \delta_{1tk}
$$
where $D_{1t}$ is an indicator for treatment at time $t$. The challenge is to estimate the counterfactual outcome $Y_{1tk}(0)$, which is unobserved post-treatment.
SCM estimates $Y_{1tk}(0)$ as a weighted combination of control units:
$$
\hat{Y}_{1tk}(0) = \sum_{i=2}^{N} w_i Y_{itk}
$$
where weights $w_i$ are chosen to minimize pre-treatment imbalance.
### Using Multiple Outcomes for Bias Reduction
Instead of estimating separate weights $w_k$ for each outcome $k$, @sun2023using propose a single set of weights $w$ across all outcomes. This approach is justified under a low-rank factor model, which assumes that multiple outcomes share common latent factors.
#### Low-Rank Factor Model
Assume the untreated potential outcome follows a linear factor structure:
$$
Y_{itk}(0) = X_{it} \beta_k + \lambda_i' f_{tk} + \varepsilon_{itk}
$$
where:
- $X_{it}$ are observed covariates.
- $\beta_k$ are outcome-specific coefficients.
- $\lambda_i$ are unit-specific factor loadings.
- $f_{tk}$ are time-and-outcome-specific latent factors.
If all outcomes share the same latent factor structure, then the bias in synthetic control estimation can be reduced by a factor of $1 / \sqrt{K}$ as the number of outcomes $K$ increases.
### Estimation Methods
@sun2023using propose two methods for constructing a common synthetic control:
1. Concatenated Outcome Weights: Estimate weights by minimizing imbalance across all outcomes simultaneously:
$$
\hat{w} = \arg\min_w \sum_{k=1}^{K} || Y_{1,\text{pre},k} - \sum_{i=2}^{N} w_i Y_{i,\text{pre},k} ||^2
$$
2. Averaged Outcome Weights: Estimate weights based on a linear combination (e.g., average) of outcomes:
$$
\hat{w} = \arg\min_w || \frac{1}{K} \sum_{k=1}^{K} Y_{1,\text{pre},k} - \sum_{i=2}^{N} w_i \frac{1}{K} \sum_{k=1}^{K} Y_{i,\text{pre},k} ||^2
$$
These methods improve SCM performance by reducing variance and overfitting to noise.
### Empirical Application: Flint Water Crisis
To illustrate the benefits of multiple outcome SCM, @sun2023using re-analyze the Flint water crisis, which led to lead contamination in drinking water, potentially affecting student performance.
Four key educational outcomes were studied:
1. Math Achievement
2. Reading Achievement
3. Special Needs Status
4. Daily Attendance
By applying common weights across these outcomes, their SCM results showed:
- Reduced bias and improved robustness compared to separate SCM fits.
- Better pre-treatment fit for educational outcomes.
- Stronger evidence of educational impacts following the crisis.
```{r, eval = FALSE}
# Load necessary libraries
library(augsynth)
# Fit SCM using a common set of weights across multiple outcomes
synth_model <- augsynth_multiout()
```
------------------------------------------------------------------------
## Applications
### Synthetic Control Estimation
This example simulates data for 10 states over 30 years, where State A receives treatment after year 15. We implement two approaches:
1. Standard Synthetic Control using `Synth`.
2. [Generalized Synthetic Control] using `gsynth`, which incorporates iterative fixed effects and multiple treated units.
Load Required Libraries
```{r, message=FALSE}
# install.packages("Synth")
# install.packages("gsynth")
library("Synth")
library("gsynth")
```
We construct a panel dataset where the outcome variable $Y$ is influenced by two covariates ($X_1, X_2$). Treatment ($T$) is applied to State A from year 15 onwards, with an artificial treatment effect of +20.
```{r}
# Simulate panel data
set.seed(1)
df <- data.frame(
year = rep(1:30, 10), # 30 years for 10 states
state = rep(LETTERS[1:10], each = 30), # States A to J
X1 = round(rnorm(300, 2, 1), 2), # Continuous covariate
X2 = round(rbinom(300, 1, 0.5) + rnorm(300), 2), # Binary + noise
state.num = rep(1:10, each = 30) # Numeric identifier for states
)
# Outcome variable: Y = 1 + 2 * X1 + noise
df$Y <- round(1 + 2 * df$X1 + rnorm(300), 2)
# Assign treatment: Only State A (state == "A") from year 15 onward
df$T <- as.integer(df$state == "A" & df$year >= 15)
# Apply treatment effect: Increase Y by 20 where treatment is applied
df$Y[df$T == 1] <- df$Y[df$T == 1] + 20
# View data structure
str(df)
```
#### Step 1: Estimating Synthetic Control with `Synth`
The `Synth` package creates a synthetic control by matching pre-treatment trends of the treated unit (`State A`) with a weighted combination of donor states.
We specify predictors, dependent variable, and donor pool.
```{r}
dataprep.out <- dataprep(
df,
predictors = c("X1", "X2"),
dependent = "Y",
unit.variable = "state.num",
time.variable = "year",
unit.names.variable = "state",
treatment.identifier = 1,
controls.identifier = 2:10,
time.predictors.prior = 1:14,
time.optimize.ssr = 1:14,
time.plot = 1:30
)
```
Fit Synthetic Control Model
```{r}
synth.out <- synth(dataprep.out)
# Display synthetic control weights and balance table
print(synth.tab(dataprep.res = dataprep.out, synth.res = synth.out))
```
Plot: Observed vs. Synthetic State A. Figure \@ref(fig:sc-stateA-path) overlays the actual outcome trajectory of State A with its synthetic counterfactual.
```{r sc-stateA-path, fig.cap="Path plot comparing the observed outcome of treated State A with its synthetic-control counterfactual; the dashed vertical line marks the treatment start at year 15."}
path.plot(
synth.out,
dataprep.out,
Ylab = "Y",
Xlab = "Year",
Legend = c("State A", "Synthetic State A"),
Legend.position = "topleft"
)
# Mark the treatment start year
abline(v = 15, lty = 2)
```
Plot: Treatment Effect (Gaps Plot)
The gaps plot shows the difference between `State A` and its synthetic control over time. Figure \@ref(fig:sc-stateA-gaps) plots this treatment-effect path.
```{r sc-stateA-gaps, fig.cap="Gaps plot showing the period-by-period difference between the observed outcome of State A and its synthetic counterfactual; the post-1975 deviation indicates the estimated treatment effect."}
gaps.plot(synth.res = synth.out,
dataprep.res = dataprep.out,
Ylab = c("Gap"),
Xlab = c("Year"),
Ylim = c(-30, 30),
Main = ""
)
abline(v = 15, lty = 2)
```
#### Modern alternatives: `tidysynth` and `augsynth`
The classic `Synth` workflow above relies on building a `dataprep` matrix of predictors, treated/donor identifiers, and time windows before invoking `synth()`. Two more recent packages streamline this pipeline:
- `tidysynth` (Dunford) provides a tidyverse-style API in which the synthetic-control workflow is expressed as a chained sequence of verbs, `synthetic_control()` initializes the object, `generate_predictor()` defines pre-treatment matching variables, `generate_weights()` solves for donor weights, and `generate_control()` constructs the synthetic counterfactual. Diagnostics, plots, and placebo tests are dispatched on the resulting object via S3 methods (`plot_trends()`, `plot_placebos()`, `grab_significance()`), avoiding the matrix bookkeeping required by `Synth::dataprep()`.
- `augsynth` (Ben-Michael, Feller, and Rothstein), already used elsewhere in this chapter (see Section [Augmented Synthetic Control Method]), implements ridge-augmented synthetic control with explicit bias correction and is the recommended package when pre-treatment fit is poor.
A minimal `tidysynth` skeleton, parallel to the `Synth` example above, is:
```{r, eval=FALSE}
# install.packages("tidysynth")
library(tidysynth)
library(dplyr)
# `df` is a long-format panel with state, year, Y, X1, X2;
# state == "State A" is treated, intervention at year 15.
sc_out <- df %>%
synthetic_control(
outcome = Y,
unit = state,
time = year,
i_unit = "State A",
i_time = 15,
generate_placebos = TRUE
) %>%
generate_predictor(
time_window = 1:14,
X1_mean = mean(X1, na.rm = TRUE),
X2_mean = mean(X2, na.rm = TRUE)
) %>%
generate_weights(
optimization_window = 1:14,
margin_ipop = 0.02,
sigf_ipop = 7,
bound_ipop = 6
) %>%
generate_control()
sc_out %>% plot_trends()
sc_out %>% plot_placebos()
sc_out %>% grab_significance()
# See https://github.com/edunford/tidysynth for full examples.
```
The conceptual model is identical to `Synth`, a convex combination of donor units that minimizes pre-treatment outcome (and predictor) discrepancies, but the chained pipeline keeps the data, weights, and synthetic counterfactual bound to a single tibble-like object, which is convenient for embedding inside `dplyr`/`purrr` workflows and for batch placebo inference.
------------------------------------------------------------------------
#### Step 2: Estimating Generalized Synthetic Control with `gsynth`
Unlike `Synth`, the `gsynth` package supports:
- Iterative Fixed Effects (IFE) for unobserved heterogeneity.
- Multiple Treated Units and Staggered Adoption.
- Bootstrapped Standard Errors for inference.
Fit Generalized Synthetic Control Model
We use two-way fixed effects, cross-validation (`CV = TRUE`), and bootstrapped standard errors.
```{r}
gsynth.out <- gsynth(
Y ~ T + X1 + X2,
data = df,
index = c("state", "year"),
force = "two-way",
CV = TRUE,
r = c(0, 5),
se = TRUE,
inference = "parametric",
nboots = 100
)
```
The code below renders the GSC treatment-effect, counterfactual, and control-case panels for the simulated State A example.
```{r sc-gsynth-stateA}
# Plot Estimated Treatment Effects
plot(gsynth.out)
# Plot Counterfactual Trends
plot(gsynth.out, type = "counterfactual")
# Show Estimations for Control Cases
plot(gsynth.out, type = "counterfactual", raw = "all")
```
### The Basque Country Policy Change
The Basque Country in Spain implemented a major policy change in 1975, impacting its GDP per capita growth. This example uses SCM to estimate the counterfactual economic performance had the policy not been implemented.
We will:
1. Construct a synthetic control using economic predictors.
2. Evaluate the policy's impact by comparing the real and synthetic Basque GDP.
```{r}
library(Synth)
```
The `basque` dataset from `Synth` contains economic indicators for Spain's regions from 1955 to 1997.
```{r}
data("basque")
dim(basque) # 774 observations, 17 variables
head(basque)
```
#### Step 1: Preparing Data for `Synth`
We define predictors and specify pre-treatment (1960--1969) and post-treatment (1975--1997) periods.
```{r}
dataprep.out <- dataprep(
foo = basque,
predictors = c(
"school.illit",
"school.prim",
"school.med",
"school.high",
"school.post.high",
"invest"
),
predictors.op = "mean",
time.predictors.prior = 1964:1969,
# Pre-treatment period
special.predictors = list(
list("gdpcap", 1960:1969, "mean"),
list("sec.agriculture", seq(1961, 1969, 2), "mean"),
list("sec.energy", seq(1961, 1969, 2), "mean"),
list("sec.industry", seq(1961, 1969, 2), "mean"),
list("sec.construction", seq(1961, 1969, 2), "mean"),