--- title: "Optimizing an intervention with LAGO" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Optimizing an intervention with LAGO} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(LAGOtrials) ``` Learn-As-you-GO (LAGO) trials adapt a multi-component intervention as the trial proceeds. At each stage the intervention is refined using the data collected so far, so that the next stage moves toward an intervention that is effective and affordable. The `LAGOtrials` package fits the outcome model, recommends the lowest-cost intervention package that is expected to meet an outcome goal (and, optionally, a power goal), and computes a confidence set for that recommendation. This vignette walks through a single optimization on the BetterBirth data that ships with the package. For the full argument reference see `?lago_optimization`; for other worked examples see the [manual tests](https://github.com/correspondMerchant/LAGO-R-Package/tree/main/tests/manual_tests) folder. ## The data `BB_data` is a cleaned version of the BetterBirth study, a trial of the World Health Organization's Safe Childbirth Checklist in Uttar Pradesh, India. The binary outcome `pp3_oxytocin_mother` records whether oxytocin was administered. We treat two intervention components as adjustable: `coaching_updt` (number of coaching visits) and `launch_duration` (days of checklist launch). ```{r} bb_data <- BB_data head(bb_data[, c("coaching_updt", "launch_duration", "pp3_oxytocin_mother")]) ``` ## Recommending an intervention Suppose we want the least costly intervention that raises the probability of oxytocin administration to at least `0.85`, for a center with a birth volume of 1.75 (in hundreds). The costs of the two components are `1.7` and `8` per unit, respectively. ```{r} result <- lago_optimization( data = bb_data, outcome_name = "pp3_oxytocin_mother", outcome_type = "binary", intervention_components = c("coaching_updt", "launch_duration"), intervention_lower_bounds = c(1, 1), intervention_upper_bounds = c(40, 5), center_characteristics = "birth_volume_100", center_characteristics_optimization_values = 1.75, cost_list_of_vectors = list(c(0, 1700), c(0, 8000)), outcome_goal = 0.85, outcome_goal_intention = "maximize", confidence_set_grid_step_size = c(1, 0.5), quiet = TRUE ) ``` The `quiet = TRUE` argument suppresses the progress messages so the vignette output stays clean; it does not change the result. The returned object has a `print()` method that shows the full result on the console: an inputs recap, the fitted outcome-model coefficient table, the overall intervention-effect test, the recommended intervention with its cost and the estimated-outcome confidence interval, and the confidence set: ```{r} result ``` `summary()` renders the same output: ```{r} summary(result) ``` The recommended intervention and its cost are available directly: ```{r} result$rec_int result$rec_int_cost ``` ## Visualizing the confidence set `plot()` shows the 95% confidence set with the recommended intervention highlighted: ```{r, fig.width = 6, fig.height = 4} plot(result) ``` ## Adding a power goal For a binary outcome we can also require a minimum power for the next stage. A power goal needs a `group` column ("treatment" / "control") and the size of the next stage. If the trial is clustered, the power calculation can additionally account for within-center correlation through the `icc` argument (with `power_goal_cluster_id` naming the clustering column); see `?lago_optimization`. The example below uses a power goal alone. ```{r} bb_data$group <- ifelse(bb_data$pre_post == 0, "control", "treatment") power_result <- lago_optimization( data = bb_data, outcome_name = "pp3_oxytocin_mother", outcome_type = "binary", intervention_components = c("coaching_updt", "launch_duration"), intervention_lower_bounds = c(1, 1), intervention_upper_bounds = c(40, 5), center_characteristics = "birth_volume_100", center_characteristics_optimization_values = 1.75, cost_list_of_vectors = list(c(0, 1700), c(0, 8000)), power_goal = 0.8, num_centers_in_next_stage = 10, patients_per_center_in_next_stage = 30, include_confidence_set = FALSE, quiet = TRUE ) power_result$est_outcome_goal ``` When both an outcome goal and a power goal are supplied, the optimization targets the higher of the two: the outcome goal itself, or the outcome level implied by the power goal. ## How sensitive is the recommendation? The recommendation depends on inputs you may be unsure about, above all the outcome goal and the assumed costs. `lago_sensitivity()` re-runs the optimization across a sweep of one input and reports how the recommendation, its cost, and the estimated outcome move. The easiest way is to hand it the fitted `result` from above: it reuses that call, so you only add `parameter` (what to vary) and `values` (the sweep). Here we ask how the recommended cost changes as the target probability tightens from 0.75 to 0.90. The confidence set is not needed for this, so `lago_sensitivity()` skips it and the sweep is fast. ```{r} sens <- lago_sensitivity( result, parameter = "outcome_goal", values = c(0.75, 0.80, 0.85, 0.90) ) sens ``` The result is a tidy data frame with one row per swept value: the value, the recommended value of each component, the recommended cost, the estimated outcome, and a `status` column (a run that fails is recorded as `NA` rather than stopping the sweep). `plot()` draws the recommended cost as a function of the swept value: ```{r, fig.width = 6, fig.height = 4} plot(sens) ``` To vary the costs instead, use `parameter = "cost_multiplier"` with, say, `values = c(0.8, 1, 1.2)` to scale every cost by plus or minus 20%.