The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Primary Analysis Workflow

Lei Shi, Matthew Secrest

2026-08-20

Primary analysis

This vignette demonstrates the primary analysis workflow using the EC-IPW and EC-AIPW weighting estimators proposed in Zhou et al. (2024) for incorporating external controls in randomized trials with longitudinal outcomes.

1 Load data

head(SyntheticData)
##   x1 x2 x3 x4       x5 A S T_cross         y1         y2         y3        y4
## 1  1  1  1  9 54.59836 1 1       2  3.4512377 -0.7642287 -2.4713591  3.935466
## 2  0  1  0  8 33.08006 1 1       2  0.4518106  6.3516296  4.5231869 -0.198674
## 3  1  1  1  7 48.51653 0 1       2  3.0532714 -2.0453190  5.9064870 -1.374919
## 4  1  1  1 15 31.68766 1 1       2 -9.1183948  0.2304339  4.7858172  8.490757
## 5  1  1  1 12 29.98495 0 1       2 -1.4270057  1.5878794  3.7006101  9.449632
## 6  1  1  0  7 46.08991 0 1       2 -2.6967072 -0.6130288  0.7482786 -2.413717

2 EC-IPW

2.1 No borrowing (weight = 0)

method <- ec_ipw(
  ps_formula = "S ~ x1 + x2 + x3 + x4 + x5",
  weight = 0
)

analysis <- setup_analysis_primary(
  data = SyntheticData,
  trial_status_col_name = "S",
  treatment_col_name = "A",
  outcome_col_name = c("y1", "y2"),
  covariates_col_name = c("x1", "x2", "x3", "x4", "x5"),
  method_weighting_obj = method
)

run_analysis(analysis)
## $results
##      point_estimates standard_deviation lower_CI_normal upper_CI_normal
## tau1     -0.02808704          0.5367987      -1.0801931        1.024019
## tau2      0.40959558          0.5625763      -0.6930338        1.512225
## 
## $borrow_weight
## [1] 0

2.2 Optimal weight (data-adaptive)

method <- ec_ipw(ps_formula = "S ~ x1 + x2 + x3 + x4 + x5")

analysis <- setup_analysis_primary(
  data = SyntheticData,
  trial_status_col_name = "S",
  treatment_col_name = "A",
  outcome_col_name = c("y1", "y2"),
  covariates_col_name = c("x1", "x2", "x3", "x4", "x5"),
  method_weighting_obj = method
)

run_analysis(analysis)
## $results
##      point_estimates standard_deviation lower_CI_normal upper_CI_normal
## tau1      -0.1971969          0.5134018       -1.203446        0.809052
## tau2       0.4697209          0.5410007       -0.590621        1.530063
## 
## $borrow_weight
## [1] 0.1475196

2.3 Bootstrap inference

method <- ec_ipw(
  ps_formula = "S ~ x1 + x2 + x3 + x4 + x5",
  bootstrap = 50,
  bootstrap_ci_type = "perc"
)

analysis <- setup_analysis_primary(
  data = SyntheticData,
  trial_status_col_name = "S",
  treatment_col_name = "A",
  outcome_col_name = c("y1", "y2"),
  covariates_col_name = c("x1", "x2", "x3", "x4", "x5"),
  method_weighting_obj = method
)

run_analysis(analysis)
## $results
##      point_estimates standard_deviation lower_CI_boot upper_CI_boot
## tau1      -0.1971969          0.5989789    -1.4378865      1.296664
## tau2       0.4697209          0.5701665    -0.5582876      1.597238
## 
## $borrow_weight
## [1] 0.1475196

3 EC-AIPW

EC-AIPW augments the IPW estimator with an outcome regression model, making it doubly robust: consistent if either the propensity score model or the outcome model is correctly specified.

3.1 No borrowing (weight = 0)

method <- ec_aipw(
  ps_formula = "S ~ x1 + x2 + x3 + x4 + x5",
  outcome_formula = c(
    "y1 ~ x1 + x2 + x3 + x4 + x5",
    "y2 ~ x1 + x2 + x3 + x4 + x5"
  ),
  weight = 0
)

analysis <- setup_analysis_primary(
  data = SyntheticData,
  trial_status_col_name = "S",
  treatment_col_name = "A",
  outcome_col_name = c("y1", "y2"),
  covariates_col_name = c("x1", "x2", "x3", "x4", "x5"),
  method_weighting_obj = method
)

run_analysis(analysis)
## $results
##      point_estimates standard_deviation lower_CI_normal upper_CI_normal
## tau1      -0.4361151          0.5552065      -1.5242998       0.6520696
## tau2       0.4422248          0.5701633      -0.6752748       1.5597244
## 
## $borrow_weight
## [1] 0

3.2 Optimal weight (data-adaptive)

method <- ec_aipw(
  ps_formula = "S ~ x1 + x2 + x3 + x4 + x5",
  outcome_formula = c(
    "y1 ~ x1 + x2 + x3 + x4 + x5",
    "y2 ~ x1 + x2 + x3 + x4 + x5"
  )
)

analysis <- setup_analysis_primary(
  data = SyntheticData,
  trial_status_col_name = "S",
  treatment_col_name = "A",
  outcome_col_name = c("y1", "y2"),
  covariates_col_name = c("x1", "x2", "x3", "x4", "x5"),
  method_weighting_obj = method
)

run_analysis(analysis)
## $results
##      point_estimates standard_deviation lower_CI_normal upper_CI_normal
## tau1      -0.5463256          0.5305614       -1.586207       0.4935556
## tau2       0.5401750          0.5543275       -0.546287       1.6266369
## 
## $borrow_weight
## [1] 0.1475196

3.3 Bootstrap inference

method <- ec_aipw(
  ps_formula = "S ~ x1 + x2 + x3 + x4 + x5",
  outcome_formula = c(
    "y1 ~ x1 + x2 + x3 + x4 + x5",
    "y2 ~ x1 + x2 + x3 + x4 + x5"
  ),
  bootstrap = 50,
  bootstrap_ci_type = "perc"
)

analysis <- setup_analysis_primary(
  data = SyntheticData,
  trial_status_col_name = "S",
  treatment_col_name = "A",
  outcome_col_name = c("y1", "y2"),
  covariates_col_name = c("x1", "x2", "x3", "x4", "x5"),
  method_weighting_obj = method
)

run_analysis(analysis)
## $results
##      point_estimates standard_deviation lower_CI_boot upper_CI_boot
## tau1      -0.5463256          0.6225099    -1.9966744      1.078554
## tau2       0.5401750          0.5402187    -0.4664991      1.614346
## 
## $borrow_weight
## [1] 0.1475196

4 Notes

  1. When there are missing values in the data, preprocess the dataset (deletion, imputation, etc.) to obtain a complete dataset before applying the package.

References

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.