Checking and Improving Results of package Synth

knitr::opts_chunk$set(
  fig.width  = 7,
  fig.height = 4,
  fig.align  = "center",
#  cache      = TRUE,
  autodep    = TRUE
)

Introduction

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 @Mafia and @FastReliable. 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.

First Example

We exemplify the usage of improveSynth based on the first example of function synth in package Synth.

Generating the result of package Synth

The following code is thus essentially borrowed from the example section of the corresponding help page (all comments have been removed):

library(Synth)
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)

Checking the result

We check the result by applying function improveSynth to synth.out and dataprep.out:

library(MSCMT)
synth2.out <- improveSynth(synth.out,dataprep.out)

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 r round(synth.out$loss.v,6) (as well as the dependent loss for the corrected w r round(synth2.out$new.loss.v,6)) is considerably larger than the dependent loss r round(synth2.out$loss.v,6) for the optimal predictor weights obtained by improveSynth.

Second Example

In the second example, we modify the first example by allowing package Synth to use genoud as (outer) optimization algorithm.

Generating the result of package 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.^[To reproduce from scratch, please delete "synth3.out.RData" from the vignettes folder.]

if (file.exists("synth3.out.RData")) load ("synth3.out.RData") else {
  set.seed(42)
  out <- capture.output(synth3.out <- synth(dataprep.out,genoud=TRUE))
}  

Checking the result

We again check the result by applying function improveSynth to synth3.out and dataprep.out:

synth4.out <- improveSynth(synth3.out,dataprep.out)

Now, package Synth generated a solution with a dependent loss of r round(synth3.out$loss.v,6) which is even smaller than the dependent loss r round(synth2.out$loss.v,6) 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 r if(!isTRUE(all.equal(round(synth4.out$loss.v,6),round(synth2.out$loss.v,6)))) "essentially" else "" matches the solution obtained from the first call to improveSynth above, with a dependent loss of r round(synth4.out$loss.v,6)``r if(!isTRUE(all.equal(round(synth4.out$loss.v,6),round(synth2.out$loss.v,6)))) paste0("as compared to ",round(synth2.out$loss.v,6)," above") else "").

Summary

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.

References



Try the MSCMT package in your browser

Any scripts or data that you put into this service are public.

MSCMT documentation built on May 29, 2024, 11:29 a.m.