This vignette compares two common workflows for group sequential design:
gsDesign in R, andPROC SEQDESIGN in SAS.The goal is not to claim one method is universally better, but to clarify where the methods are aligned and where their assumptions and outputs differ in day-to-day use.
Both approaches are built on the same core large-sample theory:
In other words, if you match design intent (error rates, timing, boundary family, and endpoint scale), you should expect qualitatively similar operating characteristics.
The table below summarizes practical differences users most often encounter.
assumption_cmp <- data.frame(
Topic = c(
"Parameterization",
"Information-time handling",
"Futility interpretation",
"Design flexibility"
),
gsDesign = c(
"Directly parameterized around spending functions and canonical Z-scale boundaries.",
"Arbitrary timing vector is natural input; design can be recalibrated from information fractions.",
"Explicit non-binding vs binding behavior through design/test-type choices.",
"Broad function-level customization in R objects and user-defined workflows."
),
PROC_SEQDESIGN = c(
"Specified via procedure statements/options that map to boundary families and error control targets.",
"Stage structure and information schedule are declared in procedure options.",
"Futility behavior is typically encoded by boundary/stop choices and analysis conventions.",
"Strong standardized procedure workflow with ODS-oriented reporting."
),
check.names = FALSE,
stringsAsFactors = FALSE
)
knitr::kable(assumption_cmp, align = c("l", "l", "l"))| Topic | gsDesign | PROC_SEQDESIGN |
|---|---|---|
| Parameterization | Directly parameterized around spending functions and canonical Z-scale boundaries. | Specified via procedure statements/options that map to boundary families and error control targets. |
| Information-time handling | Arbitrary timing vector is natural input; design can be recalibrated from information fractions. | Stage structure and information schedule are declared in procedure options. |
| Futility interpretation | Explicit non-binding vs binding behavior through design/test-type choices. | Futility behavior is typically encoded by boundary/stop choices and analysis conventions. |
| Design flexibility | Broad function-level customization in R objects and user-defined workflows. | Strong standardized procedure workflow with ODS-oriented reporting. |
Both methods provide stopping boundaries and operating characteristics, but the default output style is different.
gsDesign returns an R object with components for
boundaries, spending, crossing probabilities, sample size inflation, and
plotting support.PROC SEQDESIGN provides procedure output tables
(commonly via ODS) with boundary and operating-characteristic
summaries.In short, gsDesign tends to be object-centric for
programmable post-processing, whereas PROC SEQDESIGN is
report-centric out of the box.
gsDesign exampleWe generate a one-sided, 3-look design with O’Brien-Fleming-like spending for efficacy and futility.
x <- gsDesign(
k = 3,
test.type = 4,
alpha = 0.025,
beta = 0.10,
timing = c(0.33, 0.67),
sfu = sfLDOF,
sfupar = 0,
sfl = sfLDOF,
sflpar = 0
)
gs_tbl <- data.frame(
Analysis = seq_len(x$k),
InfoFrac = x$timing,
LowerZ = round(x$lower$bound, 3),
UpperZ = round(x$upper$bound, 3),
LowerSpend = signif(x$lower$spend, 4),
UpperSpend = signif(x$upper$spend, 4),
N = ceiling(x$n.I)
)
knitr::kable(gs_tbl)| Analysis | InfoFrac | LowerZ | UpperZ | LowerSpend | UpperSpend | N |
|---|---|---|---|---|---|---|
| 1 | 0.33 | -0.719 | 3.731 | 0.004192 | 0.0000955 | 1 |
| 2 | 0.67 | 1.017 | 2.504 | 0.040290 | 0.0060800 | 1 |
| 3 | 1.00 | 1.994 | 1.994 | 0.055520 | 0.0188200 | 2 |
The resulting table makes explicit what analysts often need for simulation or protocol drafting: analysis timing, upper/lower Z-boundaries, cumulative spending, and planned sample size by look.
PROC SEQDESIGNThe same design intent can be specified in SAS, with exact option names depending on SAS version and local coding standards.
/* Template only: verify option names against your SAS version documentation */
proc seqdesign;
OBFDesign: design nstages=3
alpha=0.025
beta=0.10
info=(0.33 0.67 1.00)
method=errfuncobf
stop=both;
run;
When comparing across systems, check that the following match before concluding results are different:
Use gsDesign when you need programmable reproducibility,
transparent object-level inspection, and integration with R
simulation/reporting pipelines.
Use PROC SEQDESIGN when your statistical computing
environment is SAS-centric and standardized procedure output is the
primary deliverable.
For regulatory or internal review, the best practice is to document design assumptions explicitly and provide a cross-platform reconciliation table rather than relying on nominal boundary labels alone.