ssMRCT calculates consistency probabilities (CP), overall sample sizes, and regional recruitment fractions for multi-regional clinical trials (MRCTs). It supports fixed-effects and random-effects designs, two independent trials, and covariate-adjusted regional treatment-effect estimation.
CP is a probability of regional consistency conditional on overall trial significance. It is different from overall power and confidence-interval coverage. For two trials, the conditioning event is that both trials are significant.
# install.packages("pak")
pak::pak("kunhaiq/ssMRCT")| Task | Functions |
|---|---|
| Fixed-effects Method I: preserve a fraction of the overall effect | conProb(),
conProb2() |
| Find a regional fraction for a target Method I CP | regFrac(),
regFrac2() |
| Fixed-effects Method II: all regional effects are nonnegative | conProbII(),
conProbII2() |
| Random-effects sample size and Method I CP | ssCPnorm(),
ssCPbinary(), ssCPsurvPH(),
ssCPsurvNPH() |
| Random-effects CP lower bound | CPlbd() |
| Covariate-adjusted target-region ATE | regATE_dr() |
The suffix 2 denotes two independent trials.
regFrac2() requires a symmetric trial design; it does not
optimize two different regional fractions. Random-effects CP uses a
shrinkage regional estimator, so it has a different
interpretation from fixed-effects CP based on the raw regional effect
estimate.
Assume a one-sided significance level of 0.05, power of 0.80,
treatment effect of 1, standard deviation of 4 in both arms, and equal
randomization. Method I requires the regional estimate to preserve at
least pi = 0.5 of the overall estimate.
library(ssMRCT)
conProb(alpha = 0.05, power = 0.8, pi = 0.5,
rF = 0.271, d = 1, sigmaTrt = 4)
#> $CP
#> [1] 0.8000581
#>
#> $N
#> [1] 396
# Find the regional fraction needed for CP = 0.80.
design <- regFrac(alpha = 0.05, power = 0.8, pi = 0.5, CP = 0.8,
d = 1, sigmaTrt = 4)
design
#> $rF
#> [1] 0.2708974
#>
#> $N
#> [1] 396N is the recommended overall sample size;
rF is a continuous regional fraction. A recruitment plan
must allocate whole participants to each regional arm. Multiplying
N by rF alone does not establish CP for that
integer allocation.
The CP calculation allows different trial powers and regional fractions. Here study 2 has higher power; unspecified effect and variance parameters are inherited from study 1.
conProb2(alpha = 0.05, power1 = 0.8, power2 = 0.9,
rF1 = 0.15, rF2 = 0.20, d1 = 1, sigmaTrt1 = 4)
#> $CP
#> [1] 0.8309535
#>
#> $N1
#> [1] 396
#>
#> $N2
#> [1] 550For two symmetric trials, find a common fraction and verify its CP:
fraction <- regFrac2(alpha = 0.05, power = 0.8, pi = 0.5, CP = 0.8)
fraction
#> [1] 0.1530893
conProb2(alpha = 0.05, power1 = 0.8, pi = 0.5,
rF1 = fraction, d1 = 1, sigmaTrt1 = 4)
#> $CP
#> [1] 0.8
#>
#> $N1
#> [1] 396
#>
#> $N2
#> [1] 396Both trials must share the effect, arm-specific variances,
randomization ratio, power and regional fraction for this inverse
calculation. For unequal randomization ratios in conProb2()
or continuous conProbII2(), specify the control means
(muCtrl1, muCtrl2) because separate arm
pooling can make them relevant to the pooled effect.
Method II requires every regional treatment-minus-control estimate to be nonnegative. This example uses three regions, response probabilities of 0.70 and 0.55, and 2:1 treatment-to-control randomization.
set.seed(42)
binary <- conProbII(alpha = 0.025, power = 0.8, rF = c(0.2, 0.4, 0.4),
pTrt = 0.70, pCtrl = 0.55, randRatio = 2,
responseType = "binary", B = 50000)
binary[c("CP", "N", "nTrtReg", "nCtrlReg", "achievedPower", "MCSE")]
#> $CP
#> [1] 0.9151825
#>
#> $N
#> [1] 373
#>
#> $nTrtReg
#> [1] 50 99 99
#>
#> $nCtrlReg
#> [1] 25 50 50
#>
#> $achievedPower
#> [1] 0.80856
#>
#> $MCSE
#> [1] 0.001385656The simulation uses the returned integer regional arm counts. CP is
the proportion of significant trials that also meet regional
consistency; zero regional effects count as consistent.
achievedPower is the simulated probability of overall
significance, and MCSE describes simulation uncertainty in
CP. For conProbII2(), achievedPower instead
refers to both trials succeeding.
For a normal endpoint, supply the mean regional effect
delta, between-region standard deviation tau,
outcome standard deviations, and regional fractions.
ssCPnorm(alpha = 0.025, beta = 0.2, delta = 0.25, tau = 0.1,
sigma1r = 1, sigma0r = 1, randRatio = 1,
pi = 0.5, target = 1, f = c(0.2, 0.3, 0.5))
#> $n0
#> [1] 459
#>
#> $n1
#> [1] 459
#>
#> $n
#> [1] 918
#>
#> $CP
#> [1] 0.9934161n0, n1 and n are
overall control, treatment and total counts.
CP refers to the region indexed by target. The
function sizes the trial for specified overall power and then evaluates
regional CP; it does not solve for a user-specified CP target. A finite
sample-size solution requires
tau * (qnorm(1 - alpha) + qnorm(1 - beta)) / delta < sqrt(length(f)).
ssCPbinary() uses regional response probabilities and a
normal approximation. ssCPsurvPH() uses exponential
survival with fixed follow-up; ssCPsurvNPH() uses RMST
differences with piecewise exponential or Weibull survival and uniform
censoring. These functions derive delta and
tau from the unweighted mean and sample standard deviation
of the supplied regional effects.
CPlbd() returns a CP lower bound and
regional counts at its equality condition, not an
overall allocation. Its fr argument specifies output
length; it does not divide the counts by regional fractions. Counts are
NA when the finite equality condition does not apply.
alpha is one-sided. Fixed-effects functions take
power; random-effects functions take
beta = 1 - power.randRatio is treatment/control. sigma
parameters are standard deviations, not variances. Higher effects
indicate benefit; PH effects are -log(hr).pi for the fraction of the overall effect
to preserve. In regATE_dr(), pi instead
denotes target-region membership probability.regATE_dr() estimates the treatment-minus-control
average treatment effect (ATE) in a target region,
using participant-level covariates and information from other regions.
It returns an effect estimate, an influence-function standard error and
a 95% confidence interval. This is an analysis function, not a
sample-size or CP calculation.
The input has one row per participant:
| Column | Meaning |
|---|---|
y |
Numeric outcome |
trt |
Treatment assignment: 1 = treatment, 0 = control |
region |
Region label; target_region
selects one of these labels |
| Other numeric columns | Baseline covariates used in the models |
Supply complete data with both treatment arms in each region. Include only intended covariates: a numeric participant ID, for example, would otherwise be treated as a covariate. The current interface uses numeric covariates; categorical covariates need suitable numeric indicator columns.
The following example extends the one in ?regATE_dr.
There are three regions with 100 participants each, equal treatment
allocation within each region, one baseline covariate x,
and a true treatment effect of 1.
set.seed(42)
dat <- data.frame(
region = rep(1:3, each = 100),
trt = unlist(lapply(1:3, function(i) sample(rep(c(0, 1), each = 50)))),
x = rnorm(300)
)
dat$y <- dat$x + dat$trt + rnorm(300)Use region 1 as the target and regions 2 and 3 as candidate sources:
fit <- regATE_dr(dat, target_region = 1, p1 = 0.5, p0 = 0.5)
data.frame(
estimate = fit$estimate,
SE = fit$se_eif,
lower95 = fit$ci[1],
upper95 = fit$ci[2]
)
#> estimate SE lower95 upper95
#> 1 1.24205 0.1096899 1.027062 1.457038p1 and p0 are both
treatment-assignment probabilities: p1 applies to
the target population and p0 to the source population. They
are not the treatment and control response probabilities. For a trial
randomized 1:1, supplying both as 0.5 uses the known assignment
probabilities.
Other commonly used options are:
pi = NULL (default): fit a logistic model for
target-region membership given covariates. Here pi is a
selection probability, not the Method I effect-preservation fraction.
p1 and p0 can also be estimated by setting
them to NULL. Supplied probabilities can be scalars or
vectors aligned with all rows of dat.v1 = "const", v0 = "const" (defaults): estimate
marginal target-to-source outcome variance ratios separately in the
treatment and control arms. Use v1 = 1, v0 = 1 to specify
equal variances, or "log_linear" to model the ratios using
covariates.compute_se = FALSE: return the point estimate without
its standard error and confidence interval.With region_wise = TRUE, each source is compared with
the target separately in the treatment and control arms. ANCOVA compares
a common covariate model with a model allowing a region difference and
region-by-covariate interactions. A source is excluded if either p-value
is below check_p_threshold (default 0.05), and the
estimator is refitted using the retained sources.
To illustrate, give region 3 a larger treatment effect while keeping the target-region effect unchanged:
dat_heterogeneous <- dat
dat_heterogeneous$y <- dat$y + 1.5 * (dat$region == 3) * dat$trt
screened <- regATE_dr(
dat_heterogeneous, target_region = 1,
p1 = 0.5, p0 = 0.5, region_wise = TRUE,
config = list(check_p_threshold = 0.05)
)
screened$check_results
#> source_region p_value_trt p_value_ctrl passed
#> 1 2 4.420211e-01 0.3072005 TRUE
#> 2 3 2.115335e-10 0.1645980 FALSE
screened$region_wise_remaining_regions
#> [1] 2
data.frame(
analysis = c("All candidate sources", "After source screening"),
estimate = c(screened$estimate, screened$region_wise_estimate),
SE = c(screened$se_eif, screened$region_wise_se),
lower95 = c(screened$ci[1], screened$region_wise_ci[1]),
upper95 = c(screened$ci[2], screened$region_wise_ci[2])
)
#> analysis estimate SE lower95 upper95
#> 1 All candidate sources 1.778874 0.1268094 1.5303323 2.027416
#> 2 After source screening 1.149283 0.1381254 0.8785626 1.420004estimate, se_eif and ci always
describe the fit using all candidate sources. The corresponding
region_wise_* entries describe the fit after screening.
remaining_regions lists the original candidate sources;
region_wise_remaining_regions lists the retained sources,
excluding the target itself. If no sources remain, the refit uses
target-region data only. Selection probabilities are re-estimated when
sources are removed.
Borrowing assumes conditional outcome-mean exchangeability across retained regions: after accounting for covariates, the outcome mean under each treatment is shared across those regions. Double robustness concerns correct specification of either the outcome models or both the selection and treatment-assignment models, under this assumption. It does not guarantee unbiased borrowing from incompatible sources, and a nonsignificant screening test does not establish exchangeability.
The reported intervals use the estimated influence function.
Intervals after screening do not include uncertainty
from selecting the source regions. See ?regATE_dr for the
estimator formula and complete argument descriptions.
Use help(package = "ssMRCT") for the function index and
?conProb (or another function name) for arguments,
formulas, return values and examples.
Qing, Kunhai, Xinru Ren, Shuping Jiang, Ping Yang, Menggang Yu, and Jin Xu. 2025. “Regional Consistency Evaluation and Sample Size Calculation under Two MRCTs.” Statistics in Medicine 44 (25–27): e70306. https://doi.org/10.1002/sim.70306.
Ren, Xinru, and Jin Xu. 2026. “Consistency Assessment and Regional Sample Size Calculation for MRCT under Random Effects Model.” Pharmaceutical Statistics 25 (3): e70090. https://doi.org/10.1002/pst.70090.
See NEWS.md for changes that affect calculations and returned values.
MIT license. See LICENSE.md for the full text.
Run the grouped tests during development:
devtools::test()The testthat suite covers regional fraction inversion,
pooled-trial and regional-order invariance, random-effects sample sizes,
PH event requirements, censored RMST moments, and regional ATE
estimation and source screening. The existing
tests/regression.R also checks published numerical
benchmarks, exact binomial probabilities and independent
simulations.
Run both suites, together with examples and package checks, before release:
devtools::check()GitHub Actions runs both suites automatically through
R CMD check.
GitHub Actions runs package checks on every push and pull request, and can also be started from the Actions tab. The matrix covers Windows and macOS with R-release, plus Linux with R-release, R-devel and the previous R release. Errors and warnings fail the check; notes remain in the logs for review. Check reports are saved as workflow artifacts, including successful runs.
The matrix checks examples, regression tests and help files using
--as-cran. The Linux R-release job also compiles the PDF
manual. All check logs and notes must be reviewed before a CRAN
submission. The workflow does not publish the package to CRAN.
The test-coverage workflow measures line coverage on
every push and pull request. It runs both
tests/regression.R and the testthat suite,
without coverage exclusions. The workflow summary shows the overall
percentage and per-file coverage. Download the
test-coverage artifact for the Cobertura XML report,
uncovered-line CSV, and coverage RDS object. The README badge shows
workflow status, not the coverage percentage.
To generate the same reports locally, run from the package root:
install.packages(c("covr", "xml2")) # Once, if not already installed
source(".github/scripts/coverage.R")Reports are written to coverage/, which is excluded from
Git and the package source archive. Coverage measures which lines were
executed; the numerical assertions in the tests assess whether the
results are correct.
Codecov uploads are optional. Enable kunhaiq/ssMRCT in
Codecov and add its upload token as the GitHub repository Actions secret
CODECOV_TOKEN. The workflow then uploads its report
automatically. Without this secret, the GitHub summary and artifacts
remain available, and the upload step is skipped.