-
-
Notifications
You must be signed in to change notification settings - Fork 27
Add G-computation correction for emmeans, contrasts argument, and expanded emp_start #567
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
base: main
Are you sure you want to change the base?
Changes from 9 commits
03e1ab5
fbd2bcc
823734a
c10904f
df99ae7
f5dba54
6b4dd91
9904116
6176538
ace6d7c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,3 +21,4 @@ simulations | |
| ^data-raw$ | ||
| ^cache$ | ||
| ^[.]?air[.]toml$ | ||
| ^\.claude$ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| .claude | ||
| .DS_Store | ||
| .httr-oauth | ||
| .project | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -222,6 +222,14 @@ refit_multiple_optimizers <- function(fit, ..., control = mmrm_control(...)) { | |||||
| #' @param disable_theta_vcov (`flag`)\cr whether to disable calculation of | ||||||
| #' variance-covariance matrix for variance parameters. This can speed up fitting | ||||||
| #' when there are many variance parameters, see details. | ||||||
| #' @param emmeans_gcomp_vars (`character` or `NULL`)\cr names of variables to | ||||||
| #' treat as fixed in the G-computation correction for emmeans. When non-`NULL`, | ||||||
| #' enables the correction in [`emmeans_support`], producing the average | ||||||
| #' treatment effect (ATE) with corrected standard errors. The visit variable | ||||||
| #' (identified from the covariance structure) is computed separately per | ||||||
| #' level. All other named variables are treated as intervention (subjects | ||||||
| #' pooled across levels). All variables not named are averaged over using | ||||||
| #' each subject's actual values. Defaults to `NULL` (no correction). | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
we don't mention defaults in the text |
||||||
| #' @param ... additional arguments passed to [h_get_optimizers()]. | ||||||
| #' | ||||||
| #' @details | ||||||
|
|
@@ -282,11 +290,13 @@ mmrm_control <- function( | |||||
| accept_singular = TRUE, | ||||||
| drop_visit_levels = TRUE, | ||||||
| disable_theta_vcov = FALSE, | ||||||
| emmeans_gcomp_vars = NULL, | ||||||
| ..., | ||||||
| optimizers = h_get_optimizers(...) | ||||||
| ) { | ||||||
| assert_count(n_cores, positive = TRUE) | ||||||
| assert_character(method) | ||||||
| assert_character(emmeans_gcomp_vars, min.len = 1L, null.ok = TRUE) | ||||||
| if (is.null(start)) { | ||||||
| start <- std_start | ||||||
| } | ||||||
|
|
@@ -352,7 +362,8 @@ mmrm_control <- function( | |||||
| vcov = vcov, | ||||||
| n_cores = as.integer(n_cores), | ||||||
| drop_visit_levels = drop_visit_levels, | ||||||
| disable_theta_vcov = disable_theta_vcov | ||||||
| disable_theta_vcov = disable_theta_vcov, | ||||||
| emmeans_gcomp_vars = emmeans_gcomp_vars | ||||||
| ), | ||||||
| class = "mmrm_control" | ||||||
| ) | ||||||
|
|
@@ -374,6 +385,16 @@ mmrm_control <- function( | |||||
| #' as produced with [cov_struct()], or value that can be coerced to a | ||||||
| #' covariance structure using [as.cov_struct()]. If no value is provided, | ||||||
| #' a structure is derived from the provided formula. | ||||||
| #' @param contrasts (`list` or `NULL`)\cr an optional named list of contrast | ||||||
| #' matrices or contrast functions (like [stats::contr.sum] or | ||||||
| #' [stats::contr.poly]) for specific factor variables, matching the | ||||||
| #' `contrasts` argument in [stats::lm()]. The list names must correspond to | ||||||
| #' factor variable names in the model formula. When `NULL` (the default), | ||||||
| #' the contrasts set on the factor variables in `data` are used. If a | ||||||
| #' contrast matrix has rownames that include levels not present in `data`, | ||||||
| #' those levels are preserved and the corresponding model matrix columns | ||||||
| #' are marked as aliased (not estimable), enabling prediction on new data | ||||||
| #' containing those levels. | ||||||
| #' @param control (`mmrm_control`)\cr fine-grained fitting specifications list | ||||||
| #' created with [mmrm_control()]. | ||||||
| #' @param ... arguments passed to [mmrm_control()]. | ||||||
|
|
@@ -466,13 +487,16 @@ mmrm <- function( | |||||
| data, | ||||||
| weights = NULL, | ||||||
| covariance = NULL, | ||||||
| contrasts = NULL, | ||||||
| reml = TRUE, | ||||||
| control = mmrm_control(...), | ||||||
| ... | ||||||
| ) { | ||||||
| assert_false(!missing(control) && !missing(...)) | ||||||
| assert_class(control, "mmrm_control") | ||||||
| assert_list(control$optimizers, min.len = 1) | ||||||
| assert_list(contrasts, null.ok = TRUE, names = "unique") | ||||||
| emmeans_gcomp_vars <- control$emmeans_gcomp_vars | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's just do this below for the gcomp stuff |
||||||
|
|
||||||
| if (control$method %in% c("Kenward-Roger", "Kenward-Roger-Linear") && !reml) { | ||||||
| stop("Kenward-Roger only works for REML") | ||||||
|
|
@@ -494,14 +518,21 @@ mmrm <- function( | |||||
| } else { | ||||||
| attr(weights, which = "dataname") <- deparse(match.call()$weights) | ||||||
| } | ||||||
|
|
||||||
| # Validate G-computation fixed variables if specified. | ||||||
| if (!is.null(emmeans_gcomp_vars)) { | ||||||
| assert_subset(emmeans_gcomp_vars, names(data)) | ||||||
| } | ||||||
|
Comment on lines
+522
to
+525
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's do this below as well to simplify the code structure |
||||||
|
|
||||||
| tmb_data <- h_mmrm_tmb_data( | ||||||
| formula_parts, | ||||||
| data, | ||||||
| weights, | ||||||
| reml, | ||||||
| singular = if (control$accept_singular) "drop" else "error", | ||||||
| drop_visit_levels = control$drop_visit_levels, | ||||||
| allow_na_response = FALSE | ||||||
| allow_na_response = FALSE, | ||||||
| contrasts = contrasts | ||||||
| ) | ||||||
| fit <- structure("", class = "try-error") | ||||||
| names_all_optimizers <- names(control$optimizers) | ||||||
|
|
@@ -589,6 +620,20 @@ mmrm <- function( | |||||
| stop("Unrecognized coefficent variance-covariance method!") | ||||||
| } | ||||||
|
|
||||||
| # G-computation correction: store metadata for emmeans hook. | ||||||
| fit$emmeans_gcomp_vars <- emmeans_gcomp_vars | ||||||
| if (!is.null(emmeans_gcomp_vars)) { | ||||||
| # Store subject-level covariate data from the ORIGINAL data (pre-NA-removal). | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please also add a comment in the code here why this cannot be taken from |
||||||
| # This includes subjects with observed covariates but missing outcomes, | ||||||
| # who contribute to the G-computation average but not to beta estimation. | ||||||
| subject_var <- formula_parts$subject_var | ||||||
| subj_rows <- !duplicated(data[[subject_var]]) | ||||||
| model_vars <- all.vars(formula_parts$model_formula) | ||||||
| keep_vars <- intersect(c(subject_var, model_vars), names(data)) | ||||||
| fit$emmeans_gcomp_subject_data <- data[subj_rows, keep_vars, drop = FALSE] | ||||||
| rownames(fit$emmeans_gcomp_subject_data) <- NULL | ||||||
| } | ||||||
|
|
||||||
| class(fit) <- c("mmrm", class(fit)) | ||||||
| fit | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so far we don't link to any GH issues so no need for this