One complete, runnable script: design a two-arm experiment with a
continuous outcome, assign treatment, record responses, and run every
matched inference procedure. Every chunk executes when the vignette is
built; copy the whole thing into a session and it works. The other
cookbooks (vignette("cookbook-incidence"),
-count, -proportion, -survival,
-ordinal) follow exactly this shape, differing only in the
response and the inference class.
The pattern is always the same four steps:
Design for n
subjects and a response_type;Inference class on the
completed design and call its methods — or hand the design to
InferenceSuite to run every applicable procedure at
once.EDI is not on CRAN yet, so install.packages("EDI") fails
— install the prebuilt binaries from R-universe instead (fallback:
straight from GitHub; the R package is the R/EDI
subdirectory). Not evaluated here: the vignette builds inside an
already-installed package.
DesignFixedBernoulli assigns each subject by an
independent coin flip — the simplest fixed design, and the one under
which every inference method is valid without caveat. Subjects are added
all at once, assigned all at once, and responses recorded all at
once.
InferenceContinOLS regresses the response on treatment
and the covariates. Every inference class exposes the same core verbs: a
point estimate, an asymptotic (Wald) interval and p-value, a
randomization test that re-randomizes under the design’s own mechanism,
and — for fixed designs — a nonparametric bootstrap.
inf = InferenceContinOLS$new(des, verbose = FALSE)
inf$num_cores = 1L
inf$compute_estimate()
#> [1] 3.296457
inf$compute_asymp_confidence_interval(alpha = 0.05)
#> 2.5% 97.5%
#> 1.517762 5.075152
inf$compute_asymp_two_sided_pval()
#> [1] 0.000478099The randomization test uses no distributional assumption: it re-draws
treatment r times from the same design and compares the
observed statistic to that reference distribution.
set_seed() makes the result reproducible (see
vignette("reproducibility")).
Bootstrap intervals resample subjects (the design’s own resampling structure — rows here; matched pairs for matched designs):
InferenceSuiteInferenceSuite discovers every inference class
compatible with this design and response type, runs each applicable
procedure, and reports a single Cauchy-combined p-value across them.
With screen = TRUE it prints the full results table — the
one-call answer to “what does every valid analysis say?” — and returns
the same results as an object (res) for programmatic
use.
By default it runs every method each class supports,
including the resampling ones (randomization, bootstrap, Bayesian
bootstrap, jackknife) at their full default replicate counts — a few
minutes per class, which is exactly what you want for a real analysis
but not inside a vignette that rebuilds on every
R CMD check. So this chunk restricts methods
to the asymptotic procedures ("wald", "score",
"lik_ratio"; classes that don’t support one simply skip it)
and sets a per-class time guard. Drop the methods argument
to get the complete report.
suite = InferenceSuite$new(des)
res = suite$run_all_inference(screen = TRUE, plots = FALSE, num_cores = 1L,
methods = c("wald", "score", "lik_ratio"), max_secs_per_class = 15)
#> inference cov estimand est se pval pval method status
#> class mod
#> ===========================================================================================
#> Classes 0/11 [ 0% ] Status: Estimating...[KAvg Δ mean Δ 3.31 0.820 2.34e-04 wald ok
#> Classes 1/11 [=== 9% ] Estimated Time Left: 1s[KAvg Δ Pooled … mean Δ 3.31 0.895 4.76e-04 wald ok
#> Classes 2/11 [====== 18% ] Estimated Time Left: 0s[KWilcox HL shift 3.24 0.930 9.17e-04 wald ok
#> Classes 3/11 [========= 27% ] Estimated Time Left: 1s[KLin ~. mean Δ 3.35 0.846 2.32e-04 wald ok
#> Classes 4/11 [============ 36% ] Estimated Time Left: 1s[KLin ~. mean Δ 3.35 0.846 2.35e-04 score ok
#> Classes 5/11 [============== 45% ] Estimated Time Left: 1s[KLin ~. mean Δ 3.35 0.846 2.35e-04 lik_ratio ok
#> Classes 6/11 [============== 54% ] Estimated Time Left: 0s[KOLS ~. mean Δ 3.30 0.888 4.78e-04 wald ok
#> Classes 7/11 [============== 63% == ] Estimated Time Left: 0s[KOLS ~. mean Δ 3.30 0.888 2.04e-04 score ok
#> Classes 8/11 [============== 72% ===== ] Estimated Time Left: 0s[KOLS ~. mean Δ 3.30 0.888 2.04e-04 lik_ratio ok
#> Classes 9/11 [============== 81% ======== ] Estimated Time Left: 0s[KMedian Regr ~. median ef… 2.95 1.20 1.68e-02 wald ok
#> Classes 10/11 [============== 90% =========== ] Estimated Time Left: 0s[KRobust Regr ~. mean Δ 3.29 0.919 7.19e-04 wald ok
#> Classes 11/11 [============= 100% ==============] Estimated Time Left: 0s[K-------------------------------------------------------------------------------------------
#> Status: Completed in 1s.
#>
#> Estimand: HL shift (1 inferences) : p = NA
#> Estimand: mean Δ (9 inferences) : p = 0.000277
#> Estimand: median effect (1 inferences): p = NA
#>
#> Combined evidence against the sharp null across 3 estimands
#> (11 inferences, weighting = uniform within estimand):
#> p = 0.00063Most real trials enroll sequentially.
DesignSeqOneByOneKK21 — the Kapelner–Krieger
matching-on-the-fly design — decides each arrival’s treatment by trying
to match it to an earlier unmatched subject on the covariates (using the
reservoir of unmatched subjects otherwise), so covariate balance is
built as the trial runs. The API changes only at step 2: assign and
record per subject.
des_seq = DesignSeqOneByOneKK21$new(n = n, response_type = "continuous", verbose = FALSE)
for (i in seq_len(n)) {
w_i = des_seq$add_one_subject_to_experiment_and_assign(X[i, , drop = FALSE])
y_i = 10 + true_effect * w_i + 0.1 * X$age[i] - 0.3 * X$bmi[i] + rnorm(1, sd = 3)
des_seq$add_one_subject_response(i, y_i)
}The matched inference class for this design,
InferenceContinKKOLSIVWC, combines a within-pair estimate
with the reservoir’s estimate (inverse- variance weighted). Note the
nonparametric bootstrap is not offered on sequential
designs whose assignment depends on earlier subjects (row resampling
would not replicate the design); the randomization test, which replays
the design’s actual mechanism, is the right tool here.
inf_seq = InferenceContinKKOLSIVWC$new(des_seq, verbose = FALSE)
inf_seq$num_cores = 1L
inf_seq$compute_estimate()
#> [1] 2.607908
inf_seq$compute_asymp_confidence_interval(alpha = 0.05)
#> 2.5% 97.5%
#> 1.349205 3.866610
inf_seq$set_seed(1)
inf_seq$compute_rand_two_sided_pval(r = 200, show_progress = FALSE)
#> [1] NAvignette("validation-evidence").vignette("reproducibility").SimulationFramework (see its reference page’s
\donttest{} example).