Changelog
Source:NEWS.md
attrition 1.0.0
First release.
New features
Formula interface on all estimators:
estimator_ev(Y ~ Z, R = "R", ...),estimator_ds(Y ~ Z, R1 = "R1", Attempt = "Attempt", R2 = "R2", ...), and likewise forestimator_trim(),estimator_ds_sens(), andsensitivity_ds(). Response, attempt, and stratification arguments accept either an unquoted column name or a quoted string. The formula form is whatDeclareDesign::declare_estimator(.method = ...)expects.tidy()methods for all estimator output classes (attrition_bounds,attrition_trim) via thegenericspackage. Each method returns a three-row tibble with rows"bounds","lower_bound", and"upper_bound", suitable for use with DeclareDesign. The"bounds"row carries the joint Imbens-Manski confidence interval inconf.low/conf.highand the bound point estimates inestimate.low/estimate.high; the individual rows carry point estimates and standard errors selectable via thetermargument.S3 classes on all estimator return values:
estimator_ds()returns classc("attrition_ds", "attrition_bounds"),estimator_ev()returnsc("attrition_ev", "attrition_bounds"),estimator_ds_sens()returnsc("attrition_ds_sens", "attrition_bounds"), andestimator_trim()returnsc("attrition_trim").Stratified estimators now index results by name rather than position, preventing silent errors if the output vector order ever changes.
sensitivity_ds()no longer callsrequire()at runtime; all dependencies are declared via@importFrom.reshape2dependency replaced bytibble;genericsadded fortidyre-export.-
estimator_trim()gains standard errors and confidence intervals, via a newseargument.se = "analytic"(the default) uses the closed-form asymptotic variance of Lee (2009), Proposition 3, and covers the single-stageRpath.se = "bootstrap"resamples units within treatment arm and covers both that path and the weighted double-sampling path, for which no analytic variance exists in the literature.se = "none"returns bounds alone. The bound standard errors feed the existing Imbens-Manski machinery, sotidy.attrition_trim()now returnsstd.error,conf.lowandconf.highinstead ofNAthroughout.The analytic variance was validated three ways: Lee’s published term for the estimated trimming proportion agrees to machine precision with the algebraically distinct form used by Tauchmann’s Stata
leebounds; the mean analytic standard error tracks the Monte Carlo standard deviation of the estimator across sample sizes from 1,000 to 64,000; and a conventional 95% interval around each bound endpoint covers the true population endpoint 95.4% and 94.9% of the time.Requesting
se = "analytic"on the double-sampling path is an error rather than a silent substitution, since Lee’s derivation assumes i.i.d. sampling and trimming of one group only. A zero trimming proportion warns, because the bounds then collapse to a point on the boundary of the parameter space and Lee’s interior-point condition fails. Worked examples on every exported function.
A second vignette, “Drawing the extreme value bounds”, which draws the imputation that
estimator_ev()averages over usingvayrand checks that a difference in means inside each imputed scenario recovers the two bound estimates. It also shows why the Imbens-Manski interval is narrower than stacking a confidence interval on each bound.vayrandestimatrare suggested packages and the vignette does not evaluate without them.
Bug fixes
The Imbens-Manski critical value was found by minimizing an absolute value with
optim(..., method = "Brent", lower = 1, upper = 2). That interval only covers alpha near 0.05, so at other significance levels the optimizer returned a boundary value and the confidence intervals were silently wrong: atalpha = 0.01it returned 2.000 against a correct 2.326, and atalpha = 0.001it returned 2.000 against a correct 3.090. The search interval is now derived from alpha, and the root is found withuniroot()on the signed coverage excess rather than by minimizing its absolute value. Bound point estimates and variances are unaffected.estimator_trim()reported every failure insidetrimming_bounds()as a monotonicity violation, because it caught all errors and returnedNAbounds. It now catches only a classed monotonicity condition.The monotonicity violation message named the wrong group.
Q < 0means the treatment group is more likely to be missing than the control group.trimming_bounds()built its weighted CDFs with a loop that counted backwards when a treatment group had one observed outcome, silently appending anNA, and threw an opaque error when a group had none. Both are nowcumsum(), with an explicit check for empty groups.sensitivity_ds()could not detect a delta* at the last point of the delta grid, reporting a genuine crossing near delta = 1 as no crossing at all.minY,maxY,alpha,delta, andsimsare validated. Previously a reversedminY/maxYreturned a lower bound above the upper bound, an assumed support that did not cover the observed outcomes returned bounds that are not bounds, and adeltaoutside[0, 1]returnedNaNvariances.estimator_ev(): fixed a copy-paste error wheren1_c_swas incorrectly referenced asn1_c_cin the unstratified path.estimator_ds()andestimator_ds_sens(): replaced a commented-out sentinel initialization (-99) withNA_real_forc1a_t,c1r_t,c2a_t,c2r_t. These arguments were never used and have since been removed from the internal estimators altogether.