gsDesign versus PROC SEQDESIGN

Introduction

This vignette compares two common workflows for group sequential design:

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.

Common statistical foundation

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.

Where assumptions differ in practice

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.

Where outputs differ

Both methods provide stopping boundaries and operating characteristics, but the default output style is different.

In short, gsDesign tends to be object-centric for programmable post-processing, whereas PROC SEQDESIGN is report-centric out of the box.

Worked gsDesign example

We generate a one-sided, 3-look design with O’Brien-Fleming-like spending for efficacy and futility.

library(gsDesign)
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.

Translating intent to PROC SEQDESIGN

The 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:

  1. one- versus two-sided Type I error convention,
  2. boundary family/spending choice,
  3. information times,
  4. binding vs non-binding treatment of futility,
  5. effect-size and endpoint scale conventions.

Practical guidance

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.