Skip to content

Commit 63391c0

Browse files
edelaruaddsjoberg
andauthored
Add ard_categorical_max() (#244)
**What changes are proposed in this pull request?** * Added function `ard_categorical_max()` to calculate categorical occurrence rates by maximum level per unique ID. (#240) Closes #240 -------------------------------------------------------------------------------- Pre-review Checklist (if item does not apply, mark is as complete) - [x] **All** GitHub Action workflows pass with a ✅ - [x] PR branch has pulled the most recent updates from master branch: `usethis::pr_merge_main()` - [x] If a bug was fixed, a unit test was added. - [x] If a new `ard_*()` function was added, it passes the ARD structural checks from `cards::check_ard_structure()`. - [x] If a new `ard_*()` function was added, `set_cli_abort_call()` has been set. - [x] If a new `ard_*()` function was added and it depends on another package (such as, `broom`), `is_pkg_installed("broom")` has been set in the function call and the following added to the roxygen comments: `@examplesIf do.call(asNamespace("cardx")$is_pkg_installed, list(pkg = "broom""))` - [x] Code coverage is suitable for any new functions/features (generally, 100% coverage for new code): `devtools::test_coverage()` Reviewer Checklist (if item does not apply, mark is as complete) - [ ] If a bug was fixed, a unit test was added. - [ ] Code coverage is suitable for any new functions/features: `devtools::test_coverage()` When the branch is ready to be merged: - [ ] Update `NEWS.md` with the changes from this pull request under the heading "`# cardx (development version)`". If there is an issue associated with the pull request, reference it in parentheses at the end update (see `NEWS.md` for examples). - [ ] **All** GitHub Action workflows pass with a ✅ - [ ] Approve Pull Request - [ ] Merge the PR. Please use "Squash and merge" or "Rebase and merge". --------- Co-authored-by: Daniel Sjoberg <danield.sjoberg@gmail.com>
1 parent a9235b8 commit 63391c0

File tree

7 files changed

+638
-0
lines changed

7 files changed

+638
-0
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export(ard_car_anova)
2626
export(ard_car_vif)
2727
export(ard_categorical)
2828
export(ard_categorical_ci)
29+
export(ard_categorical_max)
2930
export(ard_continuous)
3031
export(ard_continuous_ci)
3132
export(ard_dichotomous)

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
* Fixed a bug in `ard_survival_survfit()` causing an error when "=" character is present in stratification variable level labels. (#252)
88

9+
* Added function `ard_categorical_max()` to calculate categorical occurrence rates by maximum level per unique ID. (#240)
10+
911
# cardx 0.2.2
1012

1113
* Added a `data.frame` method to `ard_survival_survfit()`.

R/ard_categorical_max.R

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#' ARD to Calculate Categorical Occurrence Rates by Maximum Level Per Unique ID
2+
#'
3+
#' Function calculates categorical variable level occurrences rates by maximum level per unique ID.
4+
#' Each variable in `variables` is evaluated independently and then results for all variables are stacked.
5+
#' Only the highest-ordered level will be counted for each unique ID.
6+
#' Unordered, non-numeric variables will be converted to factor and the default level order used for ordering.
7+
#'
8+
#' @inheritParams cards::ard_categorical
9+
#' @inheritParams cards::ard_stack
10+
#' @param variables ([`tidy-select`][dplyr::dplyr_tidy_select])\cr
11+
#' The categorical variables for which occurrence rates per unique ID (by maximum level) will be calculated.
12+
#' @param id ([`tidy-select`][dplyr::dplyr_tidy_select])\cr
13+
#' Argument used to subset `data` to identify rows in `data` to calculate categorical variable level occurrence rates.
14+
#' @param denominator (`data.frame`, `integer`)\cr
15+
#' An optional argument to change the denominator used for `"N"` and `"p"` statistic calculations.
16+
#' Defaults to `NULL`, in which case `dplyr::distinct(data, dplyr::pick(all_of(c(id, by))))` is used for these
17+
#' calculations. See [cards::ard_categorical()] for more details on specifying denominators.
18+
#' @param quiet (scalar `logical`)\cr
19+
#' Logical indicating whether to suppress additional messaging. Default is `FALSE`.
20+
#'
21+
#' @return an ARD data frame of class 'card'
22+
#' @name ard_categorical_max
23+
#'
24+
#' @examples
25+
#' # Occurrence Rates by Max Level (Highest Severity) --------------------------
26+
#' ard_categorical_max(
27+
#' cards::ADAE,
28+
#' variables = c(AESER, AESEV),
29+
#' id = USUBJID,
30+
#' by = TRTA,
31+
#' denominator = cards::ADSL |> dplyr::rename(TRTA = ARM)
32+
#' )
33+
NULL
34+
35+
#' @rdname ard_categorical_max
36+
#' @export
37+
ard_categorical_max <- function(data,
38+
variables,
39+
id,
40+
by = dplyr::group_vars(data),
41+
statistic = everything() ~ c("n", "p", "N"),
42+
denominator = NULL,
43+
fmt_fn = NULL,
44+
stat_label = everything() ~ cards::default_stat_labels(),
45+
quiet = FALSE,
46+
...) {
47+
set_cli_abort_call()
48+
49+
# check inputs ---------------------------------------------------------------
50+
check_not_missing(data)
51+
check_not_missing(variables)
52+
check_not_missing(id)
53+
cards::process_selectors(data, variables = {{ variables }}, id = {{ id }}, by = {{ by }})
54+
data <- dplyr::ungroup(data)
55+
56+
# check the id argument is not empty
57+
if (is_empty(id)) {
58+
cli::cli_abort("Argument {.arg id} cannot be empty.", call = get_cli_abort_call())
59+
}
60+
61+
# return empty ARD if no variables selected ----------------------------------
62+
if (is_empty(variables)) {
63+
return(dplyr::tibble() |> cards::as_card())
64+
}
65+
66+
lst_results <- lapply(
67+
variables,
68+
function(x) {
69+
ard_categorical(
70+
data = data |>
71+
arrange_using_order(c(id, by, x)) |>
72+
dplyr::slice_tail(n = 1L, by = all_of(c(id, by))),
73+
variables = all_of(x),
74+
by = all_of(by),
75+
statistic = statistic,
76+
denominator = denominator,
77+
fmt_fn = fmt_fn,
78+
stat_label = stat_label
79+
)
80+
}
81+
)
82+
83+
# print default order of variable levels -------------------------------------
84+
for (v in variables) {
85+
lvls <- .unique_and_sorted(data[[v]])
86+
vec <- cli::cli_vec(
87+
lvls,
88+
style = list("vec-sep" = " < ", "vec-sep2" = " < ", "vec-last" = " < ", "vec-trunc" = 3)
89+
)
90+
if (!quiet) cli::cli_inform("{.var {v}}: {.val {vec}}")
91+
}
92+
93+
# combine results ------------------------------------------------------------
94+
result <- lst_results |>
95+
dplyr::bind_rows() |>
96+
dplyr::mutate(context = "categorical_max") |>
97+
cards::tidy_ard_column_order() |>
98+
cards::tidy_ard_row_order()
99+
100+
# return final result --------------------------------------------------------
101+
result
102+
}
103+
104+
# internal function copied from cards
105+
# like `dplyr::arrange()`, but uses base R's `order()` to keep consistency in some edge cases
106+
arrange_using_order <- function(data, columns) {
107+
inject(data[with(data, order(!!!syms(columns))), ])
108+
}

_pkgdown.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ reference:
8888
- ard_categorical_ci.data.frame
8989
- ard_regression
9090
- ard_regression_basic
91+
- ard_categorical_max
9192

9293
- title: "Helpers"
9394
- contents:

man/ard_categorical_max.Rd

Lines changed: 79 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)