Skip to content

Add add_hierarchical_zero_rows() for unobserved hierarchical levels - #609

Open
Melkiades wants to merge 8 commits into
pharmaverse:mainfrom
Melkiades:602_hierarchical_zero_rows
Open

Melkiades wants to merge 8 commits into
pharmaverse:mainfrom
Melkiades:602_hierarchical_zero_rows

Conversation

@Melkiades

Copy link
Copy Markdown
Collaborator

Adds add_hierarchical_zero_rows(), an ARD-level helper that appends zero-count rows for unobserved hierarchical levels using a mapping of the expected level universe.

A single mapping argument (named list or two-column data.frame) covers:

  • an unobserved top-level category (e.g. an SOC with no events),
  • the children of a missing parent,
  • an unobserved child under an observed parent.

Preserves the by structure and carries denominators over so percentages stay correct (p = 0, no NaN).

closes #602

Stacked hierarchical ARDs include only observed levels because the
tabulation routes through the strata (observed-only) branch, so predefined
categories such as SMQ/CQ baskets, SOCs, and preferred terms disappear
instead of showing a zero count.

add_hierarchical_zero_rows() appends zero-count rows for unobserved levels
using a mapping of the expected level universe. A single mapping argument
(named list or data.frame) covers both an unobserved top-level category and
an unobserved child of an observed parent, and preserves the by structure
and denominators so percentages remain correct.
Comment thread R/add_hierarchical_zero_rows.R Outdated
Comment thread R/add_hierarchical_unobserved_levels.R Outdated
@ddsjoberg

Copy link
Copy Markdown
Collaborator

Preserves the by structure and carries denominators over so percentages stay correct (p = 0, no NaN).

What do you mean by percentages stay correct? 0 / 0 != 0, but it is undefined! You already have functinality in crane to turn a 0 (NaN%) into 0

Read the expected level universe from the factor levels the ARD already
carries, so top-level and nested completion need only `variables`. `mapping`
becomes optional and additive, used only for children of an unobserved parent
or a bespoke universe that factor levels cannot express.
Comment thread R/add_hierarchical_zero_rows.R Outdated
Comment thread R/add_hierarchical_zero_rows.R Outdated
Comment thread R/add_hierarchical_zero_rows.R Outdated
Comment thread R/add_hierarchical_zero_rows.R Outdated
Rename the function (and its file/tests/docs) to
add_hierarchical_unobserved_levels(), matching the intent of adding
unobserved factor levels rather than raw zero-rows.

Drop the user-facing `statistic` argument; the count-style stats are zeroed
internally while denominators carry over, so callers no longer manage that
detail. Rewrite the documentation to lead with the single-variable case and
cross-link gtsummary::tbl_hierarchical() so users can discover it.
@Melkiades
Melkiades marked this pull request as ready for review August 25, 2026 13:34
A never-observed level has no one at risk, so its proportion is 0 / 0 --
undefined, not zero. Set only the counts (n, n_cum) to zero and leave
p/p_cum as NaN, letting the display layer recode them rather than asserting
zero in the ARD.
@Melkiades

Copy link
Copy Markdown
Collaborator Author

Preserves the by structure and carries denominators over so percentages stay correct (p = 0, no NaN).

What do you mean by percentages stay correct? 0 / 0 != 0, but it is undefined! You already have functinality in crane to turn a 0 (NaN%) into 0

I was mapping it to 0 which is wrong. now for an added unobserved level the proportion is 0 / 0, which is undefined ,so I leave p/p_cum as NaN rather than asserting 0 in the ARD. The "show as 0" is a display choice and gets recoded downstream, so the ARD stays correct!!

Comment thread NEWS.md Outdated
Comment thread R/add_hierarchical_unobserved_levels.R Outdated
Comment thread R/add_hierarchical_unobserved_levels.R Outdated
Comment thread R/add_hierarchical_unobserved_levels.R
ddsjoberg and others added 3 commits September 7, 2026 17:30
Replace the factor-level reading and the named-list mapping with a
single levels data frame whose columns are named after the hierarchical
variables. This removes the positional matching, drops the reliance on
factor levels, and treats every level of the hierarchy the same way: a
newly added parent gets its full child set through the same code path as
an observed parent.
pkgdown requires every exported topic to be indexed; the new function
was missing from _pkgdown.yml, failing the docs build.
#' recoded for display rather than asserted as zero here.
#'
#' @param x (`card`)\cr
#' a stacked hierarchical ARD created with [ard_stack_hierarchical()].

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this work with the counting variant as well?

#' Use a single column (e.g. just `AESOC`) to complete only the top level.
#'
#' @return a stacked hierarchical ARD
#' @seealso [gtsummary::tbl_hierarchical()], [ard_stack_hierarchical()], [sort_ard_hierarchical()]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would take these out. They are essentially internal helpers [gtsummary::tbl_hierarchical()], [ard_stack_hierarchical()]

#'
#' @examples
#' set.seed(1)
#' adae <- data.frame(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't simulate our AE datasets in the other examples. why did you choose to do it here?

Comment on lines +64 to +65
.hierarchical_zero_stats <- c("n", "n_cum")
.hierarchical_nan_stats <- c("p", "p_cum")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if a user has the cum counts/percentage in the source table?

@@ -0,0 +1,180 @@
skip_on_cran()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude is notorious for over-testing, or not quite testing the things that matter the most to us. Can you confirm you have reviewed each of these manually and agree with all the tests added and do not see any missing tests?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Retain unobserved factor levels in hierarchical tabulations

2 participants