---
title: "Coming from the Stata package"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Coming from the Stata package}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 6,
  fig.height = 4,
  dpi = 150
)
library(regsensitivity)
library(ggplot2)
```

The reference implementation of these methods is Masten and Poirier's Stata
package, also called `regsensitivity`. This vignette maps its syntax onto
this package, command by command, using the same BFG (2020) data that the
Stata vignette uses.

It doubles as a coverage check. Every command in the Stata package's own
vignette (shipped here as `inst/stata-reference/vignette.do`) appears
below with its R equivalent, so a gap would be visible rather than
implicit.

```{r data}
data(bfg2020)
bfg2020$statea <- factor(bfg2020$statea)

w1 <- c("log_area_2010", "lat", "lon", "temp_mean", "rain_mean",
        "elev_mean", "d_coa", "d_riv", "d_lak", "ave_gyi")

form <- avgrep2000to2016 ~ tye_tfe890_500kNI_100_l6 +
    log_area_2010 + lat + lon + temp_mean + rain_mean + elev_mean +
    d_coa + d_riv + d_lak + ave_gyi + statea
```

In Stata the outcome, treatment and controls are positional and the
comparison set is named separately:

```stata
local y avgrep2000to2016
local x tye_tfe890_500kNI_100_l6
local w1 log_area_2010 lat lon temp_mean rain_mean elev_mean d_coa d_riv d_lak ave_gyi
local w0 i.statea
regsensitivity `y' `x' `w1' `w0', compare(`w1')
```

In R the same information is a formula plus `compare`. The first term on
the right-hand side is the treatment; everything else is a control.

```{r compare-map, echo = FALSE, out.width = "100%", fig.alt = "A regsen_summary call with braces under its parts: y is the outcome Y, x is the treatment X, the terms named by compare are the calibration covariates W1, and the remaining right-hand-side terms are the control covariates W0, which are partialled out. A dashed circle stands for the unobserved W2, which appears in no formula."}
knitr::include_graphics("figures/covariates.png")
```

`compare` and `nocompare` are two ways of drawing the same line, and you may
give at most one of them: `compare` names the calibration set $W_1$,
`nocompare` names its complement $W_0$. Give neither and every control
enters $W_1$.

## Command map

| Stata | R |
|---|---|
| `regsensitivity y x w, compare(w1)` | `regsen_summary(form, data, compare = w1)` |
| `regsensitivity bounds ...` | `regsen_bounds(form, data, ...)` |
| `regsensitivity breakdown ...` | `regsen_breakdown(form, data, ...)` |
| `regsensitivity plot` | `plot(result)` |
| `compare(w1)` | `compare = w1` |
| `nocompare(w0)` | `nocompare = w0` |
| `cbar(0(.2)1)` | `cbar = seq(0, 1, 0.2)` |
| `rxbar(0 2)` | `rxbar = c(0, 2)` |
| `rybar(2)` | `rybar = 2` |
| `rybar(=rxbar)` | `rybar_expr = function(rx) rx` |
| `beta(0 eq)` | `beta = bnd_eq(0)` |
| `beta(4 ub)` | `beta = bnd_ub(4)` |
| `beta(-1(.2)1 lb)` | `beta = bnd_lb(seq(-1, 1, 0.2))` |
| `beta(sign)` | `beta = "sign"` (the default) |
| `oster` | `analysis = "oster"` |
| `delta(-3 3 eq)` | `delta = c(-3, 3)`, `delta_type = "eq"` |
| `delta(0(.001).999 bound)` | `delta = seq(0, .999, .001)`, `delta_type = "bound"` |
| `rmax(0(.1)1)` | `r2long = seq(0, 1, 0.1)` |
| `plot, nolegend` | `plot(res, show_legend = FALSE)` |
| `plot, yrange(0 6)` | `plot(res, ylim = c(0, 6))` |
| `plot, ywidth(4)` | `plot(res, ywidth = 4)` |
| `plot, xline(1)` | `plot(res, xline = 1)` |
| `e(idset_table)` | `as.data.frame(res)` |
| `cluster(v)` on the regression | `regsen_boot(..., cluster = "v")` |

Two differences are worth flagging rather than burying in the table.

Stata's `numlist` syntax `0(.2)1` means "from 0 to 1 in steps of .2",
which is `seq(0, 1, 0.2)`. And Stata stores results in `e()` matrices
retrieved with matrix subscripts; here the results are already a data
frame, so `as.data.frame(res)` gives you the same content directly.

## The Stata vignette, translated

### Default summary

```stata
regsensitivity `y' `x' `w', compare(`w1')
```

```{r summary}
summ <- regsen_summary(form, bfg2020, compare = w1)
summ
```

### Bounds at a single `cbar`

```stata
regsensitivity bounds `y' `x' `w', compare(`w1') cbar(.1)
regsensitivity plot
```

```{r bounds-one}
b1 <- regsen_bounds(form, bfg2020, compare = w1, cbar = 0.1)
plot(b1)
```

### Bounds over a grid of `cbar`

```stata
regsensitivity bounds `y' `x' `w', compare(`w1') cbar(0(.2)1)
```

```{r bounds-grid}
b2 <- regsen_bounds(form, bfg2020, compare = w1,
                     cbar = seq(0, 1, 0.2))
plot(b2)
```

### Restricting `rxbar` as well

```stata
regsensitivity bounds `y' `x' `w', compare(`w1') cbar(0(.2)1) rxbar(0 2) plot
```

```{r bounds-rxbar}
b3 <- regsen_bounds(form, bfg2020, compare = w1,
                     cbar = seq(0, 1, 0.2), rxbar = c(0, 2))
plot(b3)
```

### Breakdown frontier

```stata
regsensitivity breakdown `y' `x' `w', compare(`w1') cbar(0(.1)1)
regsensitivity plot
```

```{r breakdown}
bd <- regsen_breakdown(form, bfg2020, compare = w1,
                        cbar = seq(0, 1, 0.1))
plot(bd)
```

### Breakdown for a one-sided hypothesis

```stata
regsensitivity breakdown `y' `x' `w', compare(`w1') cbar(0(.1)1) beta(4 ub)
```

```{r breakdown-ub}
bd_ub <- regsen_breakdown(form, bfg2020, compare = w1,
                           cbar = seq(0, 1, 0.1), beta = bnd_ub(4))
bd_ub
```

### Bounding the unobservable's effect on the outcome

```stata
regsensitivity bounds `y' `x' `w', compare(`w1') rybar(2)
regsensitivity bounds `y' `x' `w', compare(`w1') rybar(=rxbar)
```

```{r rybar}
b_ry  <- regsen_bounds(form, bfg2020, compare = w1, rybar = 2)
b_eq  <- regsen_bounds(form, bfg2020, compare = w1,
                        rybar_expr = function(rx) rx)
c(rybar_2 = b_ry$breakdown, rybar_eq = b_eq$breakdown)
```

### Oster (2019)

```stata
regsensitivity bounds `y' `x' `w', compare(`w1') oster
regsensitivity bounds `y' `x' `w', compare(`w1') oster delta(-3 3 eq) plot
regsensitivity plot, xline(1)
```

`xline()` marks a reference value on the x-axis; here it is
$R^2_{max} = 1$, the point past which the assumed long-regression fit
would exceed a perfect one.

Stata's `delta(-3 3 eq)` names the *endpoints* of a range and fills in
the grid itself. `delta` here is the grid, so pass the whole sequence:
`delta = c(-3, 3)` asks for the identified set at exactly two values of
$\delta$, and a curve through two points is not a curve.

```{r oster}
os <- regsen_bounds(form, bfg2020, compare = w1,
                     analysis = "oster",
                     delta = seq(-3, 3, 0.05), delta_type = "eq")
plot(os, ylim = c(-5, 8), xline = 1)
```

### Oster breakdown over `rmax`

```stata
regsensitivity breakdown `y' `x' `w', compare(`w1') oster rmax(0(.1)1) beta(0 eq)
regsensitivity breakdown `y' `x' `w', compare(`w1') oster rmax(0(.1)1) beta(sign)
```

```{r oster-breakdown}
os_bd <- regsen_breakdown(form, bfg2020, compare = w1,
                           analysis = "oster",
                           r2long = seq(0, 1, 0.1),
                           beta = bnd_eq(0))
os_sign <- regsen_breakdown(form, bfg2020, compare = w1,
                             analysis = "oster",
                             r2long = seq(0, 1, 0.1),
                             beta = "sign")
c(explain_away = os_bd$results$breakdown[1],
  sign_change  = os_sign$results$breakdown[1])
plot(os_sign)
```

## Coverage

Every option exercised by the Stata vignette has an equivalent above. The
one behaviour that is *not* carried over is Stata's habit of leaving
results in `e()` for the next command to pick up: `regsensitivity plot`
with no arguments replots whatever ran last. Here each function returns
its result and `plot()` takes it explicitly, which is what lets you keep
several analyses side by side in one session.

## Beyond the Stata package

Three things here have no Stata counterpart, so nothing in the table
above maps onto them.

`direction = "rybar"` reports the breakdown point in `rybar` at a given
`rxbar` rather than the other way round -- the frontier of DMP Theorem 4,
and the only direction that can describe the part of it where no `rxbar`
overturns the conclusion.

```{r direction}
regsen_breakdown(form, bfg2020, compare = w1, cbar = 1,
                  direction = "rybar",
                  rxbar = c(0.5, 1, 2, 4))$results
```

`clow` is the lower end of Assumption A6, asserting that the controls are
*at least* that endogenous, which narrows the identified set.

```{r clow}
regsen_bounds(form, bfg2020, compare = w1, cbar = 1, clow = 0.99,
               rxbar = c(0.5, 0.9))$results
```

And the identified set is computed for every triple of sensitivity
parameters, including `rxbar > rmax(cbar) > rybar`, where both packages
previously stopped:

```{r region}
regsen_bounds(form, bfg2020, compare = w1, cbar = 1,
               rxbar = 2, rybar = 0.5)$results
```

