1
0
mirror of https://github.com/msberends/AMR.git synced 2024-12-25 06:46:11 +01:00

add confidence intervals (fixed #70), remove combine_IR

This commit is contained in:
dr. M.S. (Matthijs) Berends 2022-10-20 16:08:01 +02:00
parent 85e2fbe4a3
commit aa2c0639d0
19 changed files with 248 additions and 144 deletions

View File

@ -1,6 +1,6 @@
Package: AMR Package: AMR
Version: 1.8.2.9023 Version: 1.8.2.9024
Date: 2022-10-19 Date: 2022-10-20
Title: Antimicrobial Resistance Data Analysis Title: Antimicrobial Resistance Data Analysis
Description: Functions to simplify and standardise antimicrobial resistance (AMR) Description: Functions to simplify and standardise antimicrobial resistance (AMR)
data analysis and to work with microbial and antimicrobial properties by data analysis and to work with microbial and antimicrobial properties by

View File

@ -325,6 +325,7 @@ export(reset_AMR_locale)
export(resistance) export(resistance)
export(resistance_predict) export(resistance_predict)
export(right_join_microorganisms) export(right_join_microorganisms)
export(rsi_confidence_interval)
export(rsi_df) export(rsi_df)
export(rsi_interpretation_history) export(rsi_interpretation_history)
export(rsi_predict) export(rsi_predict)

10
NEWS.md
View File

@ -1,4 +1,4 @@
# AMR 1.8.2.9023 # AMR 1.8.2.9024
This version will eventually become v2.0! We're happy to reach a new major milestone soon! This version will eventually become v2.0! We're happy to reach a new major milestone soon!
@ -9,7 +9,8 @@ This version will eventually become v2.0! We're happy to reach a new major miles
* Chromista are almost never clinically relevant, thus lacking the secondary scope of this package * Chromista are almost never clinically relevant, thus lacking the secondary scope of this package
* The `microorganisms` no longer relies on the Catalogue of Life, but now primarily on the List of Prokaryotic names with Standing in Nomenclature (LPSN) and is supplemented with the Global Biodiversity Information Facility (GBIF). The structure of this data set has changed to include separate LPSN and GBIF identifiers. Almost all previous MO codes were retained. It contains over 1,000 taxonomic names from 2022 already. * The `microorganisms` no longer relies on the Catalogue of Life, but now primarily on the List of Prokaryotic names with Standing in Nomenclature (LPSN) and is supplemented with the Global Biodiversity Information Facility (GBIF). The structure of this data set has changed to include separate LPSN and GBIF identifiers. Almost all previous MO codes were retained. It contains over 1,000 taxonomic names from 2022 already.
* The `microorganisms.old` data set was removed, and all previously accepted names are now included in the `microorganisms` data set. A new column `status` contains `"accepted"` for currently accepted names and `"synonym"` for taxonomic synonyms; currently invalid names. All previously accepted names now have a microorganisms ID and - if available - an LPSN, GBIF and SNOMED CT identifier. * The `microorganisms.old` data set was removed, and all previously accepted names are now included in the `microorganisms` data set. A new column `status` contains `"accepted"` for currently accepted names and `"synonym"` for taxonomic synonyms; currently invalid names. All previously accepted names now have a microorganisms ID and - if available - an LPSN, GBIF and SNOMED CT identifier.
* The `mo_matching_score()` now count deletions and substitutions as 2 instead of 1, which impacts the outcome of `as.mo()` and any `mo_*()` function * The MO matching score algorithm (`mo_matching_score()`) now counts deletions and substitutions as 2 instead of 1, which impacts the outcome of `as.mo()` and any `mo_*()` function
* Argument `combine_IR` has been removed from this package (affecting all `count_df()`, `proportion_df()` and `rsi_all()`), since it was replaced with `combine_SI` three years ago
### New ### New
* EUCAST 2022 and CLSI 2022 guidelines have been added for `as.rsi()`. EUCAST 2022 is now the new default guideline for all MIC and disks diffusion interpretations. * EUCAST 2022 and CLSI 2022 guidelines have been added for `as.rsi()`. EUCAST 2022 is now the new default guideline for all MIC and disks diffusion interpretations.
@ -23,8 +24,10 @@ This version will eventually become v2.0! We're happy to reach a new major miles
* Function `add_custom_antimicrobials()` to add custom antimicrobial codes and names to the `AMR` package * Function `add_custom_antimicrobials()` to add custom antimicrobial codes and names to the `AMR` package
* Support for `data.frame`-enhancing R packages, more specifically: `data.table::data.table`, `janitor::tabyl`, `tibble::tibble`, and `tsibble::tsibble`. AMR package functions that have a data set as output (such as `rsi_df()` and `bug_drug_combinations()`), will now return the same data type as the input. * Support for `data.frame`-enhancing R packages, more specifically: `data.table::data.table`, `janitor::tabyl`, `tibble::tibble`, and `tsibble::tsibble`. AMR package functions that have a data set as output (such as `rsi_df()` and `bug_drug_combinations()`), will now return the same data type as the input.
* All data sets in this package are now exported as `tibble`, instead of base R `data.frame`s. Older R versions are still supported. * All data sets in this package are now exported as `tibble`, instead of base R `data.frame`s. Older R versions are still supported.
* Support for the following languages: Chinese, Greek, Japanese, Polish, Turkish and Ukrainian. We are very grateful for the valuable input by our colleagues from other countries. The `AMR` package is now available in 16 languages. * Support for the following languages: Chinese, Greek, Japanese, Polish, Turkish and Ukrainian. We are very grateful for the valuable input by our colleagues from other countries. The `AMR` package is now available in 16 languages. The automatic language determination will give a note at start-up on systems in supported languages.
* Our data sets are now also continually exported to Apache Feather and Apache Parquet formats. You can find more info [in this article on our website](https://msberends.github.io/AMR/articles/datasets.html). * Our data sets are now also continually exported to Apache Feather and Apache Parquet formats. You can find more info [in this article on our website](https://msberends.github.io/AMR/articles/datasets.html).
* Added confidence intervals in AMR calculation. This is now included in `rsi_df()` and `proportion_df()` and manually available as `rsi_confidence_interval()`
* Support for using antibiotic selectors in `dplyr::vars()`, such as in: `... %>% summarise_at(vars(aminoglycosides()), resistance)`
### Changed ### Changed
* Fix for using `as.rsi()` on certain EUCAST breakpoints for MIC values * Fix for using `as.rsi()` on certain EUCAST breakpoints for MIC values
@ -38,7 +41,6 @@ This version will eventually become v2.0! We're happy to reach a new major miles
* Changed value in column `prevalence` of the `microorganisms` data set from 3 to 2 for these genera: *Acholeplasma*, *Alistipes*, *Alloprevotella*, *Bergeyella*, *Borrelia*, *Brachyspira*, *Butyricimonas*, *Cetobacterium*, *Chlamydia*, *Chlamydophila*, *Deinococcus*, *Dysgonomonas*, *Elizabethkingia*, *Empedobacter*, *Haloarcula*, *Halobacterium*, *Halococcus*, *Myroides*, *Odoribacter*, *Ornithobacterium*, *Parabacteroides*, *Pedobacter*, *Phocaeicola*, *Porphyromonas*, *Riemerella*, *Sphingobacterium*, *Streptobacillus*, *Tenacibaculum*, *Terrimonas*, *Victivallis*, *Wautersiella*, *Weeksella* * Changed value in column `prevalence` of the `microorganisms` data set from 3 to 2 for these genera: *Acholeplasma*, *Alistipes*, *Alloprevotella*, *Bergeyella*, *Borrelia*, *Brachyspira*, *Butyricimonas*, *Cetobacterium*, *Chlamydia*, *Chlamydophila*, *Deinococcus*, *Dysgonomonas*, *Elizabethkingia*, *Empedobacter*, *Haloarcula*, *Halobacterium*, *Halococcus*, *Myroides*, *Odoribacter*, *Ornithobacterium*, *Parabacteroides*, *Pedobacter*, *Phocaeicola*, *Porphyromonas*, *Riemerella*, *Sphingobacterium*, *Streptobacillus*, *Tenacibaculum*, *Terrimonas*, *Victivallis*, *Wautersiella*, *Weeksella*
* Fix for using the form `df[carbapenems() == "R", ]` when using the latest `vctrs` package * Fix for using the form `df[carbapenems() == "R", ]` when using the latest `vctrs` package
* Fix for using `info = FALSE` in `mdro()` * Fix for using `info = FALSE` in `mdro()`
* Automatic language determination will give a note once a session
* For all interpretation guidelines using `as.rsi()` on amoxicillin, the rules for ampicillin will be used if amoxicillin rules are not available * For all interpretation guidelines using `as.rsi()` on amoxicillin, the rules for ampicillin will be used if amoxicillin rules are not available
* Fix for using `ab_atc()` on non-existing ATC codes * Fix for using `ab_atc()` on non-existing ATC codes
* Black and white message texts are now reversed in colour if using an RStudio dark theme * Black and white message texts are now reversed in colour if using an RStudio dark theme

View File

@ -473,8 +473,9 @@ word_wrap <- function(...,
# clean introduced whitespace between fullstops # clean introduced whitespace between fullstops
msg <- gsub("[.] +[.]", "..", msg) msg <- gsub("[.] +[.]", "..", msg)
# remove extra space that was introduced (case: "Smith et al., 2022") # remove extra space that was introduced (e.g. "Smith et al., 2022")
msg <- gsub(". ,", ".,", msg, fixed = TRUE) msg <- gsub(". ,", ".,", msg, fixed = TRUE)
msg <- gsub("[ ,", "[,", msg, fixed = TRUE)
msg msg
} }
@ -854,7 +855,8 @@ get_current_data <- function(arg_name, call) {
} }
# try dplyr::cur_data_all() first to support dplyr groups # try dplyr::cur_data_all() first to support dplyr groups
# only useful for e.g. dplyr::filter(), dplyr::mutate() and dplyr::summarise() # only useful for e.g. dplyr::filter(), dplyr::mutate() and dplyr::summarise()
# not useful (throws error) with e.g. dplyr::select() - but that will be caught later in this function # not useful (throws error) with e.g. dplyr::select(), dplyr::across(), or dplyr::vars(),
# but that will be caught later on in this function
cur_data_all <- import_fn("cur_data_all", "dplyr", error_on_fail = FALSE) cur_data_all <- import_fn("cur_data_all", "dplyr", error_on_fail = FALSE)
if (!is.null(cur_data_all)) { if (!is.null(cur_data_all)) {
out <- tryCatch(cur_data_all(), error = function(e) NULL) out <- tryCatch(cur_data_all(), error = function(e) NULL)
@ -879,6 +881,11 @@ get_current_data <- function(arg_name, call) {
# an element `x` will be in the environment for only cols, e.g. `example_isolates[, carbapenems()]` # an element `x` will be in the environment for only cols, e.g. `example_isolates[, carbapenems()]`
return(env$x) return(env$x)
} }
} else if (!is.null(names(env)) && all(c(".tbl", ".vars", ".env") %in% names(env), na.rm = TRUE) && valid_df(env$`.tbl`)) {
# an element `.tbl` will be in the environment when using `dplyr::vars()`
# (e.g. in `dplyr::summarise_at()` or `dplyr::mutate_at()`)
return(env$`.tbl`)
} }
} }

View File

@ -31,7 +31,7 @@
#' #'
#' Determine antimicrobial resistance (AMR) of all bug-drug combinations in your data set where at least 30 (default) isolates are available per species. Use [format()] on the result to prettify it to a publishable/printable format, see *Examples*. #' Determine antimicrobial resistance (AMR) of all bug-drug combinations in your data set where at least 30 (default) isolates are available per species. Use [format()] on the result to prettify it to a publishable/printable format, see *Examples*.
#' @inheritParams eucast_rules #' @inheritParams eucast_rules
#' @param combine_IR a [logical] to indicate whether values R and I should be summed #' @param combine_SI a [logical] to indicate whether values S and I should be summed, so resistance will be based on only R, defaults to `TRUE`
#' @param add_ab_group a [logical] to indicate where the group of the antimicrobials must be included as a first column #' @param add_ab_group a [logical] to indicate where the group of the antimicrobials must be included as a first column
#' @param remove_intrinsic_resistant [logical] to indicate that rows and columns with 100% resistance for all tested antimicrobials must be removed from the table #' @param remove_intrinsic_resistant [logical] to indicate that rows and columns with 100% resistance for all tested antimicrobials must be removed from the table
#' @param FUN the function to call on the `mo` column to transform the microorganism codes, defaults to [mo_shortname()] #' @param FUN the function to call on the `mo` column to transform the microorganism codes, defaults to [mo_shortname()]
@ -39,11 +39,11 @@
#' @param ... arguments passed on to `FUN` #' @param ... arguments passed on to `FUN`
#' @inheritParams rsi_df #' @inheritParams rsi_df
#' @inheritParams base::formatC #' @inheritParams base::formatC
#' @details The function [format()] calculates the resistance per bug-drug combination. Use `combine_IR = FALSE` (default) to test R vs. S+I and `combine_IR = TRUE` to test R+I vs. S. #' @details The function [format()] calculates the resistance per bug-drug combination. Use `combine_SI = TRUE` (default) to test R vs. S+I and `combine_SI = FALSE` to test R+I vs. S.
#' @export #' @export
#' @rdname bug_drug_combinations #' @rdname bug_drug_combinations
#' @return The function [bug_drug_combinations()] returns a [data.frame] with columns "mo", "ab", "S", "I", "R" and "total". #' @return The function [bug_drug_combinations()] returns a [data.frame] with columns "mo", "ab", "S", "I", "R" and "total".
#' @source \strong{M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 4th Edition}, 2014, *Clinical and Laboratory Standards Institute (CLSI)*. <https://clsi.org/standards/products/microbiology/documents/m39/>. #' @source \strong{M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 5th Edition}, 2022, *Clinical and Laboratory Standards Institute (CLSI)*. <https://clsi.org/standards/products/microbiology/documents/m39/>.
#' @examples #' @examples
#' \donttest{ #' \donttest{
#' x <- bug_drug_combinations(example_isolates) #' x <- bug_drug_combinations(example_isolates)
@ -174,7 +174,6 @@ format.bug_drug_combinations <- function(x,
language = get_AMR_locale(), language = get_AMR_locale(),
minimum = 30, minimum = 30,
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE,
add_ab_group = TRUE, add_ab_group = TRUE,
remove_intrinsic_resistant = FALSE, remove_intrinsic_resistant = FALSE,
decimal.mark = getOption("OutDec"), decimal.mark = getOption("OutDec"),
@ -185,7 +184,6 @@ format.bug_drug_combinations <- function(x,
language <- validate_language(language) language <- validate_language(language)
meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_positive = TRUE, is_finite = TRUE) meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_positive = TRUE, is_finite = TRUE)
meet_criteria(combine_SI, allow_class = "logical", has_length = 1) meet_criteria(combine_SI, allow_class = "logical", has_length = 1)
meet_criteria(combine_IR, allow_class = "logical", has_length = 1)
meet_criteria(add_ab_group, allow_class = "logical", has_length = 1) meet_criteria(add_ab_group, allow_class = "logical", has_length = 1)
meet_criteria(remove_intrinsic_resistant, allow_class = "logical", has_length = 1) meet_criteria(remove_intrinsic_resistant, allow_class = "logical", has_length = 1)
meet_criteria(decimal.mark, allow_class = "character", has_length = 1) meet_criteria(decimal.mark, allow_class = "character", has_length = 1)
@ -218,7 +216,7 @@ format.bug_drug_combinations <- function(x,
if (remove_intrinsic_resistant == TRUE) { if (remove_intrinsic_resistant == TRUE) {
x <- subset(x, R != total) x <- subset(x, R != total)
} }
if (combine_SI == TRUE || combine_IR == FALSE) { if (combine_SI == TRUE) {
x$isolates <- x$R x$isolates <- x$R
} else { } else {
x$isolates <- x$R + x$I x$isolates <- x$R + x$I

View File

@ -126,7 +126,7 @@ count_resistant <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -139,7 +139,7 @@ count_susceptible <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -152,7 +152,7 @@ count_R <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -168,7 +168,7 @@ count_IR <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -181,7 +181,7 @@ count_I <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -194,7 +194,7 @@ count_SI <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -210,7 +210,7 @@ count_S <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -223,7 +223,7 @@ count_all <- function(..., only_all_tested = FALSE) {
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = TRUE only_count = TRUE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -236,8 +236,7 @@ n_rsi <- count_all
count_df <- function(data, count_df <- function(data,
translate_ab = "name", translate_ab = "name",
language = get_AMR_locale(), language = get_AMR_locale(),
combine_SI = TRUE, combine_SI = TRUE) {
combine_IR = FALSE) {
tryCatch( tryCatch(
rsi_calc_df( rsi_calc_df(
type = "count", type = "count",
@ -245,9 +244,8 @@ count_df <- function(data,
translate_ab = translate_ab, translate_ab = translate_ab,
language = language, language = language,
combine_SI = combine_SI, combine_SI = combine_SI,
combine_IR = combine_IR, confidence_level = 0.95 # doesn't matter, will be removed
combine_SI_missing = missing(combine_SI)
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc_df(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }

View File

@ -126,7 +126,7 @@
#' @return A [logical] vector #' @return A [logical] vector
#' @source Methodology of this function is strictly based on: #' @source Methodology of this function is strictly based on:
#' #'
#' - **M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 4th Edition**, 2014, *Clinical and Laboratory Standards Institute (CLSI)*. <https://clsi.org/standards/products/microbiology/documents/m39/>. #' - **M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 5th Edition**, 2022, *Clinical and Laboratory Standards Institute (CLSI)*. <https://clsi.org/standards/products/microbiology/documents/m39/>.
#' #'
#' - Hindler JF and Stelling J (2007). **Analysis and Presentation of Cumulative Antibiograms: A New Consensus Guideline from the Clinical and Laboratory Standards Institute.** Clinical Infectious Diseases, 44(6), 867-873. \doi{10.1086/511864} #' - Hindler JF and Stelling J (2007). **Analysis and Presentation of Cumulative Antibiograms: A New Consensus Guideline from the Clinical and Laboratory Standards Institute.** Clinical Infectious Diseases, 44(6), 867-873. \doi{10.1086/511864}
#' @examples #' @examples

View File

@ -183,7 +183,6 @@ ggplot_rsi <- function(data,
limits = NULL, limits = NULL,
translate_ab = "name", translate_ab = "name",
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE,
minimum = 30, minimum = 30,
language = get_AMR_locale(), language = get_AMR_locale(),
nrow = NULL, nrow = NULL,
@ -213,7 +212,6 @@ ggplot_rsi <- function(data,
meet_criteria(limits, allow_class = c("numeric", "integer"), has_length = 2, allow_NULL = TRUE, allow_NA = TRUE) meet_criteria(limits, allow_class = c("numeric", "integer"), has_length = 2, allow_NULL = TRUE, allow_NA = TRUE)
meet_criteria(translate_ab, allow_class = c("character", "logical"), has_length = 1, allow_NA = TRUE) meet_criteria(translate_ab, allow_class = c("character", "logical"), has_length = 1, allow_NA = TRUE)
meet_criteria(combine_SI, allow_class = "logical", has_length = 1) meet_criteria(combine_SI, allow_class = "logical", has_length = 1)
meet_criteria(combine_IR, allow_class = "logical", has_length = 1)
meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE) meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE)
language <- validate_language(language) language <- validate_language(language)
meet_criteria(nrow, allow_class = c("numeric", "integer"), has_length = 1, allow_NULL = TRUE, is_positive = TRUE, is_finite = TRUE) meet_criteria(nrow, allow_class = c("numeric", "integer"), has_length = 1, allow_NULL = TRUE, is_positive = TRUE, is_finite = TRUE)
@ -254,7 +252,7 @@ ggplot_rsi <- function(data,
geom_rsi( geom_rsi(
position = position, x = x, fill = fill, translate_ab = translate_ab, position = position, x = x, fill = fill, translate_ab = translate_ab,
minimum = minimum, language = language, minimum = minimum, language = language,
combine_SI = combine_SI, combine_IR = combine_IR, ... combine_SI = combine_SI, ...
) + ) +
theme_rsi() theme_rsi()
@ -275,7 +273,6 @@ ggplot_rsi <- function(data,
minimum = minimum, minimum = minimum,
language = language, language = language,
combine_SI = combine_SI, combine_SI = combine_SI,
combine_IR = combine_IR,
datalabels.size = datalabels.size, datalabels.size = datalabels.size,
datalabels.colour = datalabels.colour datalabels.colour = datalabels.colour
) )
@ -305,7 +302,6 @@ geom_rsi <- function(position = NULL,
minimum = 30, minimum = 30,
language = get_AMR_locale(), language = get_AMR_locale(),
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE,
...) { ...) {
x <- x[1] x <- x[1]
stop_ifnot_installed("ggplot2") stop_ifnot_installed("ggplot2")
@ -317,7 +313,6 @@ geom_rsi <- function(position = NULL,
meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE) meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE)
language <- validate_language(language) language <- validate_language(language)
meet_criteria(combine_SI, allow_class = "logical", has_length = 1) meet_criteria(combine_SI, allow_class = "logical", has_length = 1)
meet_criteria(combine_IR, allow_class = "logical", has_length = 1)
y <- "value" y <- "value"
if (missing(position) || is.null(position)) { if (missing(position) || is.null(position)) {
@ -350,8 +345,7 @@ geom_rsi <- function(position = NULL,
translate_ab = translate_ab, translate_ab = translate_ab,
language = language, language = language,
minimum = minimum, minimum = minimum,
combine_SI = combine_SI, combine_SI = combine_SI
combine_IR = combine_IR
) )
}, },
mapping = ggplot2::aes_string(x = x, y = y, fill = fill), mapping = ggplot2::aes_string(x = x, y = y, fill = fill),
@ -496,7 +490,6 @@ labels_rsi_count <- function(position = NULL,
minimum = 30, minimum = 30,
language = get_AMR_locale(), language = get_AMR_locale(),
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE,
datalabels.size = 3, datalabels.size = 3,
datalabels.colour = "grey15") { datalabels.colour = "grey15") {
stop_ifnot_installed("ggplot2") stop_ifnot_installed("ggplot2")
@ -506,7 +499,6 @@ labels_rsi_count <- function(position = NULL,
meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE) meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE)
language <- validate_language(language) language <- validate_language(language)
meet_criteria(combine_SI, allow_class = "logical", has_length = 1) meet_criteria(combine_SI, allow_class = "logical", has_length = 1)
meet_criteria(combine_IR, allow_class = "logical", has_length = 1)
meet_criteria(datalabels.size, allow_class = c("numeric", "integer"), has_length = 1, is_positive = TRUE, is_finite = TRUE) meet_criteria(datalabels.size, allow_class = c("numeric", "integer"), has_length = 1, is_positive = TRUE, is_finite = TRUE)
meet_criteria(datalabels.colour, allow_class = "character", has_length = 1) meet_criteria(datalabels.colour, allow_class = "character", has_length = 1)
@ -533,7 +525,6 @@ labels_rsi_count <- function(position = NULL,
data = x, data = x,
translate_ab = translate_ab, translate_ab = translate_ab,
combine_SI = combine_SI, combine_SI = combine_SI,
combine_IR = combine_IR,
minimum = minimum, minimum = minimum,
language = language language = language
) )

View File

@ -39,12 +39,16 @@
#' @param data a [data.frame] containing columns with class [`rsi`] (see [as.rsi()]) #' @param data a [data.frame] containing columns with class [`rsi`] (see [as.rsi()])
#' @param translate_ab a column name of the [antibiotics] data set to translate the antibiotic abbreviations to, using [ab_property()] #' @param translate_ab a column name of the [antibiotics] data set to translate the antibiotic abbreviations to, using [ab_property()]
#' @inheritParams ab_property #' @inheritParams ab_property
#' @param combine_SI a [logical] to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant). This used to be the argument `combine_IR`, but this now follows the redefinition by EUCAST about the interpretation of I (increased exposure) in 2019, see section 'Interpretation of S, I and R' below. Default is `TRUE`. #' @param combine_SI a [logical] to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant), defaults to `TRUE`
#' @param combine_IR a [logical] to indicate whether all values of I and R must be merged into one, so the output only consists of S vs. I+R (susceptible vs. non-susceptible). This is outdated, see argument `combine_SI`. #' @param ab_result antibiotic results to test against, must be one of more values of "R", "S", "I"
#' @param confidence_level the confidence level for the returned confidence interval. For the calculation, the number of S or SI isolates, and R isolates are compared with the total number of available isolates with R, S, or I by using [binom.test()], i.e., the Clopper-Pearson method.
#' @param side the side of the confidence interval to return. Defaults to `"both"` for a length 2 vector, but can also be (abbreviated as) `"min"`/`"left"`/`"lower"`/`"less"` or `"max"`/`"right"`/`"higher"`/`"greater"`.
#' @inheritSection as.rsi Interpretation of R and S/I #' @inheritSection as.rsi Interpretation of R and S/I
#' @details #' @details
#' The function [resistance()] is equal to the function [proportion_R()]. The function [susceptibility()] is equal to the function [proportion_SI()]. #' The function [resistance()] is equal to the function [proportion_R()]. The function [susceptibility()] is equal to the function [proportion_SI()].
#' #'
#' Use [rsi_confidence_interval()] to calculate the confidence interval, which relies on [binom.test()], i.e., the Clopper-Pearson method. This function returns a vector of length 2 at default for antimicrobial *resistance*. Change the `side` argument to "left"/"min" or "right"/"max" to return a single value, and change the `ab_result` argument to e.g. `c("S", "I")` to test for antimicrobial *susceptibility*, see Examples.
#'
#' **Remember that you should filter your data to let it contain only first isolates!** This is needed to exclude duplicates and to reduce selection bias. Use [first_isolate()] to determine them in your data set. #' **Remember that you should filter your data to let it contain only first isolates!** This is needed to exclude duplicates and to reduce selection bias. Use [first_isolate()] to determine them in your data set.
#' #'
#' These functions are not meant to count isolates, but to calculate the proportion of resistance/susceptibility. Use the [`count()`][AMR::count()] functions to count isolates. The function [susceptibility()] is essentially equal to `count_susceptible() / count_all()`. *Low counts can influence the outcome - the `proportion` functions may camouflage this, since they only return the proportion (albeit being dependent on the `minimum` argument).* #' These functions are not meant to count isolates, but to calculate the proportion of resistance/susceptibility. Use the [`count()`][AMR::count()] functions to count isolates. The function [susceptibility()] is essentially equal to `count_susceptible() / count_all()`. *Low counts can influence the outcome - the `proportion` functions may camouflage this, since they only return the proportion (albeit being dependent on the `minimum` argument).*
@ -84,7 +88,7 @@
#' ``` #' ```
#' #'
#' Using `only_all_tested` has no impact when only using one antibiotic as input. #' Using `only_all_tested` has no impact when only using one antibiotic as input.
#' @source **M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 4th Edition**, 2014, *Clinical and Laboratory Standards Institute (CLSI)*. <https://clsi.org/standards/products/microbiology/documents/m39/>. #' @source **M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 5th Edition**, 2022, *Clinical and Laboratory Standards Institute (CLSI)*. <https://clsi.org/standards/products/microbiology/documents/m39/>.
#' @seealso [AMR::count()] to count resistant and susceptible isolates. #' @seealso [AMR::count()] to count resistant and susceptible isolates.
#' @return A [double] or, when `as_percent = TRUE`, a [character]. #' @return A [double] or, when `as_percent = TRUE`, a [character].
#' @rdname proportion #' @rdname proportion
@ -96,8 +100,16 @@
#' # run ?example_isolates for more info. #' # run ?example_isolates for more info.
#' #'
#' # base R ------------------------------------------------------------ #' # base R ------------------------------------------------------------
#' resistance(example_isolates$AMX) # determines %R #' # determines %R
#' susceptibility(example_isolates$AMX) # determines %S+I #' resistance(example_isolates$AMX)
#' rsi_confidence_interval(example_isolates$AMX)
#' rsi_confidence_interval(example_isolates$AMX,
#' confidence_level = 0.975)
#'
#' # determines %S+I:
#' susceptibility(example_isolates$AMX)
#' rsi_confidence_interval(example_isolates$AMX,
#' ab_result = c("S", "I"))
#' #'
#' # be more specific #' # be more specific
#' proportion_S(example_isolates$AMX) #' proportion_S(example_isolates$AMX)
@ -109,6 +121,7 @@
#' # dplyr ------------------------------------------------------------- #' # dplyr -------------------------------------------------------------
#' \donttest{ #' \donttest{
#' if (require("dplyr")) { #' if (require("dplyr")) {
#'
#' example_isolates %>% #' example_isolates %>%
#' group_by(ward) %>% #' group_by(ward) %>%
#' summarise( #' summarise(
@ -116,6 +129,20 @@
#' n = n_rsi(CIP) #' n = n_rsi(CIP)
#' ) # n_rsi works like n_distinct in dplyr, see ?n_rsi #' ) # n_rsi works like n_distinct in dplyr, see ?n_rsi
#' #'
#' }
#' if (require("dplyr")) {
#'
#' example_isolates %>%
#' group_by(ward) %>%
#' summarise(
#' cipro_R = resistance(CIP),
#' ci_min = rsi_confidence_interval(CIP, side = "min"),
#' ci_max = rsi_confidence_interval(CIP, side = "max"),
#' )
#'
#' }
#' if (require("dplyr")) {
#'
#' example_isolates %>% #' example_isolates %>%
#' group_by(ward) %>% #' group_by(ward) %>%
#' summarise( #' summarise(
@ -190,7 +217,7 @@ resistance <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -208,10 +235,67 @@ susceptibility <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
#' @rdname proportion
#' @export
rsi_confidence_interval <- function(...,
ab_result = "R",
minimum = 30,
as_percent = FALSE,
only_all_tested = FALSE,
confidence_level = 0.95,
side = "both") {
meet_criteria(ab_result, allow_class = c("character", "rsi"), has_length = c(1, 2, 3), is_in = c("R", "S", "I"))
meet_criteria(confidence_level, allow_class = "numeric", is_positive = TRUE, has_length = 1)
meet_criteria(side, allow_class = "character", has_length = 1, is_in = c("both", "b", "left", "l", "lower", "lowest", "less", "min", "right", "r", "higher", "highest", "greater", "g", "max"))
x <- tryCatch(
rsi_calc(...,
ab_result = ab_result,
only_all_tested = only_all_tested,
only_count = TRUE
),
error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
)
n <- tryCatch(
rsi_calc(...,
ab_result = c("S", "I", "R"),
only_all_tested = only_all_tested,
only_count = TRUE
),
error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
)
if (n < minimum) {
warning_("Introducing NA: ",
ifelse(n == 0, "no", paste("only", n)),
" results available for `rsi_confidence_interval()` (`minimum` = ", minimum, ").",
call = FALSE
)
if (as_percent == TRUE) {
return(NA_character_)
} else {
return(NA_real_)
}
}
out <- stats::binom.test(x = x, n = n, conf.level = confidence_level)$conf.int
out <- set_clean_class(out, "double")
if (side %in% c("left", "l", "lower", "lowest", "less", "min")) {
out <- out[1]
} else if (side %in% c("right", "r", "higher", "highest", "greater", "g", "max")) {
out <- out[2]
}
if (as_percent == TRUE) {
percentage(out, digits = 1)
} else {
out
}
}
#' @rdname proportion #' @rdname proportion
#' @export #' @export
proportion_R <- function(..., proportion_R <- function(...,
@ -226,7 +310,7 @@ proportion_R <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -244,7 +328,7 @@ proportion_IR <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -262,7 +346,7 @@ proportion_I <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -280,7 +364,7 @@ proportion_SI <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -298,7 +382,7 @@ proportion_S <- function(...,
only_all_tested = only_all_tested, only_all_tested = only_all_tested,
only_count = FALSE only_count = FALSE
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }
@ -310,7 +394,7 @@ proportion_df <- function(data,
minimum = 30, minimum = 30,
as_percent = FALSE, as_percent = FALSE,
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE) { confidence_level = 0.95) {
tryCatch( tryCatch(
rsi_calc_df( rsi_calc_df(
type = "proportion", type = "proportion",
@ -320,9 +404,8 @@ proportion_df <- function(data,
minimum = minimum, minimum = minimum,
as_percent = as_percent, as_percent = as_percent,
combine_SI = combine_SI, combine_SI = combine_SI,
combine_IR = combine_IR, confidence_level = confidence_level
combine_SI_missing = missing(combine_SI)
), ),
error = function(e) stop_(e$message, call = -5) error = function(e) stop_(gsub("in rsi_calc_df(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }

View File

@ -40,11 +40,11 @@ rsi_calc <- function(...,
as_percent = FALSE, as_percent = FALSE,
only_all_tested = FALSE, only_all_tested = FALSE,
only_count = FALSE) { only_count = FALSE) {
meet_criteria(ab_result, allow_class = c("character", "numeric", "integer"), has_length = c(1, 2, 3), .call_depth = 1) meet_criteria(ab_result, allow_class = c("character", "numeric", "integer"), has_length = c(1, 2, 3))
meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE, .call_depth = 1) meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE)
meet_criteria(as_percent, allow_class = "logical", has_length = 1, .call_depth = 1) meet_criteria(as_percent, allow_class = "logical", has_length = 1)
meet_criteria(only_all_tested, allow_class = "logical", has_length = 1, .call_depth = 1) meet_criteria(only_all_tested, allow_class = "logical", has_length = 1)
meet_criteria(only_count, allow_class = "logical", has_length = 1, .call_depth = 1) meet_criteria(only_count, allow_class = "logical", has_length = 1)
data_vars <- dots2vars(...) data_vars <- dots2vars(...)
@ -221,21 +221,15 @@ rsi_calc_df <- function(type, # "proportion", "count" or "both"
minimum = 30, minimum = 30,
as_percent = FALSE, as_percent = FALSE,
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE, confidence_level = 0.95) {
combine_SI_missing = FALSE) { meet_criteria(type, is_in = c("proportion", "count", "both"), has_length = 1)
meet_criteria(type, is_in = c("proportion", "count", "both"), has_length = 1, .call_depth = 1) meet_criteria(data, allow_class = "data.frame", contains_column_class = "rsi")
meet_criteria(data, allow_class = "data.frame", contains_column_class = "rsi", .call_depth = 1) meet_criteria(translate_ab, allow_class = c("character", "logical"), has_length = 1, allow_NA = TRUE)
meet_criteria(translate_ab, allow_class = c("character", "logical"), has_length = 1, allow_NA = TRUE, .call_depth = 1) meet_criteria(language, has_length = 1, is_in = c(LANGUAGES_SUPPORTED, ""), allow_NULL = TRUE, allow_NA = TRUE)
meet_criteria(language, has_length = 1, is_in = c(LANGUAGES_SUPPORTED, ""), allow_NULL = TRUE, allow_NA = TRUE, .call_depth = 1) meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE)
meet_criteria(minimum, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE, .call_depth = 1) meet_criteria(as_percent, allow_class = "logical", has_length = 1)
meet_criteria(as_percent, allow_class = "logical", has_length = 1, .call_depth = 1) meet_criteria(combine_SI, allow_class = "logical", has_length = 1)
meet_criteria(combine_SI, allow_class = "logical", has_length = 1, .call_depth = 1) meet_criteria(confidence_level, allow_class = "numeric", has_length = 1)
meet_criteria(combine_SI_missing, allow_class = "logical", has_length = 1, .call_depth = 1)
if (isTRUE(combine_IR) && isTRUE(combine_SI_missing)) {
combine_SI <- FALSE
}
stop_if(isTRUE(combine_SI) & isTRUE(combine_IR), "either `combine_SI` or `combine_IR` can be TRUE, not both", call = -2)
translate_ab <- get_translate_ab(translate_ab) translate_ab <- get_translate_ab(translate_ab)
@ -251,15 +245,11 @@ rsi_calc_df <- function(type, # "proportion", "count" or "both"
} }
data <- as.data.frame(data, stringsAsFactors = FALSE) data <- as.data.frame(data, stringsAsFactors = FALSE)
if (isTRUE(combine_SI) || isTRUE(combine_IR)) { if (isTRUE(combine_SI)) {
for (i in seq_len(ncol(data))) { for (i in seq_len(ncol(data))) {
if (is.rsi(data[, i, drop = TRUE])) { if (is.rsi(data[, i, drop = TRUE])) {
data[, i] <- as.character(data[, i, drop = TRUE]) data[, i] <- as.character(data[, i, drop = TRUE])
if (isTRUE(combine_SI)) {
data[, i] <- gsub("(I|S)", "SI", data[, i, drop = TRUE]) data[, i] <- gsub("(I|S)", "SI", data[, i, drop = TRUE])
} else if (isTRUE(combine_IR)) {
data[, i] <- gsub("(I|R)", "IR", data[, i, drop = TRUE])
}
} }
} }
} }
@ -269,6 +259,8 @@ rsi_calc_df <- function(type, # "proportion", "count" or "both"
antibiotic = character(0), antibiotic = character(0),
interpretation = character(0), interpretation = character(0),
value = double(0), value = double(0),
ci_min = double(0),
ci_max = double(0),
isolates = integer(0), isolates = integer(0),
stringsAsFactors = FALSE stringsAsFactors = FALSE
) )
@ -281,19 +273,27 @@ rsi_calc_df <- function(type, # "proportion", "count" or "both"
values <- .data[, i, drop = TRUE] values <- .data[, i, drop = TRUE]
if (isTRUE(combine_SI)) { if (isTRUE(combine_SI)) {
values <- factor(values, levels = c("SI", "R"), ordered = TRUE) values <- factor(values, levels = c("SI", "R"), ordered = TRUE)
} else if (isTRUE(combine_IR)) {
values <- factor(values, levels = c("S", "IR"), ordered = TRUE)
} else { } else {
values <- factor(values, levels = c("S", "I", "R"), ordered = TRUE) values <- factor(values, levels = c("S", "I", "R"), ordered = TRUE)
} }
col_results <- as.data.frame(as.matrix(table(values)), stringsAsFactors = FALSE) col_results <- as.data.frame(as.matrix(table(values)), stringsAsFactors = FALSE)
col_results$interpretation <- rownames(col_results) col_results$interpretation <- rownames(col_results)
col_results$isolates <- col_results[, 1, drop = TRUE] col_results$isolates <- col_results[, 1, drop = TRUE]
ddf <<- col_results
if (NROW(col_results) > 0 && sum(col_results$isolates, na.rm = TRUE) > 0) { if (NROW(col_results) > 0 && sum(col_results$isolates, na.rm = TRUE) > 0) {
if (sum(col_results$isolates, na.rm = TRUE) >= minimum) { if (sum(col_results$isolates, na.rm = TRUE) >= minimum) {
col_results$value <- col_results$isolates / sum(col_results$isolates, na.rm = TRUE) col_results$value <- col_results$isolates / sum(col_results$isolates, na.rm = TRUE)
ci <- lapply(col_results$isolates,
function(x) stats::binom.test(x = x,
n = sum(col_results$isolates, na.rm = TRUE),
conf.level = confidence_level)$conf.int)
col_results$ci_min <- vapply(FUN.VALUE = double(1), ci, `[`, 1)
col_results$ci_max <- vapply(FUN.VALUE = double(1), ci, `[`, 2)
} else { } else {
col_results$value <- rep(NA_real_, NROW(col_results)) col_results$value <- rep(NA_real_, NROW(col_results))
# confidence intervals also to NA
col_results$ci_min <- col_results$value
col_results$ci_max <- col_results$value
} }
out_new <- data.frame( out_new <- data.frame(
antibiotic = ifelse(isFALSE(translate_ab), antibiotic = ifelse(isFALSE(translate_ab),
@ -302,6 +302,8 @@ rsi_calc_df <- function(type, # "proportion", "count" or "both"
), ),
interpretation = col_results$interpretation, interpretation = col_results$interpretation,
value = col_results$value, value = col_results$value,
ci_min = col_results$ci_min,
ci_max = col_results$ci_max,
isolates = col_results$isolates, isolates = col_results$isolates,
stringsAsFactors = FALSE stringsAsFactors = FALSE
) )
@ -341,8 +343,6 @@ rsi_calc_df <- function(type, # "proportion", "count" or "both"
# apply factors for right sorting in interpretation # apply factors for right sorting in interpretation
if (isTRUE(combine_SI)) { if (isTRUE(combine_SI)) {
out$interpretation <- factor(out$interpretation, levels = c("SI", "R"), ordered = TRUE) out$interpretation <- factor(out$interpretation, levels = c("SI", "R"), ordered = TRUE)
} else if (isTRUE(combine_IR)) {
out$interpretation <- factor(out$interpretation, levels = c("S", "IR"), ordered = TRUE)
} else { } else {
# don't use as.rsi() here, as it would add the class 'rsi' and we would like # don't use as.rsi() here, as it would add the class 'rsi' and we would like
# the same data structure as output, regardless of input # the same data structure as output, regardless of input
@ -357,10 +357,13 @@ rsi_calc_df <- function(type, # "proportion", "count" or "both"
} }
if (type == "proportion") { if (type == "proportion") {
# remove number of isolates
out <- subset(out, select = -c(isolates)) out <- subset(out, select = -c(isolates))
} else if (type == "count") { } else if (type == "count") {
# set value to be number of isolates
out$value <- out$isolates out$value <- out$isolates
out <- subset(out, select = -c(isolates)) # remove redundant columns
out <- subset(out, select = -c(ci_min, ci_max, isolates))
} }
rownames(out) <- NULL rownames(out) <- NULL

View File

@ -35,7 +35,8 @@ rsi_df <- function(data,
minimum = 30, minimum = 30,
as_percent = FALSE, as_percent = FALSE,
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE) { confidence_level = 0.95) {
tryCatch(
rsi_calc_df( rsi_calc_df(
type = "both", type = "both",
data = data, data = data,
@ -44,7 +45,8 @@ rsi_df <- function(data,
minimum = minimum, minimum = minimum,
as_percent = as_percent, as_percent = as_percent,
combine_SI = combine_SI, combine_SI = combine_SI,
combine_IR = combine_IR, confidence_level = confidence_level
combine_SI_missing = missing(combine_SI) ),
error = function(e) stop_(gsub("in rsi_calc_df(): ", "", e$message, fixed = TRUE), call = -5)
) )
} }

View File

@ -31,7 +31,7 @@ b <- suppressWarnings(bug_drug_combinations(example_isolates))
expect_inherits(b, "bug_drug_combinations") expect_inherits(b, "bug_drug_combinations")
expect_stdout(suppressMessages(print(b))) expect_stdout(suppressMessages(print(b)))
expect_true(is.data.frame(format(b))) expect_true(is.data.frame(format(b)))
expect_true(is.data.frame(format(b, combine_IR = TRUE, add_ab_group = FALSE))) expect_true(is.data.frame(format(b, add_ab_group = FALSE)))
if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0")) { if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0")) {
expect_true(example_isolates %>% expect_true(example_isolates %>%
group_by(ward) %>% group_by(ward) %>%

View File

@ -94,13 +94,6 @@ if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0")) {
example_isolates$AMX %>% count_resistant() example_isolates$AMX %>% count_resistant()
) )
) )
expect_equal(
example_isolates %>% select(AMX) %>% count_df(combine_IR = TRUE) %>% pull(value),
c(
suppressWarnings(example_isolates$AMX %>% count_S()),
suppressWarnings(example_isolates$AMX %>% count_IR())
)
)
expect_equal( expect_equal(
example_isolates %>% select(AMX) %>% count_df(combine_SI = FALSE) %>% pull(value), example_isolates %>% select(AMX) %>% count_df(combine_SI = FALSE) %>% pull(value),
c( c(

View File

@ -32,6 +32,8 @@ expect_equal(proportion_SI(example_isolates$AMX), susceptibility(example_isolate
# AMX resistance in `example_isolates` # AMX resistance in `example_isolates`
expect_equal(proportion_R(example_isolates$AMX), 0.5955556, tolerance = 0.0001) expect_equal(proportion_R(example_isolates$AMX), 0.5955556, tolerance = 0.0001)
expect_equal(proportion_I(example_isolates$AMX), 0.002222222, tolerance = 0.0001) expect_equal(proportion_I(example_isolates$AMX), 0.002222222, tolerance = 0.0001)
expect_equal(rsi_confidence_interval(example_isolates$AMX)[1], 0.5688204, tolerance = 0.0001)
expect_equal(rsi_confidence_interval(example_isolates$AMX)[2], 0.6218738, tolerance = 0.0001)
expect_equal( expect_equal(
1 - proportion_R(example_isolates$AMX) - proportion_I(example_isolates$AMX), 1 - proportion_R(example_isolates$AMX) - proportion_I(example_isolates$AMX),
proportion_S(example_isolates$AMX) proportion_S(example_isolates$AMX)
@ -99,13 +101,6 @@ if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0")) {
example_isolates$AMX %>% proportion_R() example_isolates$AMX %>% proportion_R()
) )
) )
expect_equal(
example_isolates %>% select(AMX) %>% proportion_df(combine_IR = TRUE) %>% pull(value),
c(
example_isolates$AMX %>% proportion_S(),
example_isolates$AMX %>% proportion_IR()
)
)
expect_equal( expect_equal(
example_isolates %>% select(AMX) %>% proportion_df(combine_SI = FALSE) %>% pull(value), example_isolates %>% select(AMX) %>% proportion_df(combine_SI = FALSE) %>% pull(value),
c( c(
@ -114,6 +109,8 @@ if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0")) {
example_isolates$AMX %>% proportion_R() example_isolates$AMX %>% proportion_R()
) )
) )
expect_warning(example_isolates %>% group_by(ward) %>% summarise(across(KAN, rsi_confidence_interval)))
} }
expect_warning(proportion_R(as.character(example_isolates$AMC))) expect_warning(proportion_R(as.character(example_isolates$AMC)))

View File

@ -5,7 +5,7 @@
\alias{format.bug_drug_combinations} \alias{format.bug_drug_combinations}
\title{Determine Bug-Drug Combinations} \title{Determine Bug-Drug Combinations}
\source{ \source{
\strong{M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 4th Edition}, 2014, \emph{Clinical and Laboratory Standards Institute (CLSI)}. \url{https://clsi.org/standards/products/microbiology/documents/m39/}. \strong{M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 5th Edition}, 2022, \emph{Clinical and Laboratory Standards Institute (CLSI)}. \url{https://clsi.org/standards/products/microbiology/documents/m39/}.
} }
\usage{ \usage{
bug_drug_combinations(x, col_mo = NULL, FUN = mo_shortname, ...) bug_drug_combinations(x, col_mo = NULL, FUN = mo_shortname, ...)
@ -16,7 +16,6 @@ bug_drug_combinations(x, col_mo = NULL, FUN = mo_shortname, ...)
language = get_AMR_locale(), language = get_AMR_locale(),
minimum = 30, minimum = 30,
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE,
add_ab_group = TRUE, add_ab_group = TRUE,
remove_intrinsic_resistant = FALSE, remove_intrinsic_resistant = FALSE,
decimal.mark = getOption("OutDec"), decimal.mark = getOption("OutDec"),
@ -39,9 +38,7 @@ bug_drug_combinations(x, col_mo = NULL, FUN = mo_shortname, ...)
\item{minimum}{the minimum allowed number of available (tested) isolates. Any isolate count lower than \code{minimum} will return \code{NA} with a warning. The default number of \code{30} isolates is advised by the Clinical and Laboratory Standards Institute (CLSI) as best practice, see \emph{Source}.} \item{minimum}{the minimum allowed number of available (tested) isolates. Any isolate count lower than \code{minimum} will return \code{NA} with a warning. The default number of \code{30} isolates is advised by the Clinical and Laboratory Standards Institute (CLSI) as best practice, see \emph{Source}.}
\item{combine_SI}{a \link{logical} to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant). This used to be the argument \code{combine_IR}, but this now follows the redefinition by EUCAST about the interpretation of I (increased exposure) in 2019, see section 'Interpretation of S, I and R' below. Default is \code{TRUE}.} \item{combine_SI}{a \link{logical} to indicate whether values S and I should be summed, so resistance will be based on only R, defaults to \code{TRUE}}
\item{combine_IR}{a \link{logical} to indicate whether values R and I should be summed}
\item{add_ab_group}{a \link{logical} to indicate where the group of the antimicrobials must be included as a first column} \item{add_ab_group}{a \link{logical} to indicate where the group of the antimicrobials must be included as a first column}
@ -61,7 +58,7 @@ The function \code{\link[=bug_drug_combinations]{bug_drug_combinations()}} retur
Determine antimicrobial resistance (AMR) of all bug-drug combinations in your data set where at least 30 (default) isolates are available per species. Use \code{\link[=format]{format()}} on the result to prettify it to a publishable/printable format, see \emph{Examples}. Determine antimicrobial resistance (AMR) of all bug-drug combinations in your data set where at least 30 (default) isolates are available per species. Use \code{\link[=format]{format()}} on the result to prettify it to a publishable/printable format, see \emph{Examples}.
} }
\details{ \details{
The function \code{\link[=format]{format()}} calculates the resistance per bug-drug combination. Use \code{combine_IR = FALSE} (default) to test R vs. S+I and \code{combine_IR = TRUE} to test R+I vs. S. The function \code{\link[=format]{format()}} calculates the resistance per bug-drug combination. Use \code{combine_SI = TRUE} (default) to test R vs. S+I and \code{combine_SI = FALSE} to test R+I vs. S.
} }
\examples{ \examples{
\donttest{ \donttest{

View File

@ -36,8 +36,7 @@ count_df(
data, data,
translate_ab = "name", translate_ab = "name",
language = get_AMR_locale(), language = get_AMR_locale(),
combine_SI = TRUE, combine_SI = TRUE
combine_IR = FALSE
) )
} }
\arguments{ \arguments{
@ -51,9 +50,7 @@ count_df(
\item{language}{language of the returned text, defaults to system language (see \code{\link[=get_AMR_locale]{get_AMR_locale()}}) and can also be set with \code{getOption("AMR_locale")}. Use \code{language = NULL} or \code{language = ""} to prevent translation.} \item{language}{language of the returned text, defaults to system language (see \code{\link[=get_AMR_locale]{get_AMR_locale()}}) and can also be set with \code{getOption("AMR_locale")}. Use \code{language = NULL} or \code{language = ""} to prevent translation.}
\item{combine_SI}{a \link{logical} to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant). This used to be the argument \code{combine_IR}, but this now follows the redefinition by EUCAST about the interpretation of I (increased exposure) in 2019, see section 'Interpretation of S, I and R' below. Default is \code{TRUE}.} \item{combine_SI}{a \link{logical} to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant), defaults to \code{TRUE}}
\item{combine_IR}{a \link{logical} to indicate whether all values of I and R must be merged into one, so the output only consists of S vs. I+R (susceptible vs. non-susceptible). This is outdated, see argument \code{combine_SI}.}
} }
\value{ \value{
An \link{integer} An \link{integer}

View File

@ -7,7 +7,7 @@
\source{ \source{
Methodology of this function is strictly based on: Methodology of this function is strictly based on:
\itemize{ \itemize{
\item \strong{M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 4th Edition}, 2014, \emph{Clinical and Laboratory Standards Institute (CLSI)}. \url{https://clsi.org/standards/products/microbiology/documents/m39/}. \item \strong{M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 5th Edition}, 2022, \emph{Clinical and Laboratory Standards Institute (CLSI)}. \url{https://clsi.org/standards/products/microbiology/documents/m39/}.
\item Hindler JF and Stelling J (2007). \strong{Analysis and Presentation of Cumulative Antibiograms: A New Consensus Guideline from the Clinical and Laboratory Standards Institute.} Clinical Infectious Diseases, 44(6), 867-873. \doi{10.1086/511864} \item Hindler JF and Stelling J (2007). \strong{Analysis and Presentation of Cumulative Antibiograms: A New Consensus Guideline from the Clinical and Laboratory Standards Institute.} Clinical Infectious Diseases, 44(6), 867-873. \doi{10.1086/511864}
} }
} }

View File

@ -20,7 +20,6 @@ ggplot_rsi(
limits = NULL, limits = NULL,
translate_ab = "name", translate_ab = "name",
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE,
minimum = 30, minimum = 30,
language = get_AMR_locale(), language = get_AMR_locale(),
nrow = NULL, nrow = NULL,
@ -45,7 +44,6 @@ geom_rsi(
minimum = 30, minimum = 30,
language = get_AMR_locale(), language = get_AMR_locale(),
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE,
... ...
) )
@ -64,7 +62,6 @@ labels_rsi_count(
minimum = 30, minimum = 30,
language = get_AMR_locale(), language = get_AMR_locale(),
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE,
datalabels.size = 3, datalabels.size = 3,
datalabels.colour = "grey15" datalabels.colour = "grey15"
) )
@ -86,9 +83,7 @@ labels_rsi_count(
\item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}} \item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}}
\item{combine_SI}{a \link{logical} to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant). This used to be the argument \code{combine_IR}, but this now follows the redefinition by EUCAST about the interpretation of I (increased exposure) in 2019, see section 'Interpretation of S, I and R' below. Default is \code{TRUE}.} \item{combine_SI}{a \link{logical} to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant), defaults to \code{TRUE}}
\item{combine_IR}{a \link{logical} to indicate whether all values of I and R must be merged into one, so the output only consists of S vs. I+R (susceptible vs. non-susceptible). This is outdated, see argument \code{combine_SI}.}
\item{minimum}{the minimum allowed number of available (tested) isolates. Any isolate count lower than \code{minimum} will return \code{NA} with a warning. The default number of \code{30} isolates is advised by the Clinical and Laboratory Standards Institute (CLSI) as best practice, see \emph{Source}.} \item{minimum}{the minimum allowed number of available (tested) isolates. Any isolate count lower than \code{minimum} will return \code{NA} with a warning. The default number of \code{30} isolates is advised by the Clinical and Laboratory Standards Institute (CLSI) as best practice, see \emph{Source}.}

View File

@ -5,6 +5,7 @@
\alias{resistance} \alias{resistance}
\alias{portion} \alias{portion}
\alias{susceptibility} \alias{susceptibility}
\alias{rsi_confidence_interval}
\alias{proportion_R} \alias{proportion_R}
\alias{proportion_IR} \alias{proportion_IR}
\alias{proportion_I} \alias{proportion_I}
@ -14,13 +15,23 @@
\alias{rsi_df} \alias{rsi_df}
\title{Calculate Microbial Resistance} \title{Calculate Microbial Resistance}
\source{ \source{
\strong{M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 4th Edition}, 2014, \emph{Clinical and Laboratory Standards Institute (CLSI)}. \url{https://clsi.org/standards/products/microbiology/documents/m39/}. \strong{M39 Analysis and Presentation of Cumulative Antimicrobial Susceptibility Test Data, 5th Edition}, 2022, \emph{Clinical and Laboratory Standards Institute (CLSI)}. \url{https://clsi.org/standards/products/microbiology/documents/m39/}.
} }
\usage{ \usage{
resistance(..., minimum = 30, as_percent = FALSE, only_all_tested = FALSE) resistance(..., minimum = 30, as_percent = FALSE, only_all_tested = FALSE)
susceptibility(..., minimum = 30, as_percent = FALSE, only_all_tested = FALSE) susceptibility(..., minimum = 30, as_percent = FALSE, only_all_tested = FALSE)
rsi_confidence_interval(
...,
ab_result = "R",
minimum = 30,
as_percent = FALSE,
only_all_tested = FALSE,
confidence_level = 0.95,
side = "both"
)
proportion_R(..., minimum = 30, as_percent = FALSE, only_all_tested = FALSE) proportion_R(..., minimum = 30, as_percent = FALSE, only_all_tested = FALSE)
proportion_IR(..., minimum = 30, as_percent = FALSE, only_all_tested = FALSE) proportion_IR(..., minimum = 30, as_percent = FALSE, only_all_tested = FALSE)
@ -38,7 +49,7 @@ proportion_df(
minimum = 30, minimum = 30,
as_percent = FALSE, as_percent = FALSE,
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE confidence_level = 0.95
) )
rsi_df( rsi_df(
@ -48,7 +59,7 @@ rsi_df(
minimum = 30, minimum = 30,
as_percent = FALSE, as_percent = FALSE,
combine_SI = TRUE, combine_SI = TRUE,
combine_IR = FALSE confidence_level = 0.95
) )
} }
\arguments{ \arguments{
@ -60,15 +71,19 @@ rsi_df(
\item{only_all_tested}{(for combination therapies, i.e. using more than one variable for \code{...}): a \link{logical} to indicate that isolates must be tested for all antibiotics, see section \emph{Combination Therapy} below} \item{only_all_tested}{(for combination therapies, i.e. using more than one variable for \code{...}): a \link{logical} to indicate that isolates must be tested for all antibiotics, see section \emph{Combination Therapy} below}
\item{ab_result}{antibiotic results to test against, must be one of more values of "R", "S", "I"}
\item{confidence_level}{the confidence level for the returned confidence interval. For the calculation, the number of S or SI isolates, and R isolates are compared with the total number of available isolates with R, S, or I by using \code{\link[=binom.test]{binom.test()}}, i.e., the Clopper-Pearson method.}
\item{side}{the side of the confidence interval to return. Defaults to \code{"both"} for a length 2 vector, but can also be (abbreviated as) \code{"min"}/\code{"left"}/\code{"lower"}/\code{"less"} or \code{"max"}/\code{"right"}/\code{"higher"}/\code{"greater"}.}
\item{data}{a \link{data.frame} containing columns with class \code{\link{rsi}} (see \code{\link[=as.rsi]{as.rsi()}})} \item{data}{a \link{data.frame} containing columns with class \code{\link{rsi}} (see \code{\link[=as.rsi]{as.rsi()}})}
\item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}} \item{translate_ab}{a column name of the \link{antibiotics} data set to translate the antibiotic abbreviations to, using \code{\link[=ab_property]{ab_property()}}}
\item{language}{language of the returned text, defaults to system language (see \code{\link[=get_AMR_locale]{get_AMR_locale()}}) and can also be set with \code{getOption("AMR_locale")}. Use \code{language = NULL} or \code{language = ""} to prevent translation.} \item{language}{language of the returned text, defaults to system language (see \code{\link[=get_AMR_locale]{get_AMR_locale()}}) and can also be set with \code{getOption("AMR_locale")}. Use \code{language = NULL} or \code{language = ""} to prevent translation.}
\item{combine_SI}{a \link{logical} to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant). This used to be the argument \code{combine_IR}, but this now follows the redefinition by EUCAST about the interpretation of I (increased exposure) in 2019, see section 'Interpretation of S, I and R' below. Default is \code{TRUE}.} \item{combine_SI}{a \link{logical} to indicate whether all values of S and I must be merged into one, so the output only consists of S+I vs. R (susceptible vs. resistant), defaults to \code{TRUE}}
\item{combine_IR}{a \link{logical} to indicate whether all values of I and R must be merged into one, so the output only consists of S vs. I+R (susceptible vs. non-susceptible). This is outdated, see argument \code{combine_SI}.}
} }
\value{ \value{
A \link{double} or, when \code{as_percent = TRUE}, a \link{character}. A \link{double} or, when \code{as_percent = TRUE}, a \link{character}.
@ -81,6 +96,8 @@ These functions can be used to calculate the (co-)resistance or susceptibility o
\details{ \details{
The function \code{\link[=resistance]{resistance()}} is equal to the function \code{\link[=proportion_R]{proportion_R()}}. The function \code{\link[=susceptibility]{susceptibility()}} is equal to the function \code{\link[=proportion_SI]{proportion_SI()}}. The function \code{\link[=resistance]{resistance()}} is equal to the function \code{\link[=proportion_R]{proportion_R()}}. The function \code{\link[=susceptibility]{susceptibility()}} is equal to the function \code{\link[=proportion_SI]{proportion_SI()}}.
Use \code{\link[=rsi_confidence_interval]{rsi_confidence_interval()}} to calculate the confidence interval, which relies on \code{\link[=binom.test]{binom.test()}}, i.e., the Clopper-Pearson method. This function returns a vector of length 2 at default for antimicrobial \emph{resistance}. Change the \code{side} argument to "left"/"min" or "right"/"max" to return a single value, and change the \code{ab_result} argument to e.g. \code{c("S", "I")} to test for antimicrobial \emph{susceptibility}, see Examples.
\strong{Remember that you should filter your data to let it contain only first isolates!} This is needed to exclude duplicates and to reduce selection bias. Use \code{\link[=first_isolate]{first_isolate()}} to determine them in your data set. \strong{Remember that you should filter your data to let it contain only first isolates!} This is needed to exclude duplicates and to reduce selection bias. Use \code{\link[=first_isolate]{first_isolate()}} to determine them in your data set.
These functions are not meant to count isolates, but to calculate the proportion of resistance/susceptibility. Use the \code{\link[=count]{count()}} functions to count isolates. The function \code{\link[=susceptibility]{susceptibility()}} is essentially equal to \code{count_susceptible() / count_all()}. \emph{Low counts can influence the outcome - the \code{proportion} functions may camouflage this, since they only return the proportion (albeit being dependent on the \code{minimum} argument).} These functions are not meant to count isolates, but to calculate the proportion of resistance/susceptibility. Use the \code{\link[=count]{count()}} functions to count isolates. The function \code{\link[=susceptibility]{susceptibility()}} is essentially equal to \code{count_susceptible() / count_all()}. \emph{Low counts can influence the outcome - the \code{proportion} functions may camouflage this, since they only return the proportion (albeit being dependent on the \code{minimum} argument).}
@ -144,8 +161,16 @@ This AMR package honours this (new) insight. Use \code{\link[=susceptibility]{su
# run ?example_isolates for more info. # run ?example_isolates for more info.
# base R ------------------------------------------------------------ # base R ------------------------------------------------------------
resistance(example_isolates$AMX) # determines \%R # determines \%R
susceptibility(example_isolates$AMX) # determines \%S+I resistance(example_isolates$AMX)
rsi_confidence_interval(example_isolates$AMX)
rsi_confidence_interval(example_isolates$AMX,
confidence_level = 0.975)
# determines \%S+I:
susceptibility(example_isolates$AMX)
rsi_confidence_interval(example_isolates$AMX,
ab_result = c("S", "I"))
# be more specific # be more specific
proportion_S(example_isolates$AMX) proportion_S(example_isolates$AMX)
@ -157,6 +182,7 @@ proportion_R(example_isolates$AMX)
# dplyr ------------------------------------------------------------- # dplyr -------------------------------------------------------------
\donttest{ \donttest{
if (require("dplyr")) { if (require("dplyr")) {
example_isolates \%>\% example_isolates \%>\%
group_by(ward) \%>\% group_by(ward) \%>\%
summarise( summarise(
@ -164,6 +190,20 @@ if (require("dplyr")) {
n = n_rsi(CIP) n = n_rsi(CIP)
) # n_rsi works like n_distinct in dplyr, see ?n_rsi ) # n_rsi works like n_distinct in dplyr, see ?n_rsi
}
if (require("dplyr")) {
example_isolates \%>\%
group_by(ward) \%>\%
summarise(
cipro_R = resistance(CIP),
ci_min = rsi_confidence_interval(CIP, side = "min"),
ci_max = rsi_confidence_interval(CIP, side = "max"),
)
}
if (require("dplyr")) {
example_isolates \%>\% example_isolates \%>\%
group_by(ward) \%>\% group_by(ward) \%>\%
summarise( summarise(