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
.
Synth
The 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)
##
## X1, X0, Z1, Z0 all come directly from dataprep object.
##
##
## ****************
## searching for synthetic control unit
##
##
## ****************
## ****************
## ****************
##
## MSPE (LOSS V): 4.336449
##
## solution.v:
## 3e-10 0.05280699 8.18e-08 7.8556e-06 0.02100039 0.9261847
##
## solution.w:
## 0.03731375 0.01107601 0.02654235 0.2187975 0.5977232 0.1085472
We check the result by applying function improveSynth
to
synth.out
and dataprep.out
:
## Results reported by package Synth
## =================================
##
## Optimal V : 2.58605456984468e-10 0.0528069911280163 8.17880000614617e-08
## 7.8555744885663e-06 0.0210003915149864 0.926184679735903
## Optimal W*(V): 0.0373137507322773 0.0110760128181821 0.0265423524102657
## 0.218797508784054 0.597723171666936 0.108547203218592
## with corresponding predictor loss ('loss W') of 6.493667e-05
## and corresponding dependent loss ('loss V') of 4.336449.
##
##
## Components of W*(V) do not sum to 1, dependent loss ('loss V') of
## rescaled W*(V) is 4.336449.
##
##
## Feasibility of W*(V)
## ====================
##
## WARNING: W*(V) is NOT optimal and thus infeasible!
## 'True' W*(V): 0 0 0 0.228673506839661 0.715612731748116 0.0557137614122222
## with corresponding predictor loss ('loss W') of 2.127212e-06
## and corresponding dependent loss ('loss V') of 6.061088.
##
##
## 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* : 7.184528113096e-09 0.7184528113096 1.52853700363516e-08
## 7.184528113096e-09 1.36202094308034e-07 0.281547022833879
## Optimal W*(V*): 0 0 0.0456857070977501 0.250555275845772 0.627184223918666
## 0.0765747931378118
## with corresponding predictor loss ('loss W') of 9.54466e-09
## and corresponding dependent loss ('loss V') of 4.440946.
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.336449 (as well as the dependent loss for the corrected w
6.061088) is considerably larger than the dependent loss 4.440946 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.
Synth
genoud
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.0551530964015713
## 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* : 7.184528113096e-09 0.7184528113096 1.52853700363516e-08
## 7.184528113096e-09 1.36202094308034e-07 0.281547022833879
## Optimal W*(V*): 0 0 0.0456857070977501 0.250555275845772 0.627184223918666
## 0.0765747931378118
## with corresponding predictor loss ('loss W') of 9.54466e-09
## and corresponding dependent loss ('loss V') of 4.440946.
Now, package Synth
generated a solution with a dependent
loss of 4.328506 which is even smaller than the dependent loss 4.440946
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.440946).
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.↩︎