new rsi_interpretation_history

This commit is contained in:
dr. M.S. (Matthijs) Berends 2022-09-01 15:20:57 +02:00
parent a3b97a10a5
commit 63fe160322
12 changed files with 191 additions and 171 deletions

View File

@ -1,6 +1,6 @@
Package: AMR
Version: 1.8.1.9047
Date: 2022-08-30
Version: 1.8.1.9049
Date: 2022-09-01
Title: Antimicrobial Resistance Data Analysis
Description: Functions to simplify and standardise antimicrobial resistance (AMR)
data analysis and to work with microbial and antimicrobial properties by

View File

@ -321,6 +321,7 @@ export(resistance)
export(resistance_predict)
export(right_join_microorganisms)
export(rsi_df)
export(rsi_interpretation_history)
export(rsi_predict)
export(scale_rsi_colours)
export(scale_y_percent)

View File

@ -1,8 +1,9 @@
# AMR 1.8.1.9047
# AMR 1.8.1.9049
### 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.
* Function to calculate the mean AMR distance: `mean_amr_distance()`. The mean AMR distance is a normalised numeric value to compare AMR test results and can help to identify similar isolates, without comparing antibiograms by hand.
* Function `mean_amr_distance()` to calculate the mean AMR distance. The mean AMR distance is a normalised numeric value to compare AMR test results and can help to identify similar isolates, without comparing antibiograms by hand.
* Function `rsi_interpretation_history()` to view the history of previous runs of `as.rsi()`. This returns a 'logbook' with the selected guideline, reference table and specific interpretation of each row in a data set on which `as.rsi()` was run.
* Support for `data.frame`-enhancing R packages, more specifically: `data.table`, `tibble`, and `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. Furthermore, all our data sets are now in `tibble` format.
* 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).
* 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.
@ -23,6 +24,7 @@
* 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
* 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
### Other
* New website to make use of the new Bootstrap 5 and pkgdown v2.0. The website now contains results for all examples and will be automatically regenerated with every change to our repository, using GitHub Actions

View File

@ -1062,10 +1062,10 @@ has_colour <- function() {
if ((cols <- Sys.getenv("RSTUDIO_CONSOLE_COLOR", "")) != "" && !is.na(as.double(cols))) {
return(TRUE)
}
tryCatch(get("isAvailable", envir = asNamespace("rstudioapi"))(), error = function(e) {
tryCatch(getExportedValue("isAvailable", ns = asNamespace("rstudioapi"))(), error = function(e) {
return(FALSE)
}) &&
tryCatch(get("hasFun", envir = asNamespace("rstudioapi"))("getConsoleHasColor"), error = function(e) {
tryCatch(getExportedValue("hasFun", ns = asNamespace("rstudioapi"))("getConsoleHasColor"), error = function(e) {
return(FALSE)
})
}
@ -1112,7 +1112,26 @@ try_colour <- function(..., before, after, collapse = " ") {
}
}
font_black <- function(..., collapse = " ") {
try_colour(..., before = "\033[38;5;232m", after = "\033[39m", collapse = collapse)
before <- "\033[38;5;232m"
after <- "\033[39m"
theme_info <- import_fn("getThemeInfo", "rstudioapi", error_on_fail = FALSE)
if (!is.null(theme_info) && isTRUE(theme_info()$dark)) {
# white
before <- "\033[37m"
after <- "\033[39m"
}
try_colour(..., before = before, after = after, collapse = collapse)
}
font_white <- function(..., collapse = " ") {
before <- "\033[37m"
after <- "\033[39m"
theme_info <- import_fn("getThemeInfo", "rstudioapi", error_on_fail = FALSE)
if (!is.null(theme_info) && isTRUE(theme_info()$dark)) {
# black
before <- "\033[38;5;232m"
after <- "\033[39m"
}
try_colour(..., before = before, after = after, collapse = collapse)
}
font_blue <- function(..., collapse = " ") {
try_colour(..., before = "\033[34m", after = "\033[39m", collapse = collapse)
@ -1129,9 +1148,6 @@ font_red <- function(..., collapse = " ") {
font_silver <- function(..., collapse = " ") {
try_colour(..., before = "\033[90m", after = "\033[39m", collapse = collapse)
}
font_white <- function(..., collapse = " ") {
try_colour(..., before = "\033[37m", after = "\033[39m", collapse = collapse)
}
font_yellow <- function(..., collapse = " ") {
try_colour(..., before = "\033[33m", after = "\033[39m", collapse = collapse)
}

189
R/rsi.R
View File

@ -52,16 +52,16 @@
#' your_data %>% mutate(across(where(is.mic), as.rsi)) # since dplyr 1.0.0
#' ```
#' * Operators like "<=" will be stripped before interpretation. When using `conserve_capped_values = TRUE`, an MIC value of e.g. ">2" will always return "R", even if the breakpoint according to the chosen guideline is ">=4". This is to prevent that capped values from raw laboratory data would not be treated conservatively. The default behaviour (`conserve_capped_values = FALSE`) considers ">2" to be lower than ">=4" and might in this case return "S" or "I".
#'
#' 3. For **interpreting disk diffusion diameters** according to EUCAST or CLSI. You must clean your disk zones first using [as.disk()], that also gives your columns the new data class [`disk`]. Also, be sure to have a column with microorganism names or codes. It will be found automatically, but can be set manually using the `mo` argument.
#' * Using `dplyr`, R/SI interpretation can be done very easily with either:
#' ```
#' your_data %>% mutate_if(is.disk, as.rsi) # until dplyr 1.0.0
#' your_data %>% mutate(across(where(is.disk), as.rsi)) # since dplyr 1.0.0
#' ```
#'
#' 4. For **interpreting a complete data set**, with automatic determination of MIC values, disk diffusion diameters, microorganism names or codes, and antimicrobial test results. This is done very simply by running `as.rsi(your_data)`.
#'
#' For points 2, 3 and 4: Use [rsi_interpretation_history()] to retrieve a [data.frame] (or [tibble][tibble::tibble()] if the `tibble` package is installed) with all results of the last [as.rsi()] call.
#'
#' ## Supported Guidelines
#'
#' For interpreting MIC values as well as disk diffusion diameters, currently implemented guidelines are EUCAST (`r min(as.integer(gsub("[^0-9]", "", subset(rsi_translation, guideline %like% "EUCAST")$guideline)))`-`r max(as.integer(gsub("[^0-9]", "", subset(rsi_translation, guideline %like% "EUCAST")$guideline)))`) and CLSI (`r min(as.integer(gsub("[^0-9]", "", subset(rsi_translation, guideline %like% "CLSI")$guideline)))`-`r max(as.integer(gsub("[^0-9]", "", subset(rsi_translation, guideline %like% "CLSI")$guideline)))`).
@ -110,11 +110,13 @@
#' CIP = as.mic(0.256),
#' GEN = as.disk(18),
#' TOB = as.disk(16),
#' NIT = as.mic(32),
#' ERY = "R"
#' )
#' as.rsi(df)
#'
#' # return a 'logbook' about the results:
#' rsi_interpretation_history()
#'
#' # for single values
#' as.rsi(
#' x = as.mic(2),
@ -553,34 +555,36 @@ as.rsi.data.frame <- function(x,
for (i in seq_len(length(ab_cols))) {
if (types[i] == "mic") {
x[, ab_cols[i]] <- as.rsi(
x = x %pm>%
pm_pull(ab_cols[i]) %pm>%
as.character() %pm>%
as.mic(),
mo = x_mo,
ab = ab_cols[i],
guideline = guideline,
uti = uti,
conserve_capped_values = conserve_capped_values,
add_intrinsic_resistance = add_intrinsic_resistance,
reference_data = reference_data,
is_data.frame = TRUE
)
x[, ab_cols[i]] <- x %pm>%
pm_pull(ab_cols[i]) %pm>%
as.character() %pm>%
as.mic() %pm>%
as.rsi(
mo = x_mo,
mo.bak = x[, col_mo, drop = TRUE],
ab = ab_cols[i],
guideline = guideline,
uti = uti,
conserve_capped_values = conserve_capped_values,
add_intrinsic_resistance = add_intrinsic_resistance,
reference_data = reference_data,
is_data.frame = TRUE
)
} else if (types[i] == "disk") {
x[, ab_cols[i]] <- as.rsi(
x = x %pm>%
pm_pull(ab_cols[i]) %pm>%
as.character() %pm>%
as.disk(),
mo = x_mo,
ab = ab_cols[i],
guideline = guideline,
uti = uti,
add_intrinsic_resistance = add_intrinsic_resistance,
reference_data = reference_data,
is_data.frame = TRUE
)
x[, ab_cols[i]] <- x %pm>%
pm_pull(ab_cols[i]) %pm>%
as.character() %pm>%
as.disk() %pm>%
as.rsi(
mo = x_mo,
mo.bak = x[, col_mo, drop = TRUE],
ab = ab_cols[i],
guideline = guideline,
uti = uti,
add_intrinsic_resistance = add_intrinsic_resistance,
reference_data = reference_data,
is_data.frame = TRUE
)
} else if (types[i] == "rsi") {
show_message <- FALSE
ab <- ab_cols[i]
@ -647,14 +651,14 @@ as_rsi_method <- function(method_short,
add_intrinsic_resistance,
reference_data,
...) {
meet_criteria(x, allow_NA = TRUE)
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = TRUE)
meet_criteria(ab, allow_class = c("ab", "character"))
meet_criteria(guideline, allow_class = "character", has_length = 1)
meet_criteria(uti, allow_class = "logical", has_length = c(1, length(x)))
meet_criteria(conserve_capped_values, allow_class = "logical", has_length = 1)
meet_criteria(add_intrinsic_resistance, allow_class = "logical", has_length = 1)
meet_criteria(reference_data, allow_class = "data.frame")
meet_criteria(x, allow_NA = TRUE, .call_depth = -2)
meet_criteria(mo, allow_class = c("mo", "character"), allow_NULL = TRUE, .call_depth = -2)
meet_criteria(ab, allow_class = c("ab", "character"), .call_depth = -2)
meet_criteria(guideline, allow_class = "character", has_length = 1, .call_depth = -2)
meet_criteria(uti, allow_class = "logical", has_length = c(1, length(x)), .call_depth = -2)
meet_criteria(conserve_capped_values, allow_class = "logical", has_length = 1, .call_depth = -2)
meet_criteria(add_intrinsic_resistance, allow_class = "logical", has_length = 1, .call_depth = -2)
meet_criteria(reference_data, allow_class = "data.frame", .call_depth = -2)
check_reference_data(reference_data)
# for dplyr's across()
@ -701,31 +705,37 @@ as_rsi_method <- function(method_short,
stop_("No unambiguous name was supplied about the antibiotic (argument `ab`). See ?as.rsi.", call = FALSE)
}
ab_coerced <- suppressWarnings(as.ab(ab))
mo_coerced <- suppressWarnings(as.mo(mo))
ab.bak <- ab
ab <- suppressWarnings(as.ab(ab))
if (!is.null(list(...)$mo.bak)) {
mo.bak <- list(...)$mo.bak
} else {
mo.bak <- mo
mo <- suppressWarnings(as.mo(mo))
}
guideline_coerced <- get_guideline(guideline, reference_data)
if (is.na(ab_coerced)) {
message_("Returning NAs for unknown drug: '", font_bold(ab),
if (is.na(ab)) {
message_("Returning NAs for unknown drug: '", font_bold(ab.bak),
"'. Rename this column to a drug name or code, and check the output with `as.ab()`.",
add_fn = font_red,
as_note = FALSE
)
return(as.rsi(rep(NA, length(x))))
}
if (length(mo_coerced) == 1) {
mo_coerced <- rep(mo_coerced, length(x))
if (length(mo) == 1) {
mo <- rep(mo, length(x))
}
if (length(uti) == 1) {
uti <- rep(uti, length(x))
}
agent_formatted <- paste0("'", font_bold(ab), "'")
agent_name <- ab_name(ab_coerced, tolower = TRUE, language = NULL)
agent_formatted <- paste0("'", font_bold(ab.bak), "'")
agent_name <- ab_name(ab, tolower = TRUE, language = NULL)
if (generalise_antibiotic_name(ab) != generalise_antibiotic_name(agent_name)) {
agent_formatted <- paste0(
agent_formatted,
" (", ifelse(ab == ab_coerced, "",
paste0(ab_coerced, ", ")
" (", ifelse(ab.bak == ab, "",
paste0(ab, ", ")
), agent_name, ")"
)
}
@ -740,29 +750,9 @@ as_rsi_method <- function(method_short,
appendLF = FALSE,
as_note = FALSE
)
result <- exec_as.rsi(
method = method_short,
x = x,
mo = mo_coerced,
ab = ab_coerced,
guideline = guideline_coerced,
uti = uti,
conserve_capped_values = conserve_capped_values,
add_intrinsic_resistance = add_intrinsic_resistance,
reference_data = reference_data
) # exec_as.rsi will return message 'OK'
result
}
exec_as.rsi <- function(method,
x,
mo,
ab,
guideline,
uti,
conserve_capped_values,
add_intrinsic_resistance,
reference_data) {
method <- method_short
metadata_mo <- get_mo_failures_uncertainties_renamed()
x_bak <- data.frame(x_mo = paste0(x, mo), stringsAsFactors = FALSE)
@ -795,13 +785,6 @@ exec_as.rsi <- function(method,
}
mo_other <- as.mo(rep("UNKNOWN", length(mo)))
guideline_coerced <- get_guideline(guideline, reference_data)
if (guideline_coerced != guideline) {
if (message_not_thrown_before("as.rsi", "guideline")) {
message_("Using guideline ", font_bold(guideline_coerced), " as input for `guideline`.")
}
}
new_rsi <- rep(NA_character_, length(x))
ab_param <- ab
@ -868,7 +851,7 @@ exec_as.rsi <- function(method,
lookup_other[i]
))
if (any(get_record$uti == TRUE, na.rm = TRUE) && !any(uti == TRUE, na.rm = TRUE) && message_not_thrown_before("as.rsi", "uti", ab_param)) {
if (any(nrow(get_record) == 1 && get_record$uti == TRUE, na.rm = TRUE) && !any(uti == TRUE, na.rm = TRUE) && message_not_thrown_before("as.rsi", "uti", ab_param)) {
warning_("in `as.rsi()`: interpretation of ", font_bold(ab_name(ab_param, tolower = TRUE)), " is only available for (uncomplicated) urinary tract infections (UTI) for some microorganisms. Use argument `uti` to set which isolates are from urine. See ?as.rsi.")
rise_warning <- TRUE
}
@ -913,6 +896,27 @@ exec_as.rsi <- function(method,
TRUE ~ NA_character_
)
}
# write to verbose output
pkg_env$rsi_interpretation_history <- rbind(
pkg_env$rsi_interpretation_history,
data.frame(
datetime = Sys.time(),
index = i,
ab_input = ab.bak[1],
ab_considered = ab[1],
mo_input = mo.bak[1],
mo_considered = mo[1],
guideline = guideline_coerced,
ref_table = get_record[, "ref_tbl", drop = TRUE],
method = method,
breakpoint_S = get_record[, "breakpoint_S", drop = TRUE],
breakpoint_R = get_record[, "breakpoint_R", drop = TRUE],
input = as.double(x[i]),
interpretation = new_rsi[i],
stringsAsFactors = FALSE
)
)
}
}
@ -946,6 +950,35 @@ exec_as.rsi <- function(method,
)
}
#' @rdname as.rsi
#' @param clean a [logical] to indicate whether previously stored results should be forgotten after returning the 'logbook' with results
#' @export
rsi_interpretation_history <- function(clean = FALSE) {
meet_criteria(clean, allow_class = "logical", has_length = 1)
out.bak <- pkg_env$rsi_interpretation_history
out <- out.bak
if (NROW(out) == 0) {
message_("No results to return. Run `as.rsi()` on MIC values or disk diffusion zones first to see a 'logbook' data set here.")
return(NULL)
}
out$ab_considered <- as.ab(out$ab_considered)
out$mo_considered <- as.mo(out$mo_considered)
out$interpretation <- as.rsi(out$interpretation)
# keep stored for next use
if (isTRUE(clean)) {
pkg_env$rsi_interpretation_history <- pkg_env$rsi_interpretation_history[0, , drop = FALSE]
} else {
pkg_env$rsi_interpretation_history <- out.bak
}
if (pkg_is_available("tibble", also_load = FALSE)) {
import_fn("as_tibble", "tibble")(out)
} else {
out
}
}
# will be exported using s3_register() in R/zzz.R
pillar_shaft.rsi <- function(x, ...) {
out <- trimws(format(x))

16
R/zzz.R
View File

@ -33,6 +33,22 @@ pkg_env$mo_field_abbreviations <- c(
"PRSP", "STEC", "UPEC", "VISA", "VISP", "VRE",
"VRSA", "VRSP"
)
pkg_env$rsi_interpretation_history <- data.frame(
datetime = Sys.time()[0],
index = integer(0),
ab_input = character(0),
ab_considered = character(0),
mo_input = character(0),
mo_considered = character(0),
guideline = character(0),
ref_table = character(0),
method = character(0),
breakpoint_S = double(0),
breakpoint_R = double(0),
input = double(0),
interpretation = character(0),
stringsAsFactors = FALSE
)
# determine info icon for messages
utf8_supported <- isTRUE(base::l10n_info()$`UTF-8`)

View File

@ -123,6 +123,10 @@ expect_equal(
c("S", "S", "I", "R", "R")
)
expect_true(is.data.frame(rsi_interpretation_history(clean = FALSE)))
expect_true(is.data.frame(rsi_interpretation_history(clean = TRUE)))
expect_true(is.null(rsi_interpretation_history()))
# cutoffs at MIC = 8
expect_equal(
as.rsi(as.mic(2), "E. coli", "ampicillin", guideline = "EUCAST 2020"),

View File

@ -10,6 +10,7 @@
\alias{as.rsi.mic}
\alias{as.rsi.disk}
\alias{as.rsi.data.frame}
\alias{rsi_interpretation_history}
\title{Interpret MIC and Disk Values, or Clean Raw R/SI Data}
\format{
An object of class \code{rsi} (inherits from \code{ordered}, \code{factor}) of length 1.
@ -56,6 +57,8 @@ is.rsi.eligible(x, threshold = 0.05)
add_intrinsic_resistance = FALSE,
reference_data = AMR::rsi_translation
)
rsi_interpretation_history(clean = FALSE)
}
\arguments{
\item{x}{vector of values (for class \code{\link{mic}}: MIC values in mg/L, for class \code{\link{disk}}: a disk diffusion radius in millimetres)}
@ -79,6 +82,8 @@ is.rsi.eligible(x, threshold = 0.05)
\item{reference_data}{a \link{data.frame} to be used for interpretation, which defaults to the \link{rsi_translation} data set. Changing this argument allows for using own interpretation guidelines. This argument must contain a data set that is equal in structure to the \link{rsi_translation} data set (same column names and column types). Please note that the \code{guideline} argument will be ignored when \code{reference_data} is manually set.}
\item{col_mo}{column name of the IDs of the microorganisms (see \code{\link[=as.mo]{as.mo()}}), defaults to the first column of class \code{\link{mo}}. Values will be coerced using \code{\link[=as.mo]{as.mo()}}.}
\item{clean}{a \link{logical} to indicate whether previously stored results should be forgotten after returning the 'logbook' with results}
}
\value{
Ordered \link{factor} with new class \verb{<rsi>}
@ -111,6 +116,8 @@ your_data \%>\% mutate(across(where(is.disk), as.rsi)) # since dplyr 1.0.0
}
\item For \strong{interpreting a complete data set}, with automatic determination of MIC values, disk diffusion diameters, microorganism names or codes, and antimicrobial test results. This is done very simply by running \code{as.rsi(your_data)}.
}
For points 2, 3 and 4: Use \code{\link[=rsi_interpretation_history]{rsi_interpretation_history()}} to retrieve a \link{data.frame} (or \link[tibble:tibble]{tibble} if the \code{tibble} package is installed) with all results of the last \code{\link[=as.rsi]{as.rsi()}} call.
}
\subsection{Supported Guidelines}{
@ -172,11 +179,13 @@ df <- data.frame(
CIP = as.mic(0.256),
GEN = as.disk(18),
TOB = as.disk(16),
NIT = as.mic(32),
ERY = "R"
)
as.rsi(df)
# return a 'logbook' about the results:
rsi_interpretation_history()
# for single values
as.rsi(
x = as.mic(2),

View File

@ -24,87 +24,43 @@ Some organisations have their own adoption of EUCAST rules. This function can be
If you are familiar with the \code{\link[dplyr:case_when]{case_when()}} function of the \code{dplyr} package, you will recognise the input method to set your own rules. Rules must be set using what \R considers to be the 'formula notation'. The rule itself is written \emph{before} the tilde (\code{~}) and the consequence of the rule is written \emph{after} the tilde:
\if{html}{\out{<div class="sourceCode r">}}\preformatted{x <- custom_eucast_rules(TZP == "S" ~ aminopenicillins == "S",
\if{html}{\out{<div class="sourceCode {r}">}}\preformatted{x <- custom_eucast_rules(TZP == "S" ~ aminopenicillins == "S",
TZP == "R" ~ aminopenicillins == "R")
}\if{html}{\out{</div>}}
These are two custom EUCAST rules: if TZP (piperacillin/tazobactam) is "S", all aminopenicillins (ampicillin and amoxicillin) must be made "S", and if TZP is "R", aminopenicillins must be made "R". These rules can also be printed to the console, so it is immediately clear how they work:
\if{html}{\out{<div class="sourceCode r">}}\preformatted{x
#> A set of custom EUCAST rules:
#>
#> 1. If TZP is "S" then set to S :
#> amoxicillin (AMX), ampicillin (AMP)
#>
#> 2. If TZP is "R" then set to R :
#> amoxicillin (AMX), ampicillin (AMP)
\if{html}{\out{<div class="sourceCode {r}">}}\preformatted{x
}\if{html}{\out{</div>}}
The rules (the part \emph{before} the tilde, in above example \code{TZP == "S"} and \code{TZP == "R"}) must be evaluable in your data set: it should be able to run as a filter in your data set without errors. This means for the above example that the column \code{TZP} must exist. We will create a sample data set and test the rules set:
\if{html}{\out{<div class="sourceCode r">}}\preformatted{df <- data.frame(mo = c("Escherichia coli", "Klebsiella pneumoniae"),
\if{html}{\out{<div class="sourceCode {r}">}}\preformatted{df <- data.frame(mo = c("Escherichia coli", "Klebsiella pneumoniae"),
TZP = as.rsi("R"),
ampi = as.rsi("S"),
cipro = as.rsi("S"))
df
#> mo TZP ampi cipro
#> 1 Escherichia coli R S S
#> 2 Klebsiella pneumoniae R S S
eucast_rules(df, rules = "custom", custom_rules = x, info = FALSE)
#> mo TZP ampi cipro
#> 1 Escherichia coli R R S
#> 2 Klebsiella pneumoniae R R S
}\if{html}{\out{</div>}}
}
\subsection{Using taxonomic properties in rules}{
There is one exception in variables used for the rules: all column names of the \link{microorganisms} data set can also be used, but do not have to exist in the data set. These column names are: "mo", "fullname", "kingdom", "phylum", "class", "order", "family", "genus", "species", "subspecies", "rank", "ref", "species_id", "source", "prevalence" and "snomed". Thus, this next example will work as well, despite the fact that the \code{df} data set does not contain a column \code{genus}:
There is one exception in variables used for the rules: all column names of the \link{microorganisms} data set can also be used, but do not have to exist in the data set. These column names are: \verb{r vector_and(colnames(microorganisms), sort = FALSE)}. Thus, this next example will work as well, despite the fact that the \code{df} data set does not contain a column \code{genus}:
\if{html}{\out{<div class="sourceCode r">}}\preformatted{y <- custom_eucast_rules(TZP == "S" & genus == "Klebsiella" ~ aminopenicillins == "S",
\if{html}{\out{<div class="sourceCode {r}">}}\preformatted{y <- custom_eucast_rules(TZP == "S" & genus == "Klebsiella" ~ aminopenicillins == "S",
TZP == "R" & genus == "Klebsiella" ~ aminopenicillins == "R")
eucast_rules(df, rules = "custom", custom_rules = y, info = FALSE)
#> mo TZP ampi cipro
#> 1 Escherichia coli R S S
#> 2 Klebsiella pneumoniae R R S
}\if{html}{\out{</div>}}
}
\subsection{Usage of antibiotic group names}{
It is possible to define antibiotic groups instead of single antibiotics for the rule consequence, the part \emph{after} the tilde. In above examples, the antibiotic group \code{aminopenicillins} is used to include ampicillin and amoxicillin. The following groups are allowed (case-insensitive). Within parentheses are the agents that will be matched when running the rule.
\itemize{
\item "aminoglycosides"\cr(amikacin, amikacin/fosfomycin, amphotericin B-high, apramycin, arbekacin, astromicin, bekanamycin, dibekacin, framycetin, gentamicin, gentamicin-high, habekacin, hygromycin, isepamicin, kanamycin, kanamycin-high, kanamycin/cephalexin, micronomicin, neomycin, netilmicin, pentisomicin, plazomicin, propikacin, ribostamycin, sisomicin, streptoduocin, streptomycin, streptomycin-high, tobramycin and tobramycin-high)
\item "aminopenicillins"\cr(amoxicillin and ampicillin)
\item "antifungals"\cr(5-fluorocytosine, amphotericin B, anidulafungin, butoconazole, caspofungin, ciclopirox, clotrimazole, econazole, fluconazole, fosfluconazole, griseofulvin, hachimycin, ibrexafungerp, isavuconazole, isoconazole, itraconazole, ketoconazole, manogepix, micafungin, miconazole, nystatin, pimaricin, posaconazole, rezafungin, ribociclib, sulconazole, terbinafine, terconazole and voriconazole)
\item "antimycobacterials"\cr(4-aminosalicylic acid, calcium aminosalicylate, capreomycin, clofazimine, delamanid, enviomycin, ethambutol, ethambutol/isoniazid, ethionamide, isoniazid, morinamide, p-aminosalicylic acid, pretomanid, prothionamide, pyrazinamide, rifabutin, rifampicin, rifampicin/isoniazid, rifampicin/pyrazinamide/ethambutol/isoniazid, rifampicin/pyrazinamide/isoniazid, rifamycin, rifapentine, simvastatin/fenofibrate, sodium aminosalicylate, streptomycin/isoniazid, terizidone, thioacetazone/isoniazid, tiocarlide and viomycin)
\item "betalactams"\cr(amoxicillin, amoxicillin/clavulanic acid, amoxicillin/sulbactam, ampicillin, ampicillin/sulbactam, apalcillin, aspoxicillin, avibactam, azidocillin, azlocillin, aztreonam, aztreonam/avibactam, aztreonam/nacubactam, bacampicillin, benzathine benzylpenicillin, benzathine phenoxymethylpenicillin, benzylpenicillin, biapenem, carbenicillin, carindacillin, cefacetrile, cefaclor, cefadroxil, cefaloridine, cefamandole, cefatrizine, cefazedone, cefazolin, cefcapene, cefcapene pivoxil, cefdinir, cefditoren, cefditoren pivoxil, cefepime, cefepime/clavulanic acid, cefepime/nacubactam, cefepime/tazobactam, cefetamet, cefetamet pivoxil, cefetecol, cefetrizole, cefixime, cefmenoxime, cefmetazole, cefodizime, cefonicid, cefoperazone, cefoperazone/sulbactam, ceforanide, cefoselis, cefotaxime, cefotaxime/clavulanic acid, cefotaxime/sulbactam, cefotetan, cefotiam, cefotiam hexetil, cefovecin, cefoxitin, cefoxitin screening, cefozopran, cefpimizole, cefpiramide, cefpirome, cefpodoxime, cefpodoxime proxetil, cefpodoxime/clavulanic acid, cefprozil, cefquinome, cefroxadine, cefsulodin, cefsumide, ceftaroline, ceftaroline/avibactam, ceftazidime, ceftazidime/avibactam, ceftazidime/clavulanic acid, cefteram, cefteram pivoxil, ceftezole, ceftibuten, ceftiofur, ceftizoxime, ceftizoxime alapivoxil, ceftobiprole, ceftobiprole medocaril, ceftolozane/enzyme inhibitor, ceftolozane/tazobactam, ceftriaxone, cefuroxime, cefuroxime axetil, cephalexin, cephalothin, cephapirin, cephradine, ciclacillin, clometocillin, cloxacillin, dicloxacillin, doripenem, epicillin, ertapenem, flucloxacillin, hetacillin, imipenem, imipenem/EDTA, imipenem/relebactam, latamoxef, lenampicillin, loracarbef, mecillinam, meropenem, meropenem/nacubactam, meropenem/vaborbactam, metampicillin, methicillin, mezlocillin, mezlocillin/sulbactam, nacubactam, nafcillin, oxacillin, panipenem, penamecillin, penicillin/novobiocin, penicillin/sulbactam, phenethicillin, phenoxymethylpenicillin, piperacillin, piperacillin/sulbactam, piperacillin/tazobactam, piridicillin, pivampicillin, pivmecillinam, procaine benzylpenicillin, propicillin, razupenem, ritipenem, ritipenem acoxil, sarmoxicillin, sulbactam, sulbenicillin, sultamicillin, talampicillin, tazobactam, tebipenem, temocillin, ticarcillin and ticarcillin/clavulanic acid)
\item "carbapenems"\cr(biapenem, doripenem, ertapenem, imipenem, imipenem/EDTA, imipenem/relebactam, meropenem, meropenem/nacubactam, meropenem/vaborbactam, panipenem, razupenem, ritipenem, ritipenem acoxil and tebipenem)
\item "cephalosporins"\cr(cefacetrile, cefaclor, cefadroxil, cefaloridine, cefamandole, cefatrizine, cefazedone, cefazolin, cefcapene, cefcapene pivoxil, cefdinir, cefditoren, cefditoren pivoxil, cefepime, cefepime/clavulanic acid, cefepime/tazobactam, cefetamet, cefetamet pivoxil, cefetecol, cefetrizole, cefixime, cefmenoxime, cefmetazole, cefodizime, cefonicid, cefoperazone, cefoperazone/sulbactam, ceforanide, cefoselis, cefotaxime, cefotaxime/clavulanic acid, cefotaxime/sulbactam, cefotetan, cefotiam, cefotiam hexetil, cefovecin, cefoxitin, cefoxitin screening, cefozopran, cefpimizole, cefpiramide, cefpirome, cefpodoxime, cefpodoxime proxetil, cefpodoxime/clavulanic acid, cefprozil, cefquinome, cefroxadine, cefsulodin, cefsumide, ceftaroline, ceftaroline/avibactam, ceftazidime, ceftazidime/avibactam, ceftazidime/clavulanic acid, cefteram, cefteram pivoxil, ceftezole, ceftibuten, ceftiofur, ceftizoxime, ceftizoxime alapivoxil, ceftobiprole, ceftobiprole medocaril, ceftolozane/enzyme inhibitor, ceftolozane/tazobactam, ceftriaxone, cefuroxime, cefuroxime axetil, cephalexin, cephalothin, cephapirin, cephradine, latamoxef and loracarbef)
\item "cephalosporins_1st"\cr(cefacetrile, cefadroxil, cefaloridine, cefatrizine, cefazedone, cefazolin, cefroxadine, ceftezole, cephalexin, cephalothin, cephapirin and cephradine)
\item "cephalosporins_2nd"\cr(cefaclor, cefamandole, cefmetazole, cefonicid, ceforanide, cefotetan, cefotiam, cefoxitin, cefoxitin screening, cefprozil, cefuroxime, cefuroxime axetil and loracarbef)
\item "cephalosporins_3rd"\cr(cefcapene, cefcapene pivoxil, cefdinir, cefditoren, cefditoren pivoxil, cefetamet, cefetamet pivoxil, cefixime, cefmenoxime, cefodizime, cefoperazone, cefoperazone/sulbactam, cefotaxime, cefotaxime/clavulanic acid, cefotaxime/sulbactam, cefotiam hexetil, cefovecin, cefpimizole, cefpiramide, cefpodoxime, cefpodoxime proxetil, cefpodoxime/clavulanic acid, cefsulodin, ceftazidime, ceftazidime/avibactam, ceftazidime/clavulanic acid, cefteram, cefteram pivoxil, ceftibuten, ceftiofur, ceftizoxime, ceftizoxime alapivoxil, ceftriaxone and latamoxef)
\item "cephalosporins_4th"\cr(cefepime, cefepime/clavulanic acid, cefepime/tazobactam, cefetecol, cefoselis, cefozopran, cefpirome and cefquinome)
\item "cephalosporins_5th"\cr(ceftaroline, ceftaroline/avibactam, ceftobiprole, ceftobiprole medocaril, ceftolozane/enzyme inhibitor and ceftolozane/tazobactam)
\item "cephalosporins_except_caz"\cr(cefacetrile, cefaclor, cefadroxil, cefaloridine, cefamandole, cefatrizine, cefazedone, cefazolin, cefcapene, cefcapene pivoxil, cefdinir, cefditoren, cefditoren pivoxil, cefepime, cefepime/clavulanic acid, cefepime/tazobactam, cefetamet, cefetamet pivoxil, cefetecol, cefetrizole, cefixime, cefmenoxime, cefmetazole, cefodizime, cefonicid, cefoperazone, cefoperazone/sulbactam, ceforanide, cefoselis, cefotaxime, cefotaxime/clavulanic acid, cefotaxime/sulbactam, cefotetan, cefotiam, cefotiam hexetil, cefovecin, cefoxitin, cefoxitin screening, cefozopran, cefpimizole, cefpiramide, cefpirome, cefpodoxime, cefpodoxime proxetil, cefpodoxime/clavulanic acid, cefprozil, cefquinome, cefroxadine, cefsulodin, cefsumide, ceftaroline, ceftaroline/avibactam, ceftazidime/avibactam, ceftazidime/clavulanic acid, cefteram, cefteram pivoxil, ceftezole, ceftibuten, ceftiofur, ceftizoxime, ceftizoxime alapivoxil, ceftobiprole, ceftobiprole medocaril, ceftolozane/enzyme inhibitor, ceftolozane/tazobactam, ceftriaxone, cefuroxime, cefuroxime axetil, cephalexin, cephalothin, cephapirin, cephradine, latamoxef and loracarbef)
\item "fluoroquinolones"\cr(besifloxacin, ciprofloxacin, clinafloxacin, danofloxacin, delafloxacin, difloxacin, enoxacin, enrofloxacin, finafloxacin, fleroxacin, garenoxacin, gatifloxacin, gemifloxacin, grepafloxacin, levofloxacin, levonadifloxacin, lomefloxacin, marbofloxacin, metioxate, miloxacin, moxifloxacin, nadifloxacin, nifuroquine, norfloxacin, ofloxacin, orbifloxacin, pazufloxacin, pefloxacin, pradofloxacin, premafloxacin, prulifloxacin, rufloxacin, sarafloxacin, sitafloxacin, sparfloxacin, temafloxacin, tilbroquinol, tioxacin, tosufloxacin and trovafloxacin)
\item "glycopeptides"\cr(avoparcin, dalbavancin, norvancomycin, oritavancin, ramoplanin, teicoplanin, teicoplanin-macromethod, telavancin, vancomycin and vancomycin-macromethod)
\item "glycopeptides_except_lipo"\cr(avoparcin, norvancomycin, ramoplanin, teicoplanin, teicoplanin-macromethod, vancomycin and vancomycin-macromethod)
\item "lincosamides"\cr(acetylmidecamycin, acetylspiramycin, clindamycin, gamithromycin, kitasamycin, lincomycin, meleumycin, nafithromycin, pirlimycin, primycin, solithromycin, tildipirosin, tilmicosin, tulathromycin, tylosin and tylvalosin)
\item "lipoglycopeptides"\cr(dalbavancin, oritavancin and telavancin)
\item "macrolides"\cr(acetylmidecamycin, acetylspiramycin, azithromycin, clarithromycin, dirithromycin, erythromycin, flurithromycin, gamithromycin, josamycin, kitasamycin, meleumycin, midecamycin, miocamycin, nafithromycin, oleandomycin, pirlimycin, primycin, rokitamycin, roxithromycin, solithromycin, spiramycin, telithromycin, tildipirosin, tilmicosin, troleandomycin, tulathromycin, tylosin and tylvalosin)
\item "oxazolidinones"\cr(cadazolid, cycloserine, linezolid, tedizolid and thiacetazone)
\item "penicillins"\cr(amoxicillin, amoxicillin/clavulanic acid, amoxicillin/sulbactam, ampicillin, ampicillin/sulbactam, apalcillin, aspoxicillin, avibactam, azidocillin, azlocillin, aztreonam, aztreonam/avibactam, aztreonam/nacubactam, bacampicillin, benzathine benzylpenicillin, benzathine phenoxymethylpenicillin, benzylpenicillin, carbenicillin, carindacillin, cefepime/nacubactam, ciclacillin, clometocillin, cloxacillin, dicloxacillin, epicillin, flucloxacillin, hetacillin, lenampicillin, mecillinam, metampicillin, methicillin, mezlocillin, mezlocillin/sulbactam, nacubactam, nafcillin, oxacillin, penamecillin, penicillin/novobiocin, penicillin/sulbactam, phenethicillin, phenoxymethylpenicillin, piperacillin, piperacillin/sulbactam, piperacillin/tazobactam, piridicillin, pivampicillin, pivmecillinam, procaine benzylpenicillin, propicillin, sarmoxicillin, sulbactam, sulbenicillin, sultamicillin, talampicillin, tazobactam, temocillin, ticarcillin and ticarcillin/clavulanic acid)
\item "polymyxins"\cr(colistin, polymyxin B and polymyxin B/polysorbate 80)
\item "quinolones"\cr(besifloxacin, cinoxacin, ciprofloxacin, clinafloxacin, danofloxacin, delafloxacin, difloxacin, enoxacin, enrofloxacin, finafloxacin, fleroxacin, flumequine, garenoxacin, gatifloxacin, gemifloxacin, grepafloxacin, levofloxacin, levonadifloxacin, lomefloxacin, marbofloxacin, metioxate, miloxacin, moxifloxacin, nadifloxacin, nalidixic acid, nifuroquine, nitroxoline, norfloxacin, ofloxacin, orbifloxacin, oxolinic acid, pazufloxacin, pefloxacin, pipemidic acid, piromidic acid, pradofloxacin, premafloxacin, prulifloxacin, rosoxacin, rufloxacin, sarafloxacin, sitafloxacin, sparfloxacin, temafloxacin, tilbroquinol, tioxacin, tosufloxacin and trovafloxacin)
\item "streptogramins"\cr(pristinamycin and quinupristin/dalfopristin)
\item "tetracyclines"\cr(cetocycline, chlortetracycline, clomocycline, demeclocycline, doxycycline, eravacycline, lymecycline, metacycline, minocycline, omadacycline, oxytetracycline, penimepicycline, rolitetracycline, tetracycline and tigecycline)
\item "tetracyclines_except_tgc"\cr(cetocycline, chlortetracycline, clomocycline, demeclocycline, doxycycline, eravacycline, lymecycline, metacycline, minocycline, omadacycline, oxytetracycline, penimepicycline, rolitetracycline and tetracycline)
\item "trimethoprims"\cr(brodimoprim, sulfadiazine, sulfadiazine/tetroxoprim, sulfadiazine/trimethoprim, sulfadimethoxine, sulfadimidine, sulfadimidine/trimethoprim, sulfafurazole, sulfaisodimidine, sulfalene, sulfamazone, sulfamerazine, sulfamerazine/trimethoprim, sulfamethizole, sulfamethoxazole, sulfamethoxypyridazine, sulfametomidine, sulfametoxydiazine, sulfametrole/trimethoprim, sulfamoxole, sulfamoxole/trimethoprim, sulfanilamide, sulfaperin, sulfaphenazole, sulfapyridine, sulfathiazole, sulfathiourea, trimethoprim and trimethoprim/sulfamethoxazole)
\item "ureidopenicillins"\cr(azlocillin, mezlocillin, piperacillin and piperacillin/tazobactam)
}
\verb{r paste0(" * ", sapply(DEFINED_AB_GROUPS, function(x) paste0("\\"", tolower(gsub("^AB_", "", x)), "\\"\\\\cr(", vector_and(ab_name(eval(parse(text = x), envir = asNamespace("AMR")), language = NULL, tolower = TRUE), quotes = FALSE), ")"), USE.NAMES = FALSE), "\\n", collapse = "")}
}
}

View File

@ -74,36 +74,15 @@ To improve the interpretation of the antibiogram before EUCAST rules are applied
\strong{Note:} This function does not translate MIC values to RSI values. Use \code{\link[=as.rsi]{as.rsi()}} for that. \cr
\strong{Note:} When ampicillin (AMP, J01CA01) is not available but amoxicillin (AMX, J01CA04) is, the latter will be used for all rules where there is a dependency on ampicillin. These drugs are interchangeable when it comes to expression of antimicrobial resistance. \cr
The file containing all EUCAST rules is located here: \url{https://github.com/msberends/AMR/blob/main/data-raw/eucast_rules.tsv}. \strong{Note:} Old taxonomic names are replaced with the current taxonomy where applicable. For example, \emph{Ochrobactrum anthropi} was renamed to \emph{Brucella anthropi} in 2020; the original EUCAST rules v3.1 and v3.2 did not yet contain this new taxonomic name. The file used as input for this \code{AMR} package contains the taxonomy updated until \link[=catalogue_of_life]{5 October 2021}.
The file containing all EUCAST rules is located here: \url{https://github.com/msberends/AMR/blob/main/data-raw/eucast_rules.tsv}. \strong{Note:} Old taxonomic names are replaced with the current taxonomy where applicable. For example, \emph{Ochrobactrum anthropi} was renamed to \emph{Brucella anthropi} in 2020; the original EUCAST rules v3.1 and v3.2 did not yet contain this new taxonomic name. The file used as input for this \code{AMR} package contains the taxonomy updated until \code{\link[=catalogue_of_life]{r CATALOGUE_OF_LIFE$yearmonth_LPSN}}.
\subsection{Custom Rules}{
Custom rules can be created using \code{\link[=custom_eucast_rules]{custom_eucast_rules()}}, e.g.:
\if{html}{\out{<div class="sourceCode r">}}\preformatted{x <- custom_eucast_rules(AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
\if{html}{\out{<div class="sourceCode {r}">}}\preformatted{x <- custom_eucast_rules(AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
AMC == "I" & genus == "Klebsiella" ~ aminopenicillins == "I")
eucast_rules(example_isolates, rules = "custom", custom_rules = x, info = FALSE)
#> # A tibble: 2,000 x 46
#> date patient age gender ward mo PEN OXA FLC AMX
#> * <date> <chr> <dbl> <chr> <chr> <mo> <rsi> <rsi> <rsi> <rsi>
#> 1 2002-01-02 A77334 65 F Clinical B_ESCHR_COLI R NA NA NA
#> 2 2002-01-03 A77334 65 F Clinical B_ESCHR_COLI R NA NA NA
#> 3 2002-01-07 067927 45 F ICU B_STPHY_EPDR R NA R NA
#> 4 2002-01-07 067927 45 F ICU B_STPHY_EPDR R NA R NA
#> 5 2002-01-13 067927 45 F ICU B_STPHY_EPDR R NA R NA
#> 6 2002-01-13 067927 45 F ICU B_STPHY_EPDR R NA R NA
#> 7 2002-01-14 462729 78 M Clinical B_STPHY_AURS R NA S R
#> 8 2002-01-14 462729 78 M Clinical B_STPHY_AURS R NA S R
#> 9 2002-01-16 067927 45 F ICU B_STPHY_EPDR R NA R NA
#> 10 2002-01-17 858515 79 F ICU B_STPHY_EPDR R NA S NA
#> # ... with 1,990 more rows, and 36 more variables: AMC <rsi>, AMP <rsi>,
#> # TZP <rsi>, CZO <rsi>, FEP <rsi>, CXM <rsi>, FOX <rsi>, CTX <rsi>,
#> # CAZ <rsi>, CRO <rsi>, GEN <rsi>, TOB <rsi>, AMK <rsi>, KAN <rsi>,
#> # TMP <rsi>, SXT <rsi>, NIT <rsi>, FOS <rsi>, LNZ <rsi>, CIP <rsi>,
#> # MFX <rsi>, VAN <rsi>, TEC <rsi>, TCY <rsi>, TGC <rsi>, DOX <rsi>,
#> # ERY <rsi>, CLI <rsi>, AZM <rsi>, IPM <rsi>, MEM <rsi>, MTR <rsi>,
#> # CHL <rsi>, COL <rsi>, MUP <rsi>, RIF <rsi>
#> # i Use `print(n = ...)` to see more rows, and `colnames()` to see all variable names
}\if{html}{\out{</div>}}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

View File

@ -59,20 +59,24 @@ x <- random_mic(10)
x
mean_amr_distance(x)
y <- data.frame(id = LETTERS[1:10],
amox = random_mic(10, ab = "amox", mo = "Escherichia coli"),
cipr = random_mic(10, ab = "cipr", mo = "Escherichia coli"),
gent = random_mic(10, ab = "gent", mo = "Escherichia coli"),
tobr = random_mic(10, ab = "tobr", mo = "Escherichia coli"))
y <- data.frame(
id = LETTERS[1:10],
amox = random_mic(10, ab = "amox", mo = "Escherichia coli"),
cipr = random_mic(10, ab = "cipr", mo = "Escherichia coli"),
gent = random_mic(10, ab = "gent", mo = "Escherichia coli"),
tobr = random_mic(10, ab = "tobr", mo = "Escherichia coli")
)
y
mean_amr_distance(y)
y$amr_distance <- mean_amr_distance(y, where(is.mic))
y[order(y$amr_distance), ]
if (require("dplyr")) {
y \%>\%
mutate(amr_distance = mean_amr_distance(., where(is.mic)),
check_id_C = distance_from_row(amr_distance, id == "C")) \%>\%
y \%>\%
mutate(
amr_distance = mean_amr_distance(., where(is.mic)),
check_id_C = distance_from_row(amr_distance, id == "C")
) \%>\%
arrange(check_id_C)
}
if (require("dplyr")) {