Nothing
#' Extract low level terms from soc classification
#'
#' @description `r lifecycle::badge('stable')` Collect llt codes from a `meddra`
#' data.table, given another term of the MedDRA SOC Hierarchy.
#'
#' @details `get_llt_soc()` is an *ID collector* function. The function extracts low level term codes.
#' `get_llt_soc()` is **case-sensitive**, and MedDRA terms always begin with a capital letter,
#' in their native version.
#' In `term_sel`, all terms should come from the same hierarchical level,
#' e.g. all preferred terms, all high level terms, etc.
#'
#' @param term_sel A named list of character vector(s). The terms to extract llts codes from. See details.
#' @param term_level A character string. One of "soc", "hlgt", "hlt", "pt", or "llt"
#' @param meddra A data.table. Built from meddra_builders functions
#' @param verbose Logical. Allows you to see matching reactions in the console.
#' @returns A named list of integers. Low-level term codes.
#' @keywords data_management meddra soc llt
#' @seealso [get_llt_smq()]
#' @export
#' @examplesIf interactive()
#'
#' ## Finding llt codes for colitis
#'
#' pt_sel <- rlang::list2(
#' colitis = c("Colitis",
#' "Autoimmune colitis"),
#' pneumonitis = c("Pneumonitis",
#' "Organising pneumonia")
#' )
#'
#' hlt_sel <- rlang::list2(
#' colitis = c("Gastrointestinal inflammatory disorders NEC"),
#' pneumonitis = c("Pulmonary thrombotic and embolic conditions")
#' )
#'
#' # Remember you can use more than one term to define each adverse reaction,
#' # but they should all be at the same hierarchical level in meddra.
#'
#' # with preferred terms
#'
#' get_llt_soc(
#' term_sel = pt_sel,
#' term_level = "pt",
#' meddra = meddra_
#' )
#'
#' # with high level terms
#'
#' get_llt_soc(
#' term_sel = hlt_sel,
#' term_level = "hlt",
#' meddra = meddra_
#' )
get_llt_soc <-
function(
term_sel,
term_level = c("soc", "hlgt", "hlt", "pt", "llt"),
meddra,
verbose = TRUE
) {
term_level <- rlang::arg_match(term_level)
term_col <- paste0(term_level, "_name")
if("Table" %in% class(meddra)){
# automatically collect meddra if out of memory
# since it's a small table
meddra <-
dplyr::collect(meddra)
}
check_data_meddra(meddra)
# check for match and collect term codes
llt_codes_dataset <-
get_term_matching_and_codes(term_sel, term_col, meddra)
# gather matching and non matching terms
matching_terms <-
llt_codes_dataset |>
purrr::map(function(lcd){
lcd |>
dplyr::filter(!is.na(.data$match)) |>
dplyr::distinct(.data$term) |>
dplyr::pull(term)
})
unmatching_terms <-
llt_codes_dataset |>
purrr::map(function(lcd){
lcd |>
dplyr::filter(is.na(.data$match)) |>
dplyr::distinct(.data$term) |>
dplyr::pull(term)
}) |>
purrr::compact()
# keep codes
llt_list <-
llt_codes_dataset |>
purrr::map(function(lcd){
lcd |>
dplyr::filter(!is.na(.data$match)) |>
dplyr::pull(.data$llt_code) |>
unique()
})
if (length(unmatching_terms) > 0 | verbose == TRUE){
cli_h1("get_llt_soc()")
if(verbose == TRUE)
msg_getlltsoc_match(llt_codes_dataset, term_level)
if(length(unmatching_terms) > 0){
cli_h2("{col_red({symbol$cross})} Unmatched reactions")
msg_getlltsoc_no_match(unmatching_terms, term_level)
}
}
llt_list
}
# Helpers -----------------------------------------------------
get_term_matching_and_codes <-
function(term_sel, term_col, meddra){
llt_codes_dataset <-
term_sel |>
purrr::map(function(t_)
data.frame(
term = t_
) |>
dplyr::left_join(
meddra |>
dplyr::distinct(.data[[term_col]], .data$llt_code) |>
dplyr::mutate(match = 1),
by = c("term" = term_col)
)
)
return(llt_codes_dataset)
}
msg_getlltsoc_match <-
function(llt_codes_dataset,
term_level
){
msg_match <- function() {
lines <-
llt_codes_dataset |>
purrr::map(function(lcd)
lcd |>
dplyr::filter(!is.na(.data$match)) |>
dplyr::group_by(.data$term) |>
dplyr::summarise(lab =
paste0(unique(term), " (",dplyr::n(), ")")) |>
dplyr::pull(.data$lab)
)
cli_par()
cli_h2("{col_green({symbol$tick})} Matched reactions at {.code {term_level}} level (number of codes)")
cli_end()
cli_par()
lines_cli <-
lines |> purrr::imap(function(l_, n_){
l_lab <- if(length(l_) == 0) "{symbol$cross} No match" else "{.val {l_}}"
cli::cli_inform(
c(">" = paste0(
"{.code {n_}}: ",
l_lab)
)
)
})
cli_end()
cli_par()
cli::cli_alert_info(
"Set {.arg verbose} to FALSE to suppress this section."
)
cli_end()
}
msg_match()
}
msg_getlltsoc_no_match <-
function(res_list_no_match,
term_level
){
res_list_no_match_compact <-
purrr::compact(res_list_no_match)
no_capital_letter <-
res_list_no_match_compact |>
purrr::map(function(nm_)
nm_ |>
stringr::str_subset("^[a-z]")
)
other_unmatched_terms <-
list(ini = res_list_no_match_compact,
no_cap = no_capital_letter) |>
purrr::pmap(function(ini, no_cap)
ini[!ini %in% no_cap]
)
no_cap_compact <-
purrr::compact(no_capital_letter)
other_compact <-
purrr::compact(other_unmatched_terms)
msg_no_match <-
function() {
cli_par()
if (length(other_compact) > 0) {
cli_h3(paste0(
col_yellow("!"),
" Some reactions were not found at ",
"{.code {term_level}} level"
))
cli_end()
cli_par()
lid <- cli_ul()
for (i in seq_along(other_compact)) {
cli_li(
paste0(
'In {.code {names(other_compact)[i]}}:',
col_red(' {symbol$cross} '),
"{.val {other_compact[[i]]}}",
''
)
)
}
cli_end(lid)
}
if (length(no_cap_compact) > 0) {
cli_h3(
paste0(
col_yellow("!"),
" Some reactions did not start with a ",
col_yellow(style_underline("C")),
"apital letter"
)
)
cli_end()
cli_par()
lid2 <- cli_ul()
for (i in seq_along(no_cap_compact)) {
cli_li(
paste0(
'In {.code {names(no_cap_compact)[i]}}:',
col_red(' {symbol$cross} '),
"{.val {no_cap_compact[[i]]}}",
''
)
)
}
cli_end(lid2)
}
}
msg_no_match()
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.