From c0fc82c794a0e426190d15491b6db3bac9b9e590 Mon Sep 17 00:00:00 2001 From: "Matthijs S. Berends" Date: Wed, 2 May 2018 14:56:25 +0200 Subject: [PATCH] Added function `n_rsi` --- DESCRIPTION | 2 +- NAMESPACE | 2 + NEWS.md | 2 + R/classes.R | 14 +- R/eucast.R | 1 + R/misc.R | 6 +- R/print.R | 10 +- R/rsi_analysis.R | 244 +++++++++++++++++++---------- README.md | 11 +- man/EUCAST.Rd | 1 + man/figures/combi_therapy_2.png | Bin 0 -> 3066 bytes man/figures/combi_therapy_3.png | Bin 0 -> 3637 bytes man/figures/mono_therapy.png | Bin 0 -> 1865 bytes man/rsi.Rd | 99 +++++++++--- man/rsi_df.Rd | 54 ------- tests/testthat/test-eucast.R | 2 + tests/testthat/test-rsi_analysis.R | 15 ++ 17 files changed, 292 insertions(+), 171 deletions(-) create mode 100644 man/figures/combi_therapy_2.png create mode 100644 man/figures/combi_therapy_3.png create mode 100644 man/figures/mono_therapy.png delete mode 100644 man/rsi_df.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 34ae0ab2..f06f8f3f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: AMR Version: 0.2.0 -Date: 2018-04-30 +Date: 2018-05-02 Title: Antimicrobial Resistance Analysis Authors@R: c( person( diff --git a/NAMESPACE b/NAMESPACE index b027ce30..c74fb9c2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -38,6 +38,7 @@ export(is.rsi) export(key_antibiotics) export(left_join_microorganisms) export(mo_property) +export(n_rsi) export(right_join_microorganisms) export(rsi) export(rsi_df) @@ -96,5 +97,6 @@ importFrom(rvest,html_table) importFrom(stats,fivenum) importFrom(stats,quantile) importFrom(stats,sd) +importFrom(utils,object.size) importFrom(utils,packageDescription) importFrom(xml2,read_html) diff --git a/NEWS.md b/NEWS.md index ec2a0d5a..51194f3d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,7 @@ #### New * Full support for Windows, Linux and macOS * Full support for old R versions, only R-3.0.0 (April 2013) or later is needed (needed packages may have other dependencies) +* Function `n_rsi` to count cases where antibiotic test results were available, to be used in conjunction with `dplyr::summarise`, see ?rsi * Function `guess_bactid` to **determine the ID** of a microorganism based on genus/species or known abbreviations like MRSA * Function `guess_atc` to **determine the ATC** of an antibiotic based on name, trade name, or known abbreviations * Function `freq` to create **frequency tables**, with additional info in a header @@ -13,6 +14,7 @@ * New print format for `tibble`s and `data.table`s #### Changed +* Fixed `rsi` class for vectors that contain only invalid antimicrobial interpretations * Renamed dataset `ablist` to `antibiotics` * Renamed dataset `bactlist` to `microorganisms` * Added common abbreviations and trade names to the `antibiotics` dataset diff --git a/R/classes.R b/R/classes.R index cb0aa73a..20c7db64 100644 --- a/R/classes.R +++ b/R/classes.R @@ -93,12 +93,14 @@ print.rsi <- function(x, ...) { R <- x[x == 'R'] %>% length() IR <- x[x %in% c('I', 'R')] %>% length() cat("Class 'rsi'\n") - cat(n, " results (missing: ", n_total - n, ' = ', percent((n_total - n) / n, force_zero = TRUE), ')\n', sep = "") - cat('\n') - cat('Sum of S: ', S, ' (', percent(S / n, force_zero = TRUE), ')\n', sep = "") - cat('Sum of IR: ', IR, ' (', percent(IR / n, force_zero = TRUE), ')\n', sep = "") - cat('- Sum of R: ', R, ' (', percent(R / n, force_zero = TRUE), ')\n', sep = "") - cat('- Sum of I: ', I, ' (', percent(I / n, force_zero = TRUE), ')\n', sep = "") + cat(n, " results (missing: ", n_total - n, ' = ', percent((n_total - n) / n_total, force_zero = TRUE), ')\n', sep = "") + if (n > 0) { + cat('\n') + cat('Sum of S: ', S, ' (', percent(S / n, force_zero = TRUE), ')\n', sep = "") + cat('Sum of IR: ', IR, ' (', percent(IR / n, force_zero = TRUE), ')\n', sep = "") + cat('- Sum of R: ', R, ' (', percent(R / n, force_zero = TRUE), ')\n', sep = "") + cat('- Sum of I: ', I, ' (', percent(I / n, force_zero = TRUE), ')\n', sep = "") + } } #' @exportMethod summary.rsi diff --git a/R/eucast.R b/R/eucast.R index 01c3cc5c..3d2575fd 100644 --- a/R/eucast.R +++ b/R/eucast.R @@ -36,6 +36,7 @@ #' EUCAST Expert Rules Version 3.1 (Intrinsic Resistance and Exceptional Phenotypes Tables): \cr #' \url{http://www.eucast.org/fileadmin/src/media/PDFs/EUCAST_files/Expert_Rules/Expert_rules_intrinsic_exceptional_V3.1.pdf} #' @examples +#' a <- EUCAST_rules(septic_patients) #' a <- data.frame(bactid = c("STAAUR", # Staphylococcus aureus #' "ENCFAE", # Enterococcus faecalis #' "ESCCOL", # Escherichia coli diff --git a/R/misc.R b/R/misc.R index 18a36908..fb6bf27a 100644 --- a/R/misc.R +++ b/R/misc.R @@ -48,10 +48,12 @@ # No export, no Rd percent <- function(x, round = 1, force_zero = FALSE, ...) { val <- base::round(x * 100, digits = round) - if (force_zero & any(val == as.integer(val))) { + if (force_zero == TRUE & any(val == as.integer(val) & !is.na(val))) { val[val == as.integer(val)] <- paste0(val[val == as.integer(val)], ".", strrep(0, round)) } - base::paste0(val, "%") + pct <- base::paste0(val, "%") + pct[pct == "NA%"] <- NA_character_ + pct } check_available_columns <- function(tbl, col.list, info = TRUE) { diff --git a/R/print.R b/R/print.R index 676917bb..09138087 100644 --- a/R/print.R +++ b/R/print.R @@ -29,6 +29,7 @@ #' @name print #' @importFrom dplyr %>% n_groups group_vars group_size filter pull select #' @importFrom data.table data.table +#' @importFrom utils object.size #' @exportMethod print.tbl_df #' @export #' @examples @@ -191,7 +192,8 @@ prettyprint_df <- function(x, if (n + 1 < nrow(x)) { # remove in between part, 1 extra for ~~~~ between first and last part rows_list <- c(1:(n / 2 + 1), (nrow(x) - (n / 2) + 1):nrow(x)) - x <- x %>% filter(row_number() %in% rows_list) + x <- as.data.frame(x.bak[rows_list,]) + colnames(x) <- colnames(x.bak) rownames(x) <- rownames(x.bak)[rows_list] # set inbetweener between parts rownames(x)[n / 2 + 1] <- strrep("~", maxrowchars) @@ -218,7 +220,11 @@ prettyprint_df <- function(x, gsub('POSIX', '', .) %>% paste0(collapse = '/')) } else { - c[[1]] + if (NCOL(.) > 1) { + .[1,] + } else { + c[[1]] + } } }) %>% unlist() %>% diff --git a/R/rsi_analysis.R b/R/rsi_analysis.R index 2ec1cdaa..be5874af 100644 --- a/R/rsi_analysis.R +++ b/R/rsi_analysis.R @@ -16,40 +16,164 @@ # GNU General Public License for more details. # # ==================================================================== # -#' Resistance of isolates in data.frame +#' Resistance of isolates #' -#' \strong{NOTE: use \code{\link{rsi}} in dplyr functions like \code{\link[dplyr]{summarise}}.} \cr Calculate the percentage of S, SI, I, IR or R of a \code{data.frame} containing isolates. +#' This functions can be used to calculate the (co-)resistance of isolates (i.e. percentage S, SI, I, IR or R [of a vector] of isolates). The functions \code{rsi} and \code{n_rsi} can be used in \code{dplyr}s \code{\link[dplyr]{summarise}} and support grouped variables, see \emph{Examples}. #' @param tbl \code{data.frame} containing columns with antibiotic interpretations. #' @param ab character vector with 1, 2 or 3 antibiotics that occur as column names in \code{tbl}, like \code{ab = c("amox", "amcl")} +#' @param ab1,ab2 vector of antibiotic interpretations, they will be transformed internally with \code{\link{as.rsi}} #' @param interpretation antimicrobial interpretation of which the portion must be calculated. Valid values are \code{"S"}, \code{"SI"}, \code{"I"}, \code{"IR"} or \code{"R"}. #' @param minimum minimal amount of available isolates. Any number lower than \code{minimum} will return \code{NA} with a warning (when \code{warning = TRUE}). -#' @param percent return output as percent (text), will else (at default) be a double +#' @param as_percent return output as percent (text), will else (at default) be a double #' @param info calculate the amount of available isolates and print it, like \code{n = 423} #' @param warning show a warning when the available amount of isolates is below \code{minimum} #' @details Remember that you should filter your table to let it contain \strong{only first isolates}! +#' +#' To calculate the probability (\emph{p}) of susceptibility of one antibiotic, we use this formula: +#' \if{html}{ +#' \out{
}\figure{mono_therapy.png}\out{
} +#' } +#' \if{latex}{ +#' \deqn{p = \frac{\sum{ab1_S}}{\sum{ab1_{R|I|S}}}} +#' } +#' \cr +#' To calculate the probability (\emph{p}) of susceptibility of more antibiotics a combination therapy, we need to check whether one of them has a susceptible result (as numerator) and count all cases where all antibiotics were tested (as denominator). \cr +#' For two antibiotics: +#' \if{html}{ +#' \out{
}\figure{combi_therapy_2.png}\out{
} +#' } +#' \if{latex}{ +#' \deqn{p = \frac{\sum{ab1_S}\mid{ab2_S}}{\sum{ab1_{R|I|S},ab2_{R|I|S}}}} +#' } +#' \cr +#' For three antibiotics: +#' \if{html}{ +#' \out{
}\figure{combi_therapy_3.png}\out{
} +#' } +#' \if{latex}{ +#' \deqn{p = \frac{\sum{ab1_S}\mid{ab2_S}\mid{ab3_S}}{\sum{ab1_{R|I|S},ab2_{R|I|S},ab3_{R|I|S}}}} +#' } +#' #' @keywords rsi antibiotics isolate isolates -#' @return Double or, when \code{percent = TRUE}, a character. +#' @return Double or, when \code{as_percent = TRUE}, a character. +#' @rdname rsi #' @export #' @importFrom dplyr %>% n_distinct filter filter_at pull vars all_vars any_vars -#' @seealso \code{\link{rsi}} for the function that can be used with \code{\link[dplyr]{summarise}} directly. #' @examples -#' \dontrun{ -#' rsi_df(tbl_with_bloodcultures, 'amcl') -#' -#' rsi_df(tbl_with_bloodcultures, c('amcl', 'gent'), interpretation = 'IR') -#' #' library(dplyr) -#' # calculate current empiric therapy of Helicobacter gastritis: +#' +#' septic_patients %>% +#' group_by(hospital_id) %>% +#' summarise(cipro_susceptibility = rsi(cipr, interpretation = "S"), +#' n = n_rsi(cipr)) # n_rsi works like n_distinct in dplyr +#' +#' septic_patients %>% +#' group_by(hospital_id) %>% +#' summarise(cipro_S = rsi(cipr, interpretation = "S", +#' as_percent = TRUE, warning = FALSE), +#' cipro_n = n_rsi(cipr), +#' genta_S = rsi(gent, interpretation = "S", +#' as_percent = TRUE, warning = FALSE), +#' genta_n = n_rsi(gent), +#' combination_S = rsi(cipr, gent, interpretation = "S", +#' as_percent = TRUE, warning = FALSE), +#' combination_n = n_rsi(cipr, gent)) +#' +#' # calculate resistance +#' rsi(septic_patients$amox) +#' # or susceptibility +#' rsi(septic_patients$amox, interpretation = "S") +#' +#' # calculate co-resistance between amoxicillin/clav acid and gentamicin, +#' # so we can review that combination therapy does a lot more than mono therapy: +#' septic_patients %>% rsi_df(ab = "amcl", interpretation = "S") # = 67.8% +#' septic_patients %>% rsi_df(ab = "gent", interpretation = "S") # = 69.1% +#' septic_patients %>% rsi_df(ab = c("amcl", "gent"), interpretation = "S") # = 90.6% +#' +#' \dontrun{ +#' # calculate current empiric combination therapy of Helicobacter gastritis: #' my_table %>% #' filter(first_isolate == TRUE, #' genus == "Helicobacter") %>% -#' rsi_df(ab = c("amox", "metr")) +#' rsi_df(ab = c("amox", "metr")) # amoxicillin with metronidazole #' } +rsi <- function(ab1, + ab2 = NA, + interpretation = 'IR', + minimum = 30, + as_percent = FALSE, + info = FALSE, + warning = TRUE) { + ab1.name <- deparse(substitute(ab1)) + if (ab1.name %like% '.[$].') { + ab1.name <- unlist(strsplit(ab1.name, "$", fixed = TRUE)) + ab1.name <- ab1.name[length(ab1.name)] + } + if (!ab1.name %like% '^[a-z]{3,4}$') { + ab1.name <- 'rsi1' + } + if (length(ab1) == 1 & is.character(ab1)) { + stop('`ab1` must be a vector of antibiotic interpretations.', + '\n Try rsi(', ab1, ', ...) instead of rsi("', ab1, '", ...)', call. = FALSE) + } + ab2.name <- deparse(substitute(ab2)) + if (ab2.name %like% '.[$].') { + ab2.name <- unlist(strsplit(ab2.name, "$", fixed = TRUE)) + ab2.name <- ab2.name[length(ab2.name)] + } + if (!ab2.name %like% '^[a-z]{3,4}$') { + ab2.name <- 'rsi2' + } + if (length(ab2) == 1 & is.character(ab2)) { + stop('`ab2` must be a vector of antibiotic interpretations.', + '\n Try rsi(', ab2, ', ...) instead of rsi("', ab2, '", ...)', call. = FALSE) + } + + interpretation <- paste(interpretation, collapse = "") + + ab1 <- as.rsi(ab1) + ab2 <- as.rsi(ab2) + + tbl <- tibble(rsi1 = ab1, rsi2 = ab2) + colnames(tbl) <- c(ab1.name, ab2.name) + + if (length(ab2) == 1) { + r <- rsi_df(tbl = tbl, + ab = ab1.name, + interpretation = interpretation, + minimum = minimum, + as_percent = FALSE, + info = info, + warning = warning) + } else { + if (length(ab1) != length(ab2)) { + stop('`ab1` (n = ', length(ab1), ') and `ab2` (n = ', length(ab2), ') must be of same length.', call. = FALSE) + } + if (!interpretation %in% c('S', 'IS', 'SI')) { + warning('`interpretation` not set to S or I/S, albeit analysing a combination therapy.', call. = FALSE) + } + r <- rsi_df(tbl = tbl, + ab = c(ab1.name, ab2.name), + interpretation = interpretation, + minimum = minimum, + as_percent = FALSE, + info = info, + warning = warning) + } + if (as_percent == TRUE) { + percent(r, force_zero = TRUE) + } else { + r + } +} + +#' @export +#' @rdname rsi rsi_df <- function(tbl, ab, interpretation = 'IR', minimum = 30, - percent = FALSE, + as_percent = FALSE, info = TRUE, warning = TRUE) { @@ -103,6 +227,9 @@ rsi_df <- function(tbl, nrow() } else if (length(ab) == 2) { + if (interpretations_to_check != 'S') { + warning('`interpretation` not set to S or I/S, albeit analysing a combination therapy.', call. = FALSE) + } numerator <- tbl %>% filter_at(vars(ab[1], ab[2]), any_vars(. == interpretations_to_check)) %>% @@ -116,6 +243,9 @@ rsi_df <- function(tbl, nrow() } else if (length(ab) == 3) { + if (interpretations_to_check != 'S') { + warning('`interpretation` not set to S or I/S, albeit analysing a combination therapy.', call. = FALSE) + } numerator <- tbl %>% filter_at(vars(ab[1], ab[2], ab[3]), any_vars(. == interpretations_to_check)) %>% @@ -150,9 +280,10 @@ rsi_df <- function(tbl, # calculate and format y <- numerator / denominator - if (percent == TRUE) { - y <- percent(y) + if (as_percent == TRUE) { + y <- percent(y, force_zero = TRUE) } + if (denominator < minimum) { if (warning == TRUE) { warning(paste0('TOO FEW ISOLATES OF ', toString(ab), ' (n = ', denominator, ', n < ', minimum, '); NO RESULT.')) @@ -164,78 +295,29 @@ rsi_df <- function(tbl, y } -#' Resistance of isolates -#' -#' This function can be used in \code{dplyr}s \code{\link[dplyr]{summarise}}, see \emph{Examples}. Calculate the percentage S, SI, I, IR or R of a vector of isolates. -#' @param ab1,ab2 list with interpretations of an antibiotic -#' @inheritParams rsi_df -#' @details This function uses the \code{\link{rsi_df}} function internally. -#' @keywords rsi antibiotics isolate isolates -#' @return Double or, when \code{percent = TRUE}, a character. #' @export -#' @examples -#' \dontrun{ -#' tbl %>% -#' group_by(hospital) %>% -#' summarise(cipr = rsi(cipr)) -#' -#' tbl %>% -#' group_by(year, hospital) %>% -#' summarise( -#' isolates = n(), -#' cipro = rsi(cipr %>% as.rsi(), percent = TRUE), -#' amoxi = rsi(amox %>% as.rsi(), percent = TRUE)) -#' -#' rsi(as.rsi(isolates$amox)) -#' -#' rsi(as.rsi(isolates$amcl), interpretation = "S") -#' } -rsi <- function(ab1, ab2 = NA, interpretation = 'IR', minimum = 30, percent = FALSE, info = FALSE, warning = FALSE) { - ab1.name <- deparse(substitute(ab1)) - if (ab1.name %like% '.[$].') { - ab1.name <- unlist(strsplit(ab1.name, "$", fixed = TRUE)) - ab1.name <- ab1.name[length(ab1.name)] - } - if (!ab1.name %like% '^[a-z]{3,4}$') { - ab1.name <- 'rsi1' - } - ab2.name <- deparse(substitute(ab2)) - if (ab2.name %like% '.[$].') { - ab2.name <- unlist(strsplit(ab2.name, "$", fixed = TRUE)) - ab2.name <- ab2.name[length(ab2.name)] - } - if (!ab2.name %like% '^[a-z]{3,4}$') { - ab2.name <- 'rsi2' - } +#' @rdname rsi +n_rsi <- function(ab1, ab2 = NA) { - interpretation <- paste(interpretation, collapse = "") + if (length(ab1) == 1 & is.character(ab1)) { + stop('`ab1` must be a vector of antibiotic interpretations.', + '\n Try n_rsi(', ab1, ', ...) instead of n_rsi("', ab1, '", ...)', call. = FALSE) + } + ab1 <- as.rsi(ab1) - tbl <- tibble(rsi1 = ab1, rsi2 = ab2) - colnames(tbl) <- c(ab1.name, ab2.name) - - if (length(ab2) == 1) { - return(rsi_df(tbl = tbl, - ab = ab1.name, - interpretation = interpretation, - minimum = minimum, - percent = percent, - info = info, - warning = warning)) + if (length(ab2) == 1 & all(is.na(ab2))) { + # only 1 antibiotic + length(ab1[!is.na(ab1)]) } else { - if (length(ab1) != length(ab2)) { - stop('`ab1` (n = ', length(ab1), ') and `ab2` (n = ', length(ab2), ') must be of same length.', call. = FALSE) + if (length(ab2) == 1 & is.character(ab2)) { + stop('`ab2` must be a vector of antibiotic interpretations.', + '\n Try n_rsi(', ab2, ', ...) instead of n_rsi("', ab2, '", ...)', call. = FALSE) } - if (interpretation != 'S') { - warning('`interpretation` is not set to S, albeit analysing a combination therapy.') - } - return(rsi_df(tbl = tbl, - ab = c(ab1.name, ab2.name), - interpretation = interpretation, - minimum = minimum, - percent = percent, - info = info, - warning = warning)) + ab2 <- as.rsi(ab2) + tbl <- tibble(ab1, ab2) + tbl %>% filter(!is.na(ab1) & !is.na(ab2)) %>% nrow() } + } #' Predict antimicrobial resistance diff --git a/README.md b/README.md index ab51253b..4d889336 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This R package contains functions to make **microbiological, epidemiological dat With `AMR` you can also: * Create frequency tables with the `freq` function -* Conduct AMR analysis with the `rsi` function, that can also be used with the `dplyr` package (e.g. in conjunction with `summarise`) to calculate the resistance percentages of different antibiotic columns of a table +* Conduct AMR analysis with the `rsi` function, that can also be used with the `dplyr` package (e.g. in conjunction with `summarise`) to calculate the resistance percentages (and even co-resistance) of different antibiotic columns of a table * Predict antimicrobial resistance for the nextcoming years with the `rsi_predict` function * Apply [EUCAST rules to isolates](http://www.eucast.org/expert_rules_and_intrinsic_resistance/) with the `EUCAST_rules` function * Identify first isolates of every patient [using guidelines from the CLSI](https://clsi.org/standards/products/microbiology/documents/m39/) (Clinical and Laboratory Standards Institute) with the `first_isolate` function @@ -264,13 +264,16 @@ abname("J01CR02", from = "atc", to = "umcg") # "AMCL" ### Databases included in package Datasets to work with antibiotics and bacteria properties. ```r -# Dataset with 2000 random blood culture isolates from anonymised septic patients between 2001 and 2017 in 5 Dutch hospitals +# Dataset with 2000 random blood culture isolates from anonymised +# septic patients between 2001 and 2017 in 5 Dutch hospitals septic_patients # A tibble: 4,000 x 47 -# Dataset with ATC antibiotics codes, official names, trade names and DDD's (oral and parenteral) +# Dataset with ATC antibiotics codes, official names, trade names +# and DDD's (oral and parenteral) antibiotics # A tibble: 420 x 18 -# Dataset with bacteria codes and properties like gram stain and aerobic/anaerobic +# Dataset with bacteria codes and properties like gram stain and +# aerobic/anaerobic microorganisms # A tibble: 2,453 x 12 ``` diff --git a/man/EUCAST.Rd b/man/EUCAST.Rd index 40c51d84..95c5baa4 100644 --- a/man/EUCAST.Rd +++ b/man/EUCAST.Rd @@ -50,6 +50,7 @@ table with edited variables of antibiotics. Apply expert rules (like intrinsic resistance), as defined by the European Committee on Antimicrobial Susceptibility Testing (EUCAST, \url{http://eucast.org}), see \emph{Source}. } \examples{ +a <- EUCAST_rules(septic_patients) a <- data.frame(bactid = c("STAAUR", # Staphylococcus aureus "ENCFAE", # Enterococcus faecalis "ESCCOL", # Escherichia coli diff --git a/man/figures/combi_therapy_2.png b/man/figures/combi_therapy_2.png new file mode 100644 index 0000000000000000000000000000000000000000..c76fbb2ac8633885c51b8ae5e9d22a69c2cd142f GIT binary patch literal 3066 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 literal 0 HcmV?d00001 diff --git a/man/figures/combi_therapy_3.png b/man/figures/combi_therapy_3.png new file mode 100644 index 0000000000000000000000000000000000000000..a5f7e0304403fe39ad8c362b6d615aaebc4082cf GIT binary patch literal 3637 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 Hu0mjfqQ&OF literal 0 HcmV?d00001 diff --git a/man/figures/mono_therapy.png b/man/figures/mono_therapy.png new file mode 100644 index 0000000000000000000000000000000000000000..f0e14a7c27e5b47a6052017228276d94827e4ca1 GIT binary patch literal 1865 zcmV-P2e$Z$P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2Hr_TK~#8N?V7z$ z6kQaD*Y^+5fL6vBBDTf^K?}tWF={6X78VvJ0#-H>(1b=sDNRsFEG+y$!Dvhr777xi zP=iLIl+ch+A%^e=_&(0>FwD;E7wfV!Bl8q@=iGaDKF&S&+;e8`j^Dq3rxHTqKl@Dx zgGBpb5)bVU4Grxm#PsyE^^Onm(Ef!B7n+-!IcRThXQA@);lqcjsw#CW0gc@0)2B_& z24jEl;K83if0|rI>>(o0{QSJM{O;X5t6JyYy?fL%3?^@e<>h7m%Nb10gmc!`*8Wk` z)+j1Ae*eIM1HHYy99+D3(PxG&EiHDmc~)0fDK)WtVDh7*qn|!~>hA8gs2!KK~KCk&Yco-ZfIz*28XGs zsZ*y;Ei5eH`sqXKmiYHv*eJvY{J!q|+qZ94l^a%RMhgSynEw0=KdvT$h+|hz8 zqP4BFb+#Wr?SuRerO7$aI7#&a(Hk|fl2aqqt45-ZT@ufe!JRvIDBWlz7d<^a^dVZ6 zD3@~bTOn-o0Bj6(*M2@95~Ludly-`?ks1z?IL;%xIQ~iHQlyqeqWQ zgzw+KGdw3woRFyDIdbHP#DdJu&T=O=Zrq^MqGAn26F=?u_4Q%1FJ8PbIR{HiOO*Tf z@0SRVA3sLdM6M>MQsd*}EV(AE56|)A$0Ziz{Q2|e&Yi;u9z1x!d3NsHX${3=9w;V| z{&3I1ge!=8x=vq_rFW?a=2?slQ_2JnS^d72=+aU=mpIuzp5fA^OT;8+&YZETb%+#w z?|Js_-AnoA%^OOBPMi!rr@FctkEE4=G>Y=;*RPbSTv=Ip^ym?y5A}Kf{=GzT`0!yy z>)N$z{MV{Vz(yesV7XasQ=v=H46%3WF?kudQdUA5g{o8z3=9wg{n3IGL2(}Ee+J#? z%-_`kxVkqUr2{o?L|X!}(LS2uIeiKe(%@e@fs)bHHKLm(9@>|a%}-d`hmx-z55M2p z*=a|)k)y8+EF^?pI%YLuQkHi0NH(2LkBp31 zr-bt2L_Qnnt*kdANA#xSUX+68$GRqD!>=7Bgx;hEF_-qsf-^?j3w!cly#M9P7YyHh z5vZ3Z#8ncv0=tpzggtpM=E2L?)zz7hN{x<=QZ_X;N%TS3%d(sw>za@i8x9B3Woq1{ zd3kx6EY7Te#n027!@+p(Y5cZFAIr`N#;*$(7z|z z-#~AfpqS63D3{UF7j1odWDL|K5Sh@Z9;K^;_nWv#w4Z_ePr(#V<0RD!L~qojAVR8F zjYJ*0gsXl3n}*Pd{vORf2NMG1Z}ky5?MGyf=HTF%i%me2{aU9^g>gwu#{raVPAB&5NEdK5!^Mc{C z{J0ut0DLzP744(1=;uBntV)7PP)sFkAizWqoVz*SFd70 zL3b|~Z^AlE4x$|#6dEU?Y_&z?P;;r{*mZ{NPnrD9y1ceVHN>eVYsrk&5@8w!2GC4zf2S<>b7 zb#LA@jUW|ttTe)V=iXKqJw-5y3E%cH!?w0Ira4CH#10u?(bliBxE9^g(!#xI(GJ2C z@vZh*!Q)e|t*uFP319nB+oK6AGiZF@zI`0ClT~?OK^h(&W-Xx`|7CFwK1H&RbJNJ8 zuV23|(MSGPA5n>UwkL`9!zA%MVUpN>m?YW{k5uY^eg+?(Zppy%00000NkvXXu0mjf Dm71zV literal 0 HcmV?d00001 diff --git a/man/rsi.Rd b/man/rsi.Rd index d3b12765..e0da2ee9 100644 --- a/man/rsi.Rd +++ b/man/rsi.Rd @@ -2,49 +2,106 @@ % Please edit documentation in R/rsi_analysis.R \name{rsi} \alias{rsi} +\alias{rsi_df} +\alias{n_rsi} \title{Resistance of isolates} \usage{ -rsi(ab1, ab2 = NA, interpretation = "IR", minimum = 30, percent = FALSE, - info = FALSE, warning = FALSE) +rsi(ab1, ab2 = NA, interpretation = "IR", minimum = 30, + as_percent = FALSE, info = FALSE, warning = TRUE) + +rsi_df(tbl, ab, interpretation = "IR", minimum = 30, as_percent = FALSE, + info = TRUE, warning = TRUE) + +n_rsi(ab1, ab2 = NA) } \arguments{ -\item{ab1, ab2}{list with interpretations of an antibiotic} +\item{ab1, ab2}{vector of antibiotic interpretations, they will be transformed internally with \code{\link{as.rsi}}} \item{interpretation}{antimicrobial interpretation of which the portion must be calculated. Valid values are \code{"S"}, \code{"SI"}, \code{"I"}, \code{"IR"} or \code{"R"}.} \item{minimum}{minimal amount of available isolates. Any number lower than \code{minimum} will return \code{NA} with a warning (when \code{warning = TRUE}).} -\item{percent}{return output as percent (text), will else (at default) be a double} +\item{as_percent}{return output as percent (text), will else (at default) be a double} \item{info}{calculate the amount of available isolates and print it, like \code{n = 423}} \item{warning}{show a warning when the available amount of isolates is below \code{minimum}} + +\item{tbl}{\code{data.frame} containing columns with antibiotic interpretations.} + +\item{ab}{character vector with 1, 2 or 3 antibiotics that occur as column names in \code{tbl}, like \code{ab = c("amox", "amcl")}} } \value{ -Double or, when \code{percent = TRUE}, a character. +Double or, when \code{as_percent = TRUE}, a character. } \description{ -This function can be used in \code{dplyr}s \code{\link[dplyr]{summarise}}, see \emph{Examples}. Calculate the percentage S, SI, I, IR or R of a vector of isolates. +This functions can be used to calculate the (co-)resistance of isolates (i.e. percentage S, SI, I, IR or R [of a vector] of isolates). The functions \code{rsi} and \code{n_rsi} can be used in \code{dplyr}s \code{\link[dplyr]{summarise}} and support grouped variables, see \emph{Examples}. } \details{ -This function uses the \code{\link{rsi_df}} function internally. +Remember that you should filter your table to let it contain \strong{only first isolates}! + +To calculate the probability (\emph{p}) of susceptibility of one antibiotic, we use this formula: +\if{html}{ + \out{
}\figure{mono_therapy.png}\out{
} +} +\if{latex}{ + \deqn{p = \frac{\sum{ab1_S}}{\sum{ab1_{R|I|S}}}} +} +\cr +To calculate the probability (\emph{p}) of susceptibility of more antibiotics a combination therapy, we need to check whether one of them has a susceptible result (as numerator) and count all cases where all antibiotics were tested (as denominator). \cr +For two antibiotics: +\if{html}{ + \out{
}\figure{combi_therapy_2.png}\out{
} +} +\if{latex}{ + \deqn{p = \frac{\sum{ab1_S}\mid{ab2_S}}{\sum{ab1_{R|I|S},ab2_{R|I|S}}}} +} +\cr +For three antibiotics: +\if{html}{ + \out{
}\figure{combi_therapy_3.png}\out{
} +} +\if{latex}{ + \deqn{p = \frac{\sum{ab1_S}\mid{ab2_S}\mid{ab3_S}}{\sum{ab1_{R|I|S},ab2_{R|I|S},ab3_{R|I|S}}}} +} } \examples{ +library(dplyr) + +septic_patients \%>\% + group_by(hospital_id) \%>\% + summarise(cipro_susceptibility = rsi(cipr, interpretation = "S"), + n = n_rsi(cipr)) # n_rsi works like n_distinct in dplyr + +septic_patients \%>\% + group_by(hospital_id) \%>\% + summarise(cipro_S = rsi(cipr, interpretation = "S", + as_percent = TRUE, warning = FALSE), + cipro_n = n_rsi(cipr), + genta_S = rsi(gent, interpretation = "S", + as_percent = TRUE, warning = FALSE), + genta_n = n_rsi(gent), + combination_S = rsi(cipr, gent, interpretation = "S", + as_percent = TRUE, warning = FALSE), + combination_n = n_rsi(cipr, gent)) + +# calculate resistance +rsi(septic_patients$amox) +# or susceptibility +rsi(septic_patients$amox, interpretation = "S") + +# calculate co-resistance between amoxicillin/clav acid and gentamicin, +# so we can review that combination therapy does a lot more than mono therapy: +septic_patients \%>\% rsi_df(ab = "amcl", interpretation = "S") # = 67.8\% +septic_patients \%>\% rsi_df(ab = "gent", interpretation = "S") # = 69.1\% +septic_patients \%>\% rsi_df(ab = c("amcl", "gent"), interpretation = "S") # = 90.6\% + \dontrun{ -tbl \%>\% - group_by(hospital) \%>\% - summarise(cipr = rsi(cipr)) - -tbl \%>\% - group_by(year, hospital) \%>\% - summarise( - isolates = n(), - cipro = rsi(cipr \%>\% as.rsi(), percent = TRUE), - amoxi = rsi(amox \%>\% as.rsi(), percent = TRUE)) - -rsi(as.rsi(isolates$amox)) - -rsi(as.rsi(isolates$amcl), interpretation = "S") +# calculate current empiric combination therapy of Helicobacter gastritis: +my_table \%>\% + filter(first_isolate == TRUE, + genus == "Helicobacter") \%>\% + rsi_df(ab = c("amox", "metr")) # amoxicillin with metronidazole } } \keyword{antibiotics} diff --git a/man/rsi_df.Rd b/man/rsi_df.Rd deleted file mode 100644 index af883915..00000000 --- a/man/rsi_df.Rd +++ /dev/null @@ -1,54 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/rsi_analysis.R -\name{rsi_df} -\alias{rsi_df} -\title{Resistance of isolates in data.frame} -\usage{ -rsi_df(tbl, ab, interpretation = "IR", minimum = 30, percent = FALSE, - info = TRUE, warning = TRUE) -} -\arguments{ -\item{tbl}{\code{data.frame} containing columns with antibiotic interpretations.} - -\item{ab}{character vector with 1, 2 or 3 antibiotics that occur as column names in \code{tbl}, like \code{ab = c("amox", "amcl")}} - -\item{interpretation}{antimicrobial interpretation of which the portion must be calculated. Valid values are \code{"S"}, \code{"SI"}, \code{"I"}, \code{"IR"} or \code{"R"}.} - -\item{minimum}{minimal amount of available isolates. Any number lower than \code{minimum} will return \code{NA} with a warning (when \code{warning = TRUE}).} - -\item{percent}{return output as percent (text), will else (at default) be a double} - -\item{info}{calculate the amount of available isolates and print it, like \code{n = 423}} - -\item{warning}{show a warning when the available amount of isolates is below \code{minimum}} -} -\value{ -Double or, when \code{percent = TRUE}, a character. -} -\description{ -\strong{NOTE: use \code{\link{rsi}} in dplyr functions like \code{\link[dplyr]{summarise}}.} \cr Calculate the percentage of S, SI, I, IR or R of a \code{data.frame} containing isolates. -} -\details{ -Remember that you should filter your table to let it contain \strong{only first isolates}! -} -\examples{ -\dontrun{ -rsi_df(tbl_with_bloodcultures, 'amcl') - -rsi_df(tbl_with_bloodcultures, c('amcl', 'gent'), interpretation = 'IR') - -library(dplyr) -# calculate current empiric therapy of Helicobacter gastritis: -my_table \%>\% - filter(first_isolate == TRUE, - genus == "Helicobacter") \%>\% - rsi_df(ab = c("amox", "metr")) -} -} -\seealso{ -\code{\link{rsi}} for the function that can be used with \code{\link[dplyr]{summarise}} directly. -} -\keyword{antibiotics} -\keyword{isolate} -\keyword{isolates} -\keyword{rsi} diff --git a/tests/testthat/test-eucast.R b/tests/testthat/test-eucast.R index c52b5a6c..a7d8a0e1 100644 --- a/tests/testthat/test-eucast.R +++ b/tests/testthat/test-eucast.R @@ -1,6 +1,8 @@ context("eucast.R") test_that("EUCAST rules work", { + a <- EUCAST_rules(septic_patients) + a <- data.frame(bactid = c("KLEPNE", # Klebsiella pneumoniae "PSEAER", # Pseudomonas aeruginosa "ENTAER"), # Enterobacter aerogenes diff --git a/tests/testthat/test-rsi_analysis.R b/tests/testthat/test-rsi_analysis.R index 1d5e48b3..3077987f 100644 --- a/tests/testthat/test-rsi_analysis.R +++ b/tests/testthat/test-rsi_analysis.R @@ -29,6 +29,21 @@ test_that("rsi works", { info = FALSE), 0.9858, tolerance = 0.0001) + + # count of cases + expect_equal(septic_patients %>% + group_by(hospital_id) %>% + summarise(cipro_S = rsi(cipr, interpretation = "S", + as_percent = TRUE, warning = FALSE), + cipro_n = n_rsi(cipr), + genta_S = rsi(gent, interpretation = "S", + as_percent = TRUE, warning = FALSE), + genta_n = n_rsi(gent), + combination_S = rsi(cipr, gent, interpretation = "S", + as_percent = TRUE, warning = FALSE), + combination_n = n_rsi(cipr, gent)) %>% + pull(combination_n), + c(138, 474, 170, 464, 183)) }) test_that("prediction of rsi works", {