diff --git a/docs/decisions.md b/docs/decisions.md index 0b543d7..ae71ab9 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -102,3 +102,4 @@ Each decision is listed with the date and the reason for it. Settled decisions a | 48 | **The PVI model is fitted separately inside the window (month indicators) and in the deferred period (spline in month).** | A pooled model misspecified the window probabilities that the CCW and sequential weights depend on. | | 49 | **V2 is the V1 fit with a physician-cluster-robust SE.** Under V4, physicians without an estimable fixed effect in a phase get probability 0, and the V4 population is restricted to physicians with variation in early PVI. | Same point estimate by construction (D15). | | 50 | **Validation (W0, harm, 40 replicates of 50,000):** CCW A−B1 is +5.12 vs a truth of +5.11 on the disease composite (z = 0.0); sequential ITT is +5.83 vs +5.71 (z = 0.6); MALE and NCO-1 have |z| ≤ 0.7. The model SE is 0–20% below the empirical SE for CCW, so the bootstrap check in D28 still needs doing. | Plan §15 validation (a). | +| 51 | **Speed and scale.** The PVI model is fitted once per replicate and variant, and shared by CCW and the sequential trials. CCW clones and weights are built once for all outcomes. The deferred-period PVI model uses every PVI plus a fixed 10% sample of the other person-months, with offset log(10). On W0 validation the estimates are identical to 4 decimals. The main designs take about 39 s per replicate instead of about 130 s. **Scale:** n = 50,000 stays. Draft is 100 replicates; final is 200 replicates (replacing 500 in D29), and the final run extends the draft's replicates 1–100. Total about 12 hours on 11 cores. | User asked for a faster, smaller run. The sample size is not reduced, because CCW's strategy A already depends on about 250 patients treated in month 5 at n = 50,000. With 200 replicates, MCSE of bias ≈ empirical SE / 14 (CCW about 0.2 pp) and MCSE of coverage ≈ 1.5%. | diff --git a/pvisim/R/estimators.R b/pvisim/R/estimators.R index b108bb8..f6cd999 100644 --- a/pvisim/R/estimators.R +++ b/pvisim/R/estimators.R @@ -51,31 +51,45 @@ fit_pvi <- function(data, newdata, variant, extra_covs = NULL) { d <- data[win == w] nd <- newdata[i_new] tt_levels <- if (w == 1L) "factor(tt)" else "splines::ns(t, df = 4)" + # deferred period (about 2 million person-months, few PVIs): fit on every PVI and a + # fixed 10% sample of the other months, with offset log(1/0.1) so the coefficients + # are those of the full model (case-control sampling of person-months) + if (w == 0L) d <- sample_controls(d, frac = 0.1) # no exposure at all in a phase (the NCE after the window): probability 0 out[i_new] <- if (sum(d$pvi) == 0) 0 else fit_pvi_phase(d, nd, variant, tt_levels, extra_covs) } out } +#' Keep all events and a deterministic fraction of non-events; offset column `off`. +sample_controls <- function(d, frac) { + keep <- d$pvi == 1L | (((d$id * 7919L + d$t * 104729L) %% 1000L) < frac * 1000) + d <- d[keep] + d[, off := log(1 / frac)] # sampling raises every row's odds by 1/frac + d +} + fit_pvi_phase <- function(d, nd, variant, time_terms, extra_covs = NULL) { + if (!"off" %in% names(d)) d[, off := 0] + nd <- copy(nd)[, off := 0] # predictions are for the full population covs <- c(BASE_COVS, "sev_obs", "sev0", extra_covs) if (variant == "V4_within") covs <- setdiff(covs, "obl") rhs <- paste(c(covs, time_terms), collapse = " + ") if (variant %in% c("V1_ignore", "V2_cluster")) { f <- as.formula(paste("~", rhs)) X <- model.matrix(f, d) - fit <- fastglm::fastglm(X, d$pvi, family = binomial(), method = 2) + fit <- fastglm::fastglm(X, d$pvi, family = binomial(), method = 2, offset = d$off) b <- coef(fit); b[is.na(b)] <- 0 Xn <- model.matrix(f, nd) return(as.vector(plogis(Xn %*% b))) } if (variant == "V3_random") { - fit <- lme4::glmer(as.formula(paste("pvi ~", rhs, "+ (1 | phys_id)")), data = d, + fit <- lme4::glmer(as.formula(paste("pvi ~", rhs, "+ offset(off) + (1 | phys_id)")), data = d, family = binomial(), nAGQ = 0, control = lme4::glmerControl(calc.derivs = FALSE)) return(as.vector(predict(fit, newdata = nd, type = "response", allow.new.levels = TRUE))) } if (variant == "V4_within") { - fit <- fixest::feglm(as.formula(paste("pvi ~", rhs, "| phys_id")), data = d, + fit <- fixest::feglm(as.formula(paste("pvi ~", rhs, "| phys_id")), data = d, offset = ~off, family = binomial(), notes = FALSE, warn = FALSE) pr <- as.vector(predict(fit, newdata = nd, type = "response")) pr[is.na(pr)] <- 0 @@ -162,22 +176,33 @@ restrict_variant <- function(rec, variant) { #' patient-level for V1, physician-cluster-robust for V2-V4. run_design <- function(rec, design, variant, outcomes = c(male = "t_male", disease = "t_disease", nco1 = "t_nco1", nco2 = "t_nco2")) { + run_designs(rec, design, variant, outcomes) +} + +#' Several designs under one variant, sharing the PVI fit between CCW and sequential +#' trials (the sequential propensity score is the window part of the same model). +run_designs <- function(rec, designs, variant, outcomes = c(male = "t_male", disease = "t_disease", + nco1 = "t_nco1", nco2 = "t_nco2")) { rec <- restrict_variant(rec, variant) - rs <- if (design %in% c("ccw", "seq")) pvi_risk_set(rec) else NULL - phat <- if (design == "ccw") fit_pvi(rs, rs, variant, rec$extra_covs) else NULL + need <- intersect(designs, c("ccw", "seq")) + rs <- if (length(need)) pvi_risk_set(rec) else NULL + phat <- if ("ccw" %in% need) fit_pvi(rs, rs, variant, rec$extra_covs) + else if ("seq" %in% need) { x <- rep(NA_real_, nrow(rs)); w <- rs$win == 1L + x[w] <- fit_pvi(rs[w], rs[w], variant, rec$extra_covs); x } cmp <- if (is.null(rec$comparators)) c("B1", "B2") else rec$comparators - out <- lapply(names(outcomes), function(o) { + use_patient <- variant == "V1_ignore" + rbindlist(lapply(designs, function(design) { r <- switch(design, - naive = cbind(contrast = "early_none", est_naive(rec, outcomes[[o]], variant)), - landmark = cbind(contrast = "early_none", est_landmark(rec, outcomes[[o]], variant, extra_covs = rec$extra_covs)), - ccw = est_ccw(rec, outcomes[[o]], variant, rs = copy(rs), phat = phat, comparators = cmp), - seq = cbind(contrast = "now_not", est_seq(rec, outcomes[[o]], variant, rs = copy(rs)))) - r[, `:=`(outcome = o, design = design, variant = variant, n = nrow(rec$patients))] - use_patient <- variant == "V1_ignore" + naive = rbindlist(lapply(names(outcomes), function(o) + cbind(contrast = "early_none", est_naive(rec, outcomes[[o]], variant), outcome = o))), + landmark = rbindlist(lapply(names(outcomes), function(o) + cbind(contrast = "early_none", est_landmark(rec, outcomes[[o]], variant, extra_covs = rec$extra_covs), outcome = o))), + ccw = est_ccw(rec, outcomes, variant, rs = copy(rs), phat = phat, comparators = cmp), + seq = cbind(contrast = "now_not", est_seq(rec, outcomes, variant, rs = copy(rs), phat = phat))) + r[, `:=`(design = design, variant = variant, n = nrow(rec$patients))] r[, se := if (use_patient) se_patient else se_cluster] r - }) - rbindlist(out, fill = TRUE) + }), fill = TRUE) } #' Naive "ever early PVI" design: exposure = PVI in months 0..W-1, follow-up from month 0, @@ -237,13 +262,14 @@ est_ccw <- function(rec, outcome = "t_male", variant = "V1_ignore", horizon = 60 comparators = c("B1", "B2"), rs = NULL, phat = NULL) { W <- rec$par$size$window if (is.null(rs)) rs <- pvi_risk_set(rec) - if (is.null(phat)) phat <- fit_pvi(rs, rs, variant) + if (is.null(phat)) phat <- fit_pvi(rs, rs, variant, rec$extra_covs) rs[, ph := phat] rs <- rs[!is.na(ph)] # everyone eligible at diagnosis is cloned, including patients with a MALE event or - # death in month 0 (events in the grace period count in both arms) + # death in month 0 (events in the grace period count in both arms). Clones and weights + # are built once over follow-up to death or the horizon; each outcome then truncates. p <- copy(rec$patients) - p[, t_out := get(outcome)] + p[, t_out := NA_integer_] base <- expand_followup(p, 0L, horizon) # P(PVI) for each eligible month; months where a patient is not at risk of PVI have # probability 0 of deviating @@ -251,7 +277,7 @@ est_ccw <- function(rec, outcome = "t_male", variant = "V1_ignore", horizon = 60 base[is.na(ph), ph := 0] base[, `:=`(tp = fifelse(is.na(t_pvi), Inf, as.numeric(t_pvi)), el = pvi_elective %in% TRUE)] - out <- list() + arms <- list() # arm A: censored after month W-1 if no PVI by then (and still at risk of PVI then) a <- copy(base)[, arm := "A"] cens_A <- a[t == W - 1L & ph > 0 & tp > W - 1L, id] # deviated at month W-1 @@ -259,50 +285,61 @@ est_ccw <- function(rec, outcome = "t_male", variant = "V1_ignore", horizon = 60 pA <- base[t == W - 1L & ph > 0, .(id, pA = ph)] a <- pA[a, on = "id"] a[, w := ifelse(t > W - 1L & !is.na(pA) & tp == W - 1L, 1 / pA, 1)] - out$A <- a[, .(id, phys_id, arm, t, w, ev, dth)] + arms$A <- a[, .(id, phys_id, arm, t, w)] for (cmp in comparators) { b <- copy(base)[, arm := cmp] last <- if (cmp == "B1") W - 1L else horizon b <- b[!(el & tp <= last & t > tp)] # censored after month tp b[, q := ifelse(t <= last, 1 - ph, 1)] b[, w := 1 / shift(cumprod(q), fill = 1), by = id] - out[[cmp]] <- b[, .(id, phys_id, arm, t, w, ev, dth)] + arms[[cmp]] <- b[, .(id, phys_id, arm, t, w)] } - aj <- aj_cif(rbindlist(out), horizon) - rbindlist(lapply(comparators, function(cmp) cbind(contrast = paste0("A_", cmp), rd_from_aj(aj, "A", cmp)))) + clones <- rbindlist(arms) + ev_times <- rec$patients[, c("id", "t_death", unname(outcome)), with = FALSE] + rbindlist(lapply(seq_along(outcome), function(k) { + d <- ev_times[, .(id, t_death, t_out = get(outcome[k]))][clones, on = "id"] + d <- d[is.na(t_out) | t <= t_out] + aj <- aj_cif(mark_events(d), horizon) + rbindlist(lapply(comparators, function(cmp) + cbind(contrast = paste0("A_", cmp), rd_from_aj(aj, "A", cmp))))[ + , outcome := if (is.null(names(outcome))) outcome[k] else names(outcome)[k]] + })) } #' Sequential trials, ITT (D14): a trial at each month m = 0..W-1 among patients eligible #' for PVI at m; treatment = PVI at m; propensity score from covariates at m; outcome #' counted in months m+1..horizon-1; trial RDs pooled with weights = number eligible. -est_seq <- function(rec, outcome = "t_male", variant = "V1_ignore", horizon = 60L, rs = NULL) { +est_seq <- function(rec, outcome = "t_male", variant = "V1_ignore", horizon = 60L, rs = NULL, + phat = NULL) { W <- rec$par$size$window if (is.null(rs)) rs <- pvi_risk_set(rec) + if (!is.null(phat)) rs[, ps := phat] trials <- rs[t < W] - trials[, tt := t] # trial-month indicators in the PS model - ps <- fit_pvi(trials, trials, variant) - trials[, ps := ps] + # the trial-baseline propensity score is the window model of the PVI fit + if (is.null(phat)) trials[, ps := fit_pvi(trials, trials, variant, rec$extra_covs)] trials <- trials[!is.na(ps)] trials[, `:=`(m = t, arm = ifelse(pvi == 1L, "pvi", "no"), w = ifelse(pvi == 1L, 1 / ps, 1 / (1 - ps)))] - p <- rec$patients[, .(id, t_out = get(outcome))] - trials <- p[trials, on = "id"] - trials <- trials[is.na(t_out) | t_out > m] - res <- list(); infs <- list() - for (mm in 0:(W - 1)) { - tr <- trials[m == mm] - d <- expand_followup(tr[, .(id, phys_id, arm, w, t_out, t_death)], mm + 1L, horizon) - aj <- aj_cif(d, horizon) - x <- dcast(aj$inf, id + phys_id ~ arm, value.var = "inf", fill = 0) - res[[mm + 1L]] <- data.table(m = mm, n = nrow(tr), est = aj$F[["pvi"]] - aj$F[["no"]]) - infs[[mm + 1L]] <- data.table(id = x$id, phys_id = x$phys_id, m = mm, inf = x$pvi - x$no) - } - res <- rbindlist(res); infs <- rbindlist(infs) - res[, wt := n / sum(n)] - infs <- res[, .(m, wt)][infs, on = "m"] - pi <- infs[, .(inf = sum(wt * inf)), by = .(id, phys_id)] - data.table(est = sum(res$wt * res$est), se_patient = sqrt(sum(pi$inf^2)), - se_cluster = sqrt(sum(tapply(pi$inf, pi$phys_id, sum)^2)), risk1 = NA_real_, risk0 = NA_real_) + trials <- trials[, .(id, phys_id, m, arm, w, t_death)] + rbindlist(lapply(seq_along(outcome), function(k) { + tr_k <- rec$patients[, .(id, t_out = get(outcome[k]))][trials, on = "id"][is.na(t_out) | t_out > m] + res <- list(); infs <- list() + for (mm in 0:(W - 1)) { + tr <- tr_k[m == mm] + d <- expand_followup(tr[, .(id, phys_id, arm, w, t_out, t_death)], mm + 1L, horizon) + aj <- aj_cif(d, horizon) + x <- dcast(aj$inf, id + phys_id ~ arm, value.var = "inf", fill = 0) + res[[mm + 1L]] <- data.table(m = mm, n = nrow(tr), est = aj$F[["pvi"]] - aj$F[["no"]]) + infs[[mm + 1L]] <- data.table(id = x$id, phys_id = x$phys_id, m = mm, inf = x$pvi - x$no) + } + res <- rbindlist(res); infs <- rbindlist(infs) + res[, wt := n / sum(n)] + infs <- res[, .(m, wt)][infs, on = "m"] + pi <- infs[, .(inf = sum(wt * inf)), by = .(id, phys_id)] + data.table(est = sum(res$wt * res$est), se_patient = sqrt(sum(pi$inf^2)), + se_cluster = sqrt(sum(tapply(pi$inf, pi$phys_id, sum)^2)), risk1 = NA_real_, risk0 = NA_real_, + outcome = if (is.null(names(outcome))) outcome[k] else names(outcome)[k]) + })) } #' Negative-control exposure (D32, D36): the early low-value procedure (NCE, months diff --git a/simulations/config/experiments.yml b/simulations/config/experiments.yml index cd4b497..7a349b4 100644 --- a/simulations/config/experiments.yml +++ b/simulations/config/experiments.yml @@ -8,5 +8,5 @@ main: rct: [realistic, ideal] scales: smoke: {n_patients: 20000, reps: 1} - draft: {n_patients: 50000, reps: 100} - final: {n_patients: 50000, reps: 500} # to be revisited after the draft (sample size, D25/D29) + draft: {n_patients: 50000, reps: 100, dir: n50k} + final: {n_patients: 50000, reps: 200, dir: n50k} # extends the draft's replicates 1-100 to 200 (D51) diff --git a/simulations/run_experiment.R b/simulations/run_experiment.R index 4030dd7..abb4c8d 100644 --- a/simulations/run_experiment.R +++ b/simulations/run_experiment.R @@ -10,7 +10,7 @@ cores <- as.integer(opt("--cores", "10")) cfg <- yaml::read_yaml("simulations/config/experiments.yml") g <- cfg[[grid_name]]; sc <- cfg$scales[[scale]] worlds <- if (is.null(opt("--worlds", NULL))) g$worlds else strsplit(opt("--worlds", NULL), ",")[[1]] -outdir <- file.path("results", grid_name, scale) +outdir <- file.path("results", grid_name, if (is.null(sc$dir)) scale else sc$dir) jobs <- CJ(world = worlds, scenario = unlist(g$scenarios), rep = seq_len(sc$reps), sorted = FALSE) jobs[, file := file.path(outdir, world, scenario, sprintf("rep%03d.csv", rep))] todo <- jobs[!file.exists(file)] @@ -21,25 +21,17 @@ one_job <- function(i) { par <- load_params(j$world, j$scenario) rec <- simulate_records(par, rep = j$rep, n = sc$n_patients) out <- list() + with_v2 <- function(r) if (r$variant[1] == "V1_ignore") # same fit, two SEs + rbind(r, copy(r)[, `:=`(variant = "V2_cluster", se = se_cluster)]) else r + nce_out <- c(male = "t_male", disease = "t_disease") for (v in g$variants) { - for (d in g$designs) { - r <- run_design(rec, d, v) - if (v == "V1_ignore") { # same fit, two SEs - r2 <- copy(r)[, `:=`(variant = "V2_cluster", se = se_cluster)] - r <- rbind(r, r2) - } - out[[length(out) + 1]] <- r[, analysis := "main"] - } - if (isTRUE(g$nce)) for (d in c("landmark", "ccw")) { - r <- run_design(nce_records(rec), d, v, outcomes = c(male = "t_male", disease = "t_disease")) - if (v == "V1_ignore") r <- rbind(r, copy(r)[, `:=`(variant = "V2_cluster", se = se_cluster)]) - out[[length(out) + 1]] <- r[, analysis := "nce"] - } - } - for (d in c("landmark", "ccw")) { # unadjusted NCE (supplement, D36), V1/V2 only - r <- run_design(nce_records(rec, adjust_pvi = FALSE), d, "V1_ignore", outcomes = c(male = "t_male", disease = "t_disease")) - out[[length(out) + 1]] <- r[, analysis := "nce_unadjusted"] + out[[length(out) + 1]] <- with_v2(run_designs(rec, unlist(g$designs), v))[, analysis := "main"] + if (isTRUE(g$nce)) + out[[length(out) + 1]] <- with_v2(run_designs(nce_records(rec), c("landmark", "ccw"), v, nce_out))[, analysis := "nce"] } + # unadjusted NCE (supplement, D36), V1/V2 only + out[[length(out) + 1]] <- with_v2(run_designs(nce_records(rec, adjust_pvi = FALSE), c("landmark", "ccw"), + "V1_ignore", nce_out))[, analysis := "nce_unadjusted"] out[[length(out) + 1]] <- run_oracle(rec)[, analysis := "main"] # own estimand of landmark / naive for (dz in g$rct) { r <- run_rct(par, dz, rep = j$rep) diff --git a/simulations/truths/truths_rct.csv b/simulations/truths/truths_rct.csv new file mode 100644 index 0000000..209192f --- /dev/null +++ b/simulations/truths/truths_rct.csv @@ -0,0 +1,193 @@ +world,scenario,outcome,estimand,value,mcse,n +W0,null,male,rct_realistic_itt,0.135990258102635,0.000920184352771069,138782 +W0,null,disease,rct_realistic_itt,0,0,138782 +W0,null,nco1,rct_realistic_itt,0,0,138782 +W0,null,nco2,rct_realistic_itt,0,0,138782 +W0,null,male,rct_ideal_itt,0.132398000000003,0.000338976229994509,1000000 +W0,null,disease,rct_ideal_itt,0,0,1000000 +W0,null,nco1,rct_ideal_itt,0,0,1000000 +W0,null,nco2,rct_ideal_itt,0,0,1000000 +W0,harm,male,rct_realistic_itt,0.201618365494084,0.00108867376068166,138782 +W0,harm,disease,rct_realistic_itt,0.0529679641452063,0.00062217229612646,138782 +W0,harm,nco1,rct_realistic_itt,-0.00116729835281267,9.49963511299982e-05,138782 +W0,harm,nco2,rct_realistic_itt,-0.000187344180080983,4.20123301701807e-05,138782 +W0,harm,male,rct_ideal_itt,0.196825000000004,0.000401807268257721,1000000 +W0,harm,disease,rct_ideal_itt,0.0515179999999988,0.000228184021667706,1000000 +W0,harm,nco1,rct_ideal_itt,-0.000888999999999641,3.17523335710502e-05,1000000 +W0,harm,nco2,rct_ideal_itt,-0.000446999999999933,2.24232177395626e-05,1000000 +W0,benefit_harm,male,rct_realistic_itt,0.176492628727068,0.00109872534635429,138782 +W0,benefit_harm,disease,rct_realistic_itt,0.0389243561845205,0.000655419127377042,138782 +W0,benefit_harm,nco1,rct_realistic_itt,0.000677321266446925,0.000119259570456732,138782 +W0,benefit_harm,nco2,rct_realistic_itt,0.000244988543182881,5.48720558616628e-05,138782 +W0,benefit_harm,male,rct_ideal_itt,0.173512000000003,0.000406167146413866,1000000 +W0,benefit_harm,disease,rct_ideal_itt,0.0386590000000027,0.000241330768776287,1000000 +W0,benefit_harm,nco1,rct_ideal_itt,0.000763999999999833,4.10781936238178e-05,1000000 +W0,benefit_harm,nco2,rct_ideal_itt,0.000396000000000213,2.91177614495428e-05,1000000 +W1,null,male,rct_realistic_itt,0.0659595624792839,0.000666357827592477,138782 +W1,null,disease,rct_realistic_itt,0,0,138782 +W1,null,nco1,rct_realistic_itt,0,0,138782 +W1,null,nco2,rct_realistic_itt,0,0,138782 +W1,null,male,rct_ideal_itt,0.128842000000002,0.000335081857633484,1000000 +W1,null,disease,rct_ideal_itt,0,0,1000000 +W1,null,nco1,rct_ideal_itt,0,0,1000000 +W1,null,nco2,rct_ideal_itt,0,0,1000000 +W1,harm,male,rct_realistic_itt,0.0928002190485794,0.000795614703095957,138782 +W1,harm,disease,rct_realistic_itt,0.020910492715194,0.000413885769615974,138782 +W1,harm,nco1,rct_realistic_itt,-0.000439538268651489,6.64216071074703e-05,138782 +W1,harm,nco2,rct_realistic_itt,-2.8822181550956e-05,2.88221815509174e-05,138782 +W1,harm,male,rct_ideal_itt,0.204204999999998,0.000407803242113363,1000000 +W1,harm,disease,rct_ideal_itt,0.0726610000000019,0.000266656052216873,1000000 +W1,harm,nco1,rct_ideal_itt,-0.00116899999999966,3.61888760346696e-05,1000000 +W1,harm,nco2,rct_ideal_itt,-0.000669999999999987,2.67123906369683e-05,1000000 +W1,benefit_harm,male,rct_realistic_itt,0.0429234338747105,0.000826265889068951,138782 +W1,benefit_harm,disease,rct_realistic_itt,-0.0139859635975853,0.000473809643164687,138782 +W1,benefit_harm,nco1,rct_realistic_itt,0.00198152498162617,0.000124064597708836,138782 +W1,benefit_harm,nco2,rct_realistic_itt,0.000403510541712834,5.48653056966601e-05,138782 +W1,benefit_harm,male,rct_ideal_itt,0.194897999999999,0.000430045293588994,1000000 +W1,benefit_harm,disease,rct_ideal_itt,0.0869099999999998,0.000323927085666702,1000000 +W1,benefit_harm,nco1,rct_ideal_itt,0.000186000000000347,4.90098745761233e-05,1000000 +W1,benefit_harm,nco2,rct_ideal_itt,-7.20000000001851e-05,3.59443473717217e-05,1000000 +W1_rho0,null,male,rct_realistic_itt,0.0719694829047751,0.000793152060137895,106170 +W1_rho0,null,disease,rct_realistic_itt,0,0,106170 +W1_rho0,null,nco1,rct_realistic_itt,0,0,106170 +W1_rho0,null,nco2,rct_realistic_itt,0,0,106170 +W1_rho0,null,male,rct_ideal_itt,0.137793999999995,0.000344730231347967,1000000 +W1_rho0,null,disease,rct_ideal_itt,0,0,1000000 +W1_rho0,null,nco1,rct_ideal_itt,0,0,1000000 +W1_rho0,null,nco2,rct_ideal_itt,0,0,1000000 +W1_rho0,harm,male,rct_realistic_itt,0.100273146839973,0.000938894453025786,106170 +W1_rho0,harm,disease,rct_realistic_itt,0.0226052557219548,0.000485941115250653,106170 +W1_rho0,harm,nco1,rct_realistic_itt,-0.000367335405481731,6.98433406966748e-05,106170 +W1_rho0,harm,nco2,rct_realistic_itt,-6.59319958556776e-05,3.3959727351775e-05,106170 +W1_rho0,harm,male,rct_ideal_itt,0.212454,0.000413610286332383,1000000 +W1_rho0,harm,disease,rct_ideal_itt,0.0728310000000015,0.000266920806020269,1000000 +W1_rho0,harm,nco1,rct_ideal_itt,-0.00112500000000023,3.552091829803e-05,1000000 +W1_rho0,harm,nco2,rct_ideal_itt,-0.000546000000000055,2.43660107054316e-05,1000000 +W1_rho0,benefit_harm,male,rct_realistic_itt,0.0514834699067521,0.000958073606684312,106170 +W1_rho0,benefit_harm,disease,rct_realistic_itt,-0.0111801827258177,0.000529785263869061,106170 +W1_rho0,benefit_harm,nco1,rct_realistic_itt,0.00194970330601875,0.000144878621313218,106170 +W1_rho0,benefit_harm,nco2,rct_realistic_itt,0.000339078835829366,5.8052678200413e-05,106170 +W1_rho0,benefit_harm,male,rct_ideal_itt,0.202966999999999,0.000434913308670816,1000000 +W1_rho0,benefit_harm,disease,rct_ideal_itt,0.0881539999999982,0.000324972272494712,1000000 +W1_rho0,benefit_harm,nco1,rct_ideal_itt,0.000179999999999788,4.91728585498839e-05,1000000 +W1_rho0,benefit_harm,nco2,rct_ideal_itt,0.000117000000000075,3.49998219424148e-05,1000000 +W2,null,male,rct_realistic_itt,0.145191739562767,0.000945671505326518,138782 +W2,null,disease,rct_realistic_itt,0,0,138782 +W2,null,nco1,rct_realistic_itt,0,0,138782 +W2,null,nco2,rct_realistic_itt,0,0,138782 +W2,null,male,rct_ideal_itt,0.138372999999999,0.000345366518573647,1000000 +W2,null,disease,rct_ideal_itt,0,0,1000000 +W2,null,nco1,rct_ideal_itt,0,0,1000000 +W2,null,nco2,rct_ideal_itt,0,0,1000000 +W2,harm,male,rct_realistic_itt,0.212095228487845,0.00110876809241165,138782 +W2,harm,disease,rct_realistic_itt,0.0539046850456113,0.000627329268014748,138782 +W2,harm,nco1,rct_realistic_itt,-0.00117450389819992,9.47220401098828e-05,138782 +W2,harm,nco2,rct_realistic_itt,-0.000201755270856445,4.32300358424153e-05,138782 +W2,harm,male,rct_ideal_itt,0.202624999999996,0.000406091460490844,1000000 +W2,harm,disease,rct_ideal_itt,0.0515849999999986,0.00022831127852228,1000000 +W2,harm,nco1,rct_ideal_itt,-0.000893999999999869,3.18622312336383e-05,1000000 +W2,harm,nco2,rct_ideal_itt,-0.000429999999999814,2.21317778275488e-05,1000000 +W2,benefit_harm,male,rct_realistic_itt,0.186097620728912,0.00111829577643359,138782 +W2,benefit_harm,disease,rct_realistic_itt,0.0393855110893337,0.000659721855336125,138782 +W2,benefit_harm,nco1,rct_realistic_itt,0.000677321266446935,0.000118823417846105,138782 +W2,benefit_harm,nco2,rct_realistic_itt,0.000244988543182881,5.48720558616628e-05,138782 +W2,benefit_harm,male,rct_ideal_itt,0.179103000000002,0.000410338011607155,1000000 +W2,benefit_harm,disease,rct_ideal_itt,0.0387480000000017,0.000241562933514644,1000000 +W2,benefit_harm,nco1,rct_ideal_itt,0.000754999999999761,4.11148594232723e-05,1000000 +W2,benefit_harm,nco2,rct_ideal_itt,0.000370000000000232,2.87378483163834e-05,1000000 +W3,null,male,rct_realistic_itt,0.0424622789698956,0.000541270787927301,138782 +W3,null,disease,rct_realistic_itt,0,0,138782 +W3,null,nco1,rct_realistic_itt,0,0,138782 +W3,null,nco2,rct_realistic_itt,0,0,138782 +W3,null,male,rct_ideal_itt,0.0722659999999937,0.000259020640751461,1000000 +W3,null,disease,rct_ideal_itt,0,0,1000000 +W3,null,nco1,rct_ideal_itt,0,0,1000000 +W3,null,nco2,rct_ideal_itt,0,0,1000000 +W3,harm,male,rct_realistic_itt,0.107535559366489,0.000848641937483286,138782 +W3,harm,disease,rct_realistic_itt,0.0528022366012888,0.000620728301010128,138782 +W3,harm,nco1,rct_realistic_itt,-0.00113127062587396,9.41761257651062e-05,138782 +W3,harm,nco2,rct_realistic_itt,-0.000201755270856445,4.32300358424153e-05,138782 +W3,harm,male,rct_ideal_itt,0.135530000000003,0.000347591340399331,1000000 +W3,harm,disease,rct_ideal_itt,0.0503310000000001,0.000225725145677111,1000000 +W3,harm,nco1,rct_ideal_itt,-0.00089600000000022,3.18307743729401e-05,1000000 +W3,harm,nco2,rct_ideal_itt,-0.000428000000000328,2.21318165954998e-05,1000000 +W3,benefit_harm,male,rct_realistic_itt,0.0867259442867219,0.000871670642302478,138782 +W3,benefit_harm,disease,rct_realistic_itt,0.0386505454597851,0.000654029292656351,138782 +W3,benefit_harm,nco1,rct_realistic_itt,0.000706143447997551,0.000118384444891793,138782 +W3,benefit_harm,nco2,rct_realistic_itt,0.000259399633958298,5.39170624352957e-05,138782 +W3,benefit_harm,male,rct_ideal_itt,0.115277000000002,0.000354632681844953,1000000 +W3,benefit_harm,disease,rct_ideal_itt,0.0377310000000017,0.000238624031857676,1000000 +W3,benefit_harm,nco1,rct_ideal_itt,0.000750999999999899,4.09687402474652e-05,1000000 +W3,benefit_harm,nco2,rct_ideal_itt,0.000366000000000275,2.86682204863218e-05,1000000 +W4,null,male,rct_realistic_itt,0.129591733798331,0.000901597893546357,138782 +W4,null,disease,rct_realistic_itt,0,0,138782 +W4,null,nco1,rct_realistic_itt,0,0,138782 +W4,null,nco2,rct_realistic_itt,0,0,138782 +W4,null,male,rct_ideal_itt,0.121134999999996,0.000326342486164428,1000000 +W4,null,disease,rct_ideal_itt,0,0,1000000 +W4,null,nco1,rct_ideal_itt,0,0,1000000 +W4,null,nco2,rct_ideal_itt,0,0,1000000 +W4,harm,male,rct_realistic_itt,0.193620210113702,0.00107298267542429,138782 +W4,harm,disease,rct_realistic_itt,0.0515989105215381,0.000614948138369303,138782 +W4,harm,nco1,rct_realistic_itt,-0.00113847617126122,9.44507547707977e-05,138782 +W4,harm,nco2,rct_realistic_itt,-0.000180138634693252,4.01160091583548e-05,138782 +W4,harm,male,rct_ideal_itt,0.182677999999995,0.000391084263636159,1000000 +W4,harm,disease,rct_ideal_itt,0.0490339999999983,0.000223283937399999,1000000 +W4,harm,nco1,rct_ideal_itt,-0.000853000000000196,3.13731314224849e-05,1000000 +W4,harm,nco2,rct_ideal_itt,-0.00043899999999993,2.21992741281008e-05,1000000 +W4,benefit_harm,male,rct_realistic_itt,0.171881079678921,0.00108897017441715,138782 +W4,benefit_harm,disease,rct_realistic_itt,0.0400412157196173,0.000660342200256804,138782 +W4,benefit_harm,nco1,rct_realistic_itt,0.000626882448732363,0.000121204791463402,138782 +W4,benefit_harm,nco2,rct_realistic_itt,0.000223371907019628,5.43975661974938e-05,138782 +W4,benefit_harm,male,rct_ideal_itt,0.165849999999995,0.000400004921850573,1000000 +W4,benefit_harm,disease,rct_ideal_itt,0.0405780000000026,0.000244469805256133,1000000 +W4,benefit_harm,nco1,rct_ideal_itt,0.000691999999999629,4.16836043727314e-05,1000000 +W4,benefit_harm,nco2,rct_ideal_itt,0.000335000000000185,2.97470781742732e-05,1000000 +W5,null,male,rct_realistic_itt,0.135990258102635,0.000920184352771069,138782 +W5,null,disease,rct_realistic_itt,0,0,138782 +W5,null,nco1,rct_realistic_itt,0,0,138782 +W5,null,nco2,rct_realistic_itt,0,0,138782 +W5,null,male,rct_ideal_itt,0.132398000000003,0.000338976229994509,1000000 +W5,null,disease,rct_ideal_itt,0,0,1000000 +W5,null,nco1,rct_ideal_itt,0,0,1000000 +W5,null,nco2,rct_ideal_itt,0,0,1000000 +W5,harm,male,rct_realistic_itt,0.201618365494084,0.00108867376068166,138782 +W5,harm,disease,rct_realistic_itt,0.0529679641452063,0.00062217229612646,138782 +W5,harm,nco1,rct_realistic_itt,-0.00116729835281267,9.49963511299982e-05,138782 +W5,harm,nco2,rct_realistic_itt,-0.000187344180080983,4.20123301701807e-05,138782 +W5,harm,male,rct_ideal_itt,0.196825000000004,0.000401807268257721,1000000 +W5,harm,disease,rct_ideal_itt,0.0515179999999988,0.000228184021667706,1000000 +W5,harm,nco1,rct_ideal_itt,-0.000888999999999641,3.17523335710502e-05,1000000 +W5,harm,nco2,rct_ideal_itt,-0.000446999999999933,2.24232177395626e-05,1000000 +W5,benefit_harm,male,rct_realistic_itt,0.176492628727068,0.00109872534635429,138782 +W5,benefit_harm,disease,rct_realistic_itt,0.0389243561845205,0.000655419127377042,138782 +W5,benefit_harm,nco1,rct_realistic_itt,0.000677321266446925,0.000119259570456732,138782 +W5,benefit_harm,nco2,rct_realistic_itt,0.000244988543182881,5.48720558616628e-05,138782 +W5,benefit_harm,male,rct_ideal_itt,0.173512000000003,0.000406167146413866,1000000 +W5,benefit_harm,disease,rct_ideal_itt,0.0386590000000027,0.000241330768776287,1000000 +W5,benefit_harm,nco1,rct_ideal_itt,0.000763999999999833,4.10781936238178e-05,1000000 +W5,benefit_harm,nco2,rct_ideal_itt,0.000396000000000213,2.91177614495428e-05,1000000 +WR,null,male,rct_realistic_itt,0.0154198671297432,0.000330750754524574,138782 +WR,null,disease,rct_realistic_itt,0,0,138782 +WR,null,nco1,rct_realistic_itt,0,0,138782 +WR,null,nco2,rct_realistic_itt,0,0,138782 +WR,null,male,rct_ideal_itt,0.060499000000004,0.00023850980668444,1000000 +WR,null,disease,rct_ideal_itt,0,0,1000000 +WR,null,nco1,rct_ideal_itt,0,0,1000000 +WR,null,nco2,rct_ideal_itt,0,0,1000000 +WR,harm,male,rct_realistic_itt,0.0416696689772448,0.000561018599156739,138782 +WR,harm,disease,rct_realistic_itt,0.0209753426236831,0.000413673901769527,138782 +WR,harm,nco1,rct_realistic_itt,-0.000403510541712805,6.6031269023426e-05,138782 +WR,harm,nco2,rct_realistic_itt,-2.8822181550956e-05,2.88221815509174e-05,138782 +WR,harm,male,rct_ideal_itt,0.138377000000002,0.000351378612521928,1000000 +WR,harm,disease,rct_ideal_itt,0.0701189999999995,0.000262565029619595,1000000 +WR,harm,nco1,rct_ideal_itt,-0.0011509999999999,3.56886042409898e-05,1000000 +WR,harm,nco2,rct_ideal_itt,-0.000625999999999994,2.60309201067641e-05,1000000 +WR,benefit_harm,male,rct_realistic_itt,-0.00457552132120956,0.00061817312375107,138782 +WR,benefit_harm,disease,rct_realistic_itt,-0.0141733077776656,0.000473988656020485,138782 +WR,benefit_harm,nco1,rct_realistic_itt,0.00199593607240166,0.000124480729030194,138782 +WR,benefit_harm,nco2,rct_realistic_itt,0.000403510541712834,5.48653056966601e-05,138782 +WR,benefit_harm,male,rct_ideal_itt,0.137433000000005,0.000386245154916532,1000000 +WR,benefit_harm,disease,rct_ideal_itt,0.0842650000000005,0.000320113280338603,1000000 +WR,benefit_harm,nco1,rct_ideal_itt,0.000204000000000121,4.87438279166583e-05,1000000 +WR,benefit_harm,nco2,rct_ideal_itt,-6.99999999999889e-05,3.54400388824101e-05,1000000 diff --git a/simulations/validate_designs.R b/simulations/validate_designs.R index 0dbd6dc..9b72e50 100644 --- a/simulations/validate_designs.R +++ b/simulations/validate_designs.R @@ -15,7 +15,7 @@ par <- load_params(world, scenario) res <- rbindlist(parallel::mclapply(seq_len(reps), function(r) { rec <- simulate_records(par, rep = 1000L + r, n = n) rbindlist(lapply(c("naive", "landmark", "ccw", "seq"), function(d) - cbind(rep = r, run_design(rec, d, "V1_ignore", outcomes = c(male = "t_male", disease = "t_disease", nco1 = "t_nco1")))), + cbind(rep = r, run_designs(rec, d, "V1_ignore", outcomes = c(male = "t_male", disease = "t_disease", nco1 = "t_nco1")))), fill = TRUE) }, mc.cores = cores), fill = TRUE)