Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve text summaries of group sequential designs #160

Open
nanxstats opened this issue Jul 15, 2024 · 1 comment
Open

Improve text summaries of group sequential designs #160

nanxstats opened this issue Jul 15, 2024 · 1 comment

Comments

@nanxstats
Copy link
Collaborator

Keaven kindly provided a detailed analysis of the current text summary issues (mostly focusing on spending functions) for design objects generated by gsDesign. I will put it here for reference.

Make sure to render this using the development version of gsDesign (as of writing, 3.6.3.1) so it captures the state of outputs correctly.

remotes::install_github("keaven/gsDesign@1c4202c")
Click to expand spending-function-summary-issues.Rmd
---
title: "Textual summaries of group sequential designs"
author: "Keaven M. Anderson"
date: "2024-07-12"
output:
  html_document:
    toc: true
    toc_float: true
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

## Overview

```{r, message=FALSE}
library(gsDesign)
library(gt)
```

This is to document issues with printing textual summaries of group sequential designs.
This largely focuses on spending functions, but also includes other issues for textual design summary.
We do not cover tabular summaries provided by the `gsBoundSummary()` function here.
As a simple example, we consider a 2-sided symmetric design for a time-to-event endpoint.

```{r}
gsSurv(k = 2, test.type = 2, sfu = sfHSD, sfupar = -8) |> summary()
```

Designs for other endpoint types do not include as much information about the endpoint type.

```{r}
n.fix <- nBinomial(p1 = .1, p2 = .2)
gsDesign(k = 2, test.type = 1, sfu = sfLDOF, ) |> summary()
```

## Cases with no problems

### Boundary family specification

For `test.type = 1` or `test.type = 2` boundary families can be used to specify bounds.
For the O'Brien-Fleming family, we have:

```{r}
gsDesign(k = 2, test.type = 1, sfu = "OF") |> summary()
```

For the Pocock family, we have:

```{r}
gsDesign(k = 2, test.type = 1, sfu = "Pocock") |> summary()
```

Wang-Tsiatis bounds (Wang and Tsiatis 1987) are not available for `test.type = 1` or `test.type = 2`.
The parameter value is a scalar greater than or equal to 0. A value of 0 yields O'Brien-Fleming bounds
A value of 0.5 yields Pocock bounds.

```{r}
gsDesign(k = 2, test.type = 1, sfu = "WT", sfupar = 0.25) |> summary()
```

### No parameters

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfLDPocock) |> summary()
```

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfLDOF) |> summary()
```

Same thing, but specified differently:

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfLDOF, sfupar = 1) |> summary()
```

Now with a different parameter value, the parameter value should be printed:

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfLDOF, sfupar = 2) |> summary()
```

### One parameter spending functions

For one-parameter spending functions as well as spending functions with no parameters, there are currently no issues.

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfHSD, sfupar = 2) |> summary()
```

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfPower, sfupar = 2) |> summary()
```

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfExponential, sfupar = .75) |> summary()
```

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfXG1, sfupar = .5) |> summary()
```

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfXG2, sfupar = .5) |> summary()
```

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfXG3, sfupar = .5) |> summary()
```

## Cases with summary issues

### 2-parameter spending functions

There are issues summarizing the 2-parameter spending functions `sfLogistic()`, `sfNormal()`, `sfCauchy()`, `sfBetaDist()`, `sfExtremeValue()`, and `sfExtremeValue2()`.
As noted in the help file:

> In the two-parameter specification, `sfBetaDist()` requires 2 positive values, while `sfLogistic()`, `sfNormal()`, `sfExtremeValue()`,
> `sfExtremeValue2()` and `sfCauchy()` require the first parameter to be any real value and the second to be a positive value. The four parameter specification is `c(t1,t2,u1,u2)` where the objective is that `sf(t1)=alpha*u1` and `sf(t2)=alpha*u2`. In this parameterization, all four values must be between 0 and 1 and t1 < t2, u1 < u2.

We consider the 2-parameter version:

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfLogistic, sfupar = c(.5, 1.5)) |> summary()
```

This is not ideal, but OK; perhaps better would be `a = 0.5, b = 1.5`. The 4-parameter version is:

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfLogistic, sfupar = c(.5, .75, .2, .4)) |> summary()
```

This is kind of ugly! The preference might be for the 4-parameter version to be summarized with `at spending time of 0.5 and 0.75, the spending fraction are 0.2 and 0.4 of total spending, respectively`. Usually "spending time" will be information fraction, but not always; i.e., if `usTime` is `NULL`, this can be "information fraction" and otherwise can be "spending time fraction". When `test.type = 3, 4, 5` or `6`, the same can be said for the lower spending bound summary.

```{r}
gsDesign(k = 2, test.type = 4, sfu = sfLDOF, sfl = sfLogistic, sflpar = c(.5, .75, .2, .4)) |> summary()
```

### 3-parameter spending function

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfTDist, sfupar = c(.5, .75, .2, .4, 6)) |> summary()
```

Better would be `at spending time of 0.5 and 0.75, the spending function is fraction 0.2 and 0.4 of total spending, respectively, with 6 degrees of freedom` (wow: Copilot wrote that quote!).
The other option for this is a 3-parameter value specification:

```{r}
gsDesign(k = 2, test.type = 1, sfu = sfTDist, sfupar = c(.1, 2, 6)) |> summary()
```

Better description would be `the spending function is based on a t-distribution spending function with 6 degrees of freedom, a = 0.1, and b = 2.`

### Piecewise linear

## Spending functions to deprecate

`sfTrimmed()`, `sfGapped()`, and `sfTruncated()` should probably be deprecated. Would it make sense to leave them in package but not export them?
Documenting how these can be worked around using `usTime` and `lsTime` in a vignette and/or the manual could be useful.

## References

Wang, Samuel K, and Anastasios A Tsiatis. 1987. "Approximately Optimal One-Parameter Boundaries for Group Sequential Trials." _Biometrics_, 193--99.
@nanxstats
Copy link
Collaborator Author

Since this is only partially fixed by #162, I'm reopening this.

@nanxstats nanxstats reopened this Oct 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants