This vignette illustrates the usage of improveSynth. For
a more general introduction to package MSCMT see its main vignette.
Estimating an SCM model involves searching for an approximate
solution of a nested optimization problem. Although the formulation of
the optimization problem is quite simple, finding a (good approximate)
solution can be hard for several reasons, see Becker and Klößner (2017) and Becker and Klößner (2018). While implementing
package MSCMT we put a lot of effort into the design of a
smart and robust (but still fast) optimization procedure.
Apart from function mscmt for the estimation of SCM
models based on our model syntax, we also included the convenience
function improveSynth, which implements checks for
feasibility and optimality of results delivered by package
Synth. Below, we illustrate how to use
improveSynth.
We exemplify the usage of improveSynth based on the
first example of function synth in package
Synth.
SynthThe following code is thus essentially borrowed from the
example section of the corresponding help page (all
comments have been removed):
## ##
## ## Synth Package: Implements Synthetic Control Methods.
## ## See https://web.stanford.edu/~jhain/synthpage.html for additional information.
data(synth.data)
dataprep.out <-
dataprep(
foo = synth.data,
predictors = c("X1", "X2", "X3"),
predictors.op = "mean",
dependent = "Y",
unit.variable = "unit.num",
time.variable = "year",
special.predictors = list(
list("Y", 1991, "mean"),
list("Y", 1985, "mean"),
list("Y", 1980, "mean")
),
treatment.identifier = 7,
controls.identifier = c(29, 2, 13, 17, 32, 38),
time.predictors.prior = c(1984:1989),
time.optimize.ssr = c(1984:1990),
unit.names.variable = "name",
time.plot = 1984:1996
)
synth.out <- synth(dataprep.out)We check the result by applying function improveSynth to
synth.out and dataprep.out:
## Results reported by package Synth
## =================================
##
## Optimal V : 0.00505551267760859 0.00409288890585646 0.19235843488426
## 0.261630304340057 2.34057592104407e-05 0.536839453433007
## Optimal W*(V): 0.000293389419727993 0.00339261939249764 0.162550271513035
## 0.220443622139723 0.613319164980641 9.32539782132895e-07
## with corresponding predictor loss ('loss W') of 0.006061391
## and corresponding dependent loss ('loss V') of 4.705198.
##
##
## Components of W*(V) do not sum to 1, dependent loss ('loss V') of
## rescaled W*(V) is 4.705198.
##
##
## Feasibility of W*(V)
## ====================
##
## WARNING: W*(V) is NOT optimal and thus infeasible!
## 'True' W*(V): 0 0.00262165114362921 0.158307709593535 0.221730231636334
## 0.617340407626502 0
## with corresponding predictor loss ('loss W') of 0.006055947
## and corresponding dependent loss ('loss V') of 4.703986.
##
##
## Optimality of V
## ===============
##
## WARNING: 'Optimal' V (as reported by package Synth) is not optimal (W*(V) was
## infeasible), (one of potentially many) 'true' optimal V* (with
## sum(V*)=1):
## Optimal V* : 4.99999934830043e-09 0.499999934830043 8.08430877022113e-09
## 1.15032358575281e-08 1.0575236923504e-07 0.499999934830043
## Optimal W*(V*): 0 0 0.0456889853433346 0.250556787966037 0.627177938912
## 0.0765762877786278
## with corresponding predictor loss ('loss W') of 6.563844e-09
## and corresponding dependent loss ('loss V') of 4.440945.
Package Synth generated a (slightly) infeasible
solution, returning a (slightly) suboptimal weight vector w
for the control units. However, the predictor weights v are
(considerably) suboptimal anyway, because the original dependent loss of
4.705198 (as well as the dependent loss for the corrected w
4.703986) is considerably larger than the dependent loss 4.440945 for
the optimal predictor weights obtained by improveSynth.
In the second example, we modify the first example by allowing
package Synth to use genoud as (outer)
optimization algorithm.
Synthgenoud is switched on by the corresponding function
argument. We capture the output with capture.output because
it is very verbose. Furthermore, the calculation is
quite lengthy, therefore the results have been cached.1
We again check the result by applying function
improveSynth to synth3.out and
dataprep.out:
## Results reported by package Synth
## =================================
##
## Optimal V : 2.0267533885719e-10 0.282598702518196 0.0021778890504857
## 0.00278189732871801 0.000373699249646763 0.712067811650278
## Optimal W*(V): 0.0420138249827668 0.0112849868071455 0.0223432791829297
## 0.218134146153805 0.595395073764248 0.110828688687666
## with corresponding predictor loss ('loss W') of 0.0001350879
## and corresponding dependent loss ('loss V') of 4.328506.
##
##
## Components of W*(V) do not sum to 1, dependent loss ('loss V') of
## rescaled W*(V) is 4.328506.
##
##
## Feasibility of W*(V)
## ====================
##
## WARNING: W*(V) is NOT optimal and thus infeasible!
## 'True' W*(V): 0 0 0 0.229091487590933 0.715755416007496 0.0551530964015712
## with corresponding predictor loss ('loss W') of 4.4355e-05
## and corresponding dependent loss ('loss V') of 6.09574.
##
##
## Optimality of V
## ===============
##
## WARNING: 'Optimal' V (as reported by package Synth) is not optimal (W*(V) was
## infeasible), (one of potentially many) 'true' optimal V* (with
## sum(V*)=1):
## Optimal V* : 4.99999934830043e-09 0.499999934830043 8.08430877022113e-09
## 1.15032358575281e-08 1.0575236923504e-07 0.499999934830043
## Optimal W*(V*): 0 0 0.0456889853433346 0.250556787966037 0.627177938912
## 0.0765762877786278
## with corresponding predictor loss ('loss W') of 6.563844e-09
## and corresponding dependent loss ('loss V') of 4.440945.
Now, package Synth generated a solution with a dependent
loss of 4.328506 which is even smaller than the dependent loss 4.440945
obtained by improveSynth. However, the solution generated
by Synth is severely infeasible: the inner
optimization failed, returning a suboptimal weight vector w
for the control units, which itself lead to a wrong calculation of the
dependent loss (which, of course, depends on w). Implanting
the true optimal w (depending on v) leads to a
large increase of the dependent loss, which uncovers the suboptimality
of v.
improveSynth is able to detect this severe problem and
calculates an improved and feasible solution (the improved
solution matches the solution obtained from the first call to
improveSynth above, with a dependent loss of 4.440945).
Issues with the inner and outer optimizers used in synth
from package Synth may lead to infeasible or suboptimal
solutions. This vignette illustrated the usage of the convenience
function improveSynth from package MSCMT for
checking and potentially improving results obtained from
synth.
To reproduce from scratch, please delete
"synth3.out.RData" from the vignettes
folder.↩︎