Skip to content

Commit 834d838

Browse files
committed
gbsg deprecation seems complete CRAN check passes
1 parent ff765b8 commit 834d838

16 files changed

Lines changed: 1501 additions & 141 deletions

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ export(run_single_consistency_split)
113113
export(save_forestplot)
114114
export(select_best_subgroup)
115115
export(sensitivity_analysis_k_inter)
116+
export(setup_gbsg_dgm)
116117
export(setup_parallel_SGcons)
117118
export(sg_consistency_out)
118119
export(sg_tables)

NEWS.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# forestsearch NEWS
2+
3+
## forestsearch 0.2.0
4+
5+
### New functions
6+
7+
* `generate_aft_dgm_flex()` — general data-generating model (DGM) builder.
8+
Replaces the GBSG-specific `create_gbsg_dgm()` as the primary DGM
9+
constructor. Accepts any survival dataset and fits an accelerated failure
10+
time (AFT) super-population model with user-specified treatment effect
11+
heterogeneity parameters.
12+
13+
* `simulate_from_dgm()` — general simulator for drawing trial replicates from
14+
an `aft_dgm_flex` DGM. Replaces `simulate_from_gbsg_dgm()`. Column names
15+
in the returned data frame use underscore notation (`y_sim`, `event_sim`,
16+
`treat_sim`, `flag_harm`).
17+
18+
* `run_simulation_analysis()` (general version) — simulation wrapper that
19+
calls `simulate_from_dgm()` and accepts explicit column-name parameters,
20+
making it applicable to any DGM built with `generate_aft_dgm_flex()`. The
21+
GBSG dataset is now one application of this general pipeline rather than a
22+
separate code path.
23+
24+
* `setup_gbsg_dgm()` — convenience bridge function. Wraps
25+
`create_gbsg_dgm()` (see Deprecated below) and reshapes its output to the
26+
`aft_dgm_flex` class expected by `simulate_from_dgm()` and
27+
`run_simulation_analysis()`. Existing GBSG-based simulation scripts can
28+
adopt the general pipeline with a one-line change:
29+
`dgm <- setup_gbsg_dgm(model = "alt", k_inter = k, seed = seed)`.
30+
31+
### Deprecated functions
32+
33+
The following functions are retained and fully functional but will be removed
34+
in a future version. Each emits a deprecation warning on first call with a
35+
concrete migration example.
36+
37+
* `create_gbsg_dgm()` → use `generate_aft_dgm_flex()` or `setup_gbsg_dgm()`.
38+
39+
* `simulate_from_gbsg_dgm()` → use `simulate_from_dgm(analysis_time = Inf)`.
40+
Note: the new function defaults to `analysis_time = 48` (staggered-entry
41+
administrative censoring); pass `analysis_time = Inf` to match the legacy
42+
`max_follow = Inf` behaviour. Column names in the result also change — see
43+
the mapping table below.
44+
45+
| Legacy column | General column |
46+
|---------------|----------------|
47+
| `y.sim` | `y_sim` |
48+
| `event.sim` | `event_sim` |
49+
| `treat` | `treat_sim` |
50+
| `flag.harm` | `flag_harm` |
51+
52+
### Deprecated parameters
53+
54+
* `run_simulation_analysis(max_follow)` → use `analysis_time`. If supplied,
55+
`max_follow` is silently forwarded to `analysis_time` with a warning.
56+
57+
* `run_simulation_analysis(muC_adj)` → use `cens_adjust`. If supplied,
58+
`muC_adj` is silently forwarded to `cens_adjust` with a warning.
59+
60+
### Bug fixes
61+
62+
The following bugs were discovered and fixed during the general pipeline
63+
migration. All affected code paths were exercised by GBSG factor variables
64+
(`v1``v7`) stored as `factor()` rather than `numeric()`.
65+
66+
* `lasso_selection()` (`get_FSdata_helpers.R`): `as.matrix()` on a data frame
67+
containing factor columns produced a character matrix that `cv.glmnet()`
68+
rejected. Factor columns with all-numeric levels are now coerced via
69+
`as.integer(as.character(.))` before matrix conversion.
70+
71+
* `process_conf_force_expr()` (`get_FSdata_helpers.R`): `mean()` applied to a
72+
factor column returned `NA`. Factor columns are now coerced to numeric before
73+
`mean()`, `median()`, and `quantile()` calls.
74+
75+
* `evaluate_comparison()` (`forestsearch_helpers.R`): the `<=` / `>=`
76+
operator applied to a factor column triggered an `Ops.factor` warning and
77+
returned `NA`. Factor columns are now coerced to numeric before comparison.
78+
79+
* `forestsearch()` (`forestsearch_main.R`): `df[, conf.screen]` dropped to a
80+
vector when `conf.screen` had length 1, causing `dummy()` to error on a
81+
non-data-frame input. Fixed by adding `drop = FALSE`.
82+
83+
* `default_grf_params_gen()` (`run_simulation_analysis.R`): `maxdepth` was
84+
initialised to `4`, exceeding the maximum of `3` accepted by
85+
`grf.subg.harm.survival()`. Corrected to `2` (matching the legacy default).
86+
87+
* `default_grf_params_gen()` (`run_simulation_analysis.R`): `sg.criterion`
88+
was set to `"hr"`, which is not a valid value. Corrected to `"mDiff"`
89+
(matching the legacy default).
90+
91+
### Internal changes
92+
93+
* `create_gbsg_dgm()` and `simulate_from_gbsg_dgm()` are now thin public
94+
wrappers that call `.create_gbsg_dgm_()` and `.simulate_from_gbsg_dgm_()`
95+
internally. This prevents deprecation-warning spam in functions that call
96+
these internally in loops or binary searches (`calibrate_k_inter()`,
97+
`get_dgm_with_output()`, `validate_k_inter_effect()`).
98+
99+
* `compute_dgm_cde()` now resolves the super-population data frame from
100+
`dgm$df_super_rand` (GBSG DGMs) or `dgm$df_super` (general `aft_dgm_flex`
101+
DGMs), making it compatible with both class hierarchies.
102+
103+
* `globals.R`: added `"sim_id"` to `utils::globalVariables()` to suppress a
104+
spurious `R CMD check` NOTE from `run_simulation_analysis.R`.
105+
106+
---
107+
108+
## forestsearch 0.1.0
109+
110+
* Initial release.

R/forestsearch_helpers.R

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@ evaluate_comparison <- function(expr, df) {
169169
}
170170

171171
col <- df[[var_name]]
172+
# Coerce factors with all-numeric levels to numeric so that
173+
# numeric comparisons (<=, >=, <, >) are meaningful.
174+
if (is.factor(col)) {
175+
lvls <- levels(col)
176+
if (!anyNA(suppressWarnings(as.numeric(lvls))))
177+
col <- as.numeric(as.character(col))
178+
}
172179
val <- suppressWarnings(as.numeric(value))
173180
if (is.na(val)) val <- value # keep as character for string comparisons
174181

R/forestsearch_main.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ forestsearch <- function(df.analysis,
527527
# (e.g., q1 -> q1.0, q1.1), so the search explores BOTH directions
528528
# of each cut (subgroup and complement).
529529

530-
df.confounders <- df[, conf.screen]
530+
df.confounders <- df[, conf.screen, drop = FALSE]
531531
df.confounders <- dummy(df.confounders)
532532

533533

R/get_FSdata_helpers.R

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,19 @@ if (!requireNamespace("glmnet", quietly = TRUE)) stop("Package 'glmnet' is requi
112112
if (!requireNamespace("survival", quietly = TRUE)) stop("Package 'survival' is required.")
113113

114114
# Prepare the design matrix and response
115-
x <- as.matrix(df[, confounders.name, drop = FALSE])
115+
# Coerce factor columns with all-numeric levels to integer so that
116+
# as.matrix() produces a numeric matrix (not a character one).
117+
# as.integer(as.character(f)) preserves the numeric value of each level
118+
# (e.g. factor "1" -> 1L), unlike plain as.integer(f) which gives 1-based codes.
119+
x_df <- df[, confounders.name, drop = FALSE]
120+
for (.nm in names(x_df)) {
121+
if (is.factor(x_df[[.nm]])) {
122+
.lvls <- levels(x_df[[.nm]])
123+
if (!anyNA(suppressWarnings(as.numeric(.lvls))))
124+
x_df[[.nm]] <- as.integer(as.character(x_df[[.nm]]))
125+
}
126+
}
127+
x <- as.matrix(x_df)
116128

117129
y <- survival::Surv(df[[outcome.name]], df[[event.name]])
118130

@@ -187,15 +199,18 @@ process_conf_force_expr <- function(expr, df) {
187199
arg <- matches[4]
188200
# Only proceed if var and arg match
189201
if (!(var %in% colnames(df)) || !(arg %in% colnames(df))) return(expr)
202+
# Coerce factor columns to numeric before computing summary statistics
203+
col_vals <- df[[arg]]
204+
if (is.factor(col_vals)) col_vals <- as.numeric(as.character(col_vals))
190205
# Evaluate the function
191206
if (fun == "mean") {
192-
val <- round(mean(df[[arg]], na.rm = TRUE), 1)
207+
val <- round(mean(col_vals, na.rm = TRUE), 1)
193208
} else if (fun == "median") {
194-
val <- round(median(df[[arg]], na.rm = TRUE), 1)
209+
val <- round(median(col_vals, na.rm = TRUE), 1)
195210
} else if (fun == "qlow") {
196-
val <- round(quantile(df[[arg]], 0.25, na.rm = TRUE), 1)
211+
val <- round(quantile(col_vals, 0.25, na.rm = TRUE), 1)
197212
} else if (fun == "qhigh") {
198-
val <- round(quantile(df[[arg]], 0.75, na.rm = TRUE), 1)
213+
val <- round(quantile(col_vals, 0.75, na.rm = TRUE), 1)
199214
} else {
200215
# Unknown function, return as is
201216
return(expr)

R/globals.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ utils::globalVariables(c(
216216
"hr.Hc.true", "hr.Hc.hat",
217217
"hr.itt", "hr.adj.itt",
218218
"p.cens", "taumax",
219+
"sim_id",
219220
"analysis",
220221
"trimmed",
221222
"aa",

R/oc_analyses_gbsg.R

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,10 @@ get_dgm_hr <- function(dgm, which = "hr_H") {
209209
#' @export
210210
compute_dgm_cde <- function(dgm, harm_col = NULL) {
211211

212-
df <- dgm$df_super_rand
212+
# Support both gbsg_dgm (df_super_rand) and aft_dgm_flex (df_super)
213+
df <- dgm$df_super_rand %||% dgm$df_super
213214
if (is.null(df)) {
214-
warning("DGM has no df_super_rand; cannot compute CDE.")
215+
warning("DGM has no df_super_rand or df_super; cannot compute CDE.")
215216
return(dgm)
216217
}
217218
if (!all(c("theta_0", "theta_1") %in% names(df))) {
@@ -1277,8 +1278,13 @@ run_grf_analysis <- function(
12771278
#'
12781279
#' @importFrom data.table data.table rbindlist
12791280
#' @importFrom stats rnorm
1280-
#' @export
1281-
run_simulation_analysis <- function(
1281+
# Legacy GBSG-coupled implementation — retained as internal for backwards
1282+
# compatibility. The exported run_simulation_analysis() now lives in
1283+
# R/run_simulation_analysis.R and accepts any aft_dgm_flex DGM.
1284+
# Parameters max_follow / muC_adj are forwarded as deprecated shims in the
1285+
# general version.
1286+
#' @keywords internal
1287+
.run_simulation_analysis_legacy_ <- function(
12821288
sim_id,
12831289
dgm,
12841290
n_sample,

0 commit comments

Comments
 (0)