mirror of
https://github.com/msberends/AMR.git
synced 2026-05-31 19:41:51 +02:00
Compare commits
3 Commits
claude/upd
...
cd23422a5f
| Author | SHA1 | Date | |
|---|---|---|---|
| cd23422a5f | |||
|
|
e981d5227d | ||
|
|
1d48012355 |
@@ -41,5 +41,4 @@
|
||||
^CRAN-SUBMISSION$
|
||||
^PythonPackage$
|
||||
^README\.Rmd$
|
||||
^tools$
|
||||
\.no_include$
|
||||
|
||||
@@ -167,8 +167,7 @@ Then run the following from the repo root to determine the version string to use
|
||||
currenttag=$(git describe --tags --abbrev=0 | sed 's/v//')
|
||||
currenttagfull=$(git describe --tags --abbrev=0)
|
||||
defaultbranch=$(git branch | cut -c 3- | grep -E '^master$|^main$')
|
||||
git fetch origin ${defaultbranch} --quiet
|
||||
currentcommit=$(git rev-list --count ${currenttagfull}..origin/${defaultbranch})
|
||||
currentcommit=$(git rev-list --count ${currenttagfull}..${defaultbranch})
|
||||
currentversion="${currenttag}.$((currentcommit + 9001 + 1))"
|
||||
echo "$currentversion"
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package: AMR
|
||||
Version: 3.0.1.9059
|
||||
Date: 2026-05-06
|
||||
Version: 3.0.1.9045
|
||||
Date: 2026-04-05
|
||||
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
|
||||
@@ -37,18 +37,17 @@ Authors@R: c(
|
||||
person(given = c("Casper", "J."), family = "Albers", role = "ths", comment = c(ORCID = "0000-0002-9213-6743")),
|
||||
person(given = c("Corinna"), family = "Glasner", role = "ths", comment = c(ORCID = "0000-0003-1241-1328")))
|
||||
Depends: R (>= 3.0.0)
|
||||
Suggests:
|
||||
Suggests:
|
||||
cleaner,
|
||||
cli,
|
||||
crayon,
|
||||
curl,
|
||||
data.table,
|
||||
dplyr,
|
||||
future,
|
||||
future.apply,
|
||||
ggplot2,
|
||||
knitr,
|
||||
openxlsx,
|
||||
parallelly,
|
||||
pillar,
|
||||
progress,
|
||||
readxl,
|
||||
|
||||
@@ -49,7 +49,6 @@ S3method(as.data.frame,mo)
|
||||
S3method(as.double,mic)
|
||||
S3method(as.double,sir)
|
||||
S3method(as.list,custom_eucast_rules)
|
||||
S3method(as.list,custom_interpretive_rules)
|
||||
S3method(as.list,custom_mdro_guideline)
|
||||
S3method(as.list,mic)
|
||||
S3method(as.matrix,mic)
|
||||
@@ -67,7 +66,6 @@ S3method(c,ab)
|
||||
S3method(c,amr_selector)
|
||||
S3method(c,av)
|
||||
S3method(c,custom_eucast_rules)
|
||||
S3method(c,custom_interpretive_rules)
|
||||
S3method(c,custom_mdro_guideline)
|
||||
S3method(c,disk)
|
||||
S3method(c,mic)
|
||||
@@ -98,7 +96,6 @@ S3method(print,amr_selector)
|
||||
S3method(print,av)
|
||||
S3method(print,bug_drug_combinations)
|
||||
S3method(print,custom_eucast_rules)
|
||||
S3method(print,custom_interpretive_rules)
|
||||
S3method(print,custom_mdro_guideline)
|
||||
S3method(print,deprecated_amr_dataset)
|
||||
S3method(print,disk)
|
||||
@@ -231,7 +228,6 @@ export(count_df)
|
||||
export(count_resistant)
|
||||
export(count_susceptible)
|
||||
export(custom_eucast_rules)
|
||||
export(custom_interpretive_rules)
|
||||
export(custom_mdro_guideline)
|
||||
export(eucast_dosage)
|
||||
export(eucast_exceptional_phenotypes)
|
||||
@@ -300,7 +296,6 @@ export(mo_is_yeast)
|
||||
export(mo_kingdom)
|
||||
export(mo_lpsn)
|
||||
export(mo_matching_score)
|
||||
export(mo_morphology)
|
||||
export(mo_mycobank)
|
||||
export(mo_name)
|
||||
export(mo_order)
|
||||
|
||||
74
NEWS.md
74
NEWS.md
@@ -1,38 +1,54 @@
|
||||
# AMR 3.0.1.9059
|
||||
|
||||
Planned as v3.1.0, May 2026.
|
||||
# AMR 3.0.1.9045
|
||||
|
||||
### New
|
||||
* EUCAST 2026 and CLSI 2026 breakpoints: over 5,700 new breakpoints added to the `clinical_breakpoints` data set; EUCAST 2026 is now the default for all MIC and disk diffusion interpretations
|
||||
* Wildtype/Non-wildtype (WT/NWT) output when using ECOFF-based interpretation, by setting `breakpoint_type = "ECOFF"` in `as.sir()`; WT/NWT results are fully supported in all resistance/susceptibility functions and plots (#254)
|
||||
* Faster parallel computing via the `future` package; **breaking change**: a non-sequential plan (e.g. `future::plan(future::multisession)`) must be active before using `parallel = TRUE`; `antibiogram()` and `wisca()` now also support `parallel = TRUE` (#281)
|
||||
* *tidymodels* integration for using SIR, MIC and disk data in modelling pipelines: `step_mic_log2()`, `step_sir_numeric()`, and new column selectors `all_sir()`, `all_mic()`, `all_disk()`
|
||||
* New `esbl_isolates` data set for practising AMR modelling
|
||||
* New antimicrobial selectors: `ionophores()`, `peptides()`, `phosphonics()`, `spiropyrimidinetriones()`
|
||||
* New `interpretive_rules()`, a unified function for EUCAST and CLSI interpretive rules; `eucast_rules()` is now a wrapper around it (#235, #259)
|
||||
* New `amr_course()` to download and unpack course or webinar materials from GitHub in one call
|
||||
* Typed missing value constants `NA_ab_` and `NA_mo_`, for use in pipelines that need missing values of a specific class
|
||||
* Support for clinical breakpoints of 2026 of both CLSI and EUCAST, by adding all of their over 5,700 new clinical breakpoints to the `clinical_breakpoints` data set for usage in `as.sir()`. EUCAST 2026 is now the new default guideline for all MIC and disk diffusion interpretations.
|
||||
* Integration with the **tidymodels** framework to allow seamless use of SIR, MIC and disk data in modelling pipelines via `recipes`
|
||||
- `step_mic_log2()` to transform `<mic>` columns with log2, and `step_sir_numeric()` to convert `<sir>` columns to numeric
|
||||
- New `tidyselect` helpers:
|
||||
- `all_sir()`, `all_sir_predictors()`
|
||||
- `all_mic()`, `all_mic_predictors()`
|
||||
- `all_disk()`, `all_disk_predictors()`
|
||||
* Data set `esbl_isolates` to practise with AMR modelling
|
||||
* AMR selectors `ionophores()`, `peptides()`, `phosphonics()` and `spiropyrimidinetriones()`
|
||||
* Support for Wildtype (WT) / Non-wildtype (NWT) in `as.sir()`, all plotting functions, and all susceptibility/resistance functions.
|
||||
- `as.sir()` gained an argument `as_wt_nwt`, which defaults to `TRUE` only when `breakpoint_type = "ECOFF"` (#254)
|
||||
- This transforms the output from S/R to WT/NWT
|
||||
- Functions such as `susceptibility()` count WT as S and NWT as R
|
||||
* Function `interpretive_rules()`, which allows future implementation of CLSI interpretive rules (#235)
|
||||
- `eucast_rules()` has become a wrapper around that function
|
||||
- Gained argument `add_if_missing` (default: `TRUE`). When set to `FALSE`, rules are only applied to cells that already contain an SIR value; `NA` cells are left untouched. This is useful with `overwrite = TRUE` to update reported results without imputing values for drugs that were not tested (#259)
|
||||
* Function `amr_course()`, which allows for automated download and unpacking of a GitHub repository for e.g. webinar use
|
||||
* Two new `NA` objects, `NA_ab_` and `NA_mo_`, analogous to base R's `NA_character_` and `NA_integer_`, for use in pipelines that require typed missing values
|
||||
|
||||
### Fixes
|
||||
* `as.sir()` on data frames: already-converted SIR columns no longer dropped on re-run (#278); metadata columns (e.g. `patient`, `ward`) no longer misidentified as antibiotic columns; `info = FALSE` now suppresses all messages, including for columns without breakpoints
|
||||
* `as.mic()`: values in scientific notation (e.g. `1e-3`) now handled correctly
|
||||
* `as.ab()`: codes containing "PH" or "TH" (e.g. `ETH`, `PHE`) no longer return `NA` when mixed with unrecognised input (#245)
|
||||
* Combined MIC/SIR input values (e.g. `"<= 0.002; S"` or `"S; 0.002"`) now parsed correctly (#252)
|
||||
* `as.mo()`: input of the form `"X complex"` now falls back to `"X"` when the complex is not a distinct taxon in the database, preventing `NA` results for valid clinical descriptions such as `"Proteus vulgaris complex"` (#287)
|
||||
* `mo_matching_score()`: abbreviated-genus input (e.g. `"S. apiospermum"`) now correctly ranks candidates whose species epithet exactly matches the input above more-prevalent organisms whose species does not match; fixes `"S. apiospermum"` resolving to *Staphylococcus* instead of *Scedosporium apiospermum* (#288)
|
||||
* `get_author_year()` in the microorganism reproduction script now strips `emend.` and everything after it, so `ref` reflects the combination authority rather than the emendation author (e.g. *Rhodococcus equi* now returns "Goodfellow et al., 1977" instead of "Nouioui et al., 2018")
|
||||
* BRMO classification now includes bacterial complexes (#275)
|
||||
* Translation fixes for Italian CoNS/CoPS names (#256), Dutch antimicrobials, and `sir_df()` foreign-language output (#272)
|
||||
* Fixed a bug in `as.sir()` where values that were purely numeric (e.g., `"1"`) and matched the broad SIR-matching regex would be incorrectly stripped of all content by the Unicode letter filter
|
||||
* Fixed a bug in `as.mic()` where MIC values in scientific notation (e.g., `"1e-3"`) were incorrectly handled because the letter `e` was removed along with other Unicode letters; scientific notation `e` is now preserved
|
||||
* Fixed a bug in `as.ab()` where certain AB codes containing "PH" or "TH" (such as `ETH`, `MTH`, `PHE`, `PHN`, `STH`, `THA`, `THI1`) would incorrectly return `NA` when combined in a vector with any untranslatable value (#245)
|
||||
* Fixed a bug in `antibiogram()` for when no antimicrobials are set
|
||||
* Fixed a bug in `as.sir()` where for numeric input the arguments `S`, `I`, and `R` would not be considered (#244)
|
||||
* Fixed a bug in plotting MIC values when `keep_operators = "all"`
|
||||
* Fixed some foreign translations of antimicrobial drugs
|
||||
* Fixed a bug for printing column names to the console when using `mutate_at(vars(...), as.mic)` (#249)
|
||||
* Fixed a bug to disregard `NI` for susceptibility proportion functions
|
||||
* Fixed Italian translation of CoNS to Stafilococco coagulasi-negativo and CoPS to Stafilococco coagulasi-positivo (#256)
|
||||
* Fixed SIR and MIC coercion of combined values, e.g. `as.sir("<= 0.002; S") ` or `as.mic("S; 0.002")` (#252)
|
||||
|
||||
### Updates
|
||||
* `custom_eucast_rules()` renamed to `custom_interpretive_rules()`; old name deprecated but still works (#268)
|
||||
* `mdro()` can now infer resistance from a drug+inhibitor combination when the base drug column is absent (e.g. piperacillin inferred from piperacillin/tazobactam); controlled via new `infer_from_combinations` argument (default `TRUE`) (#209)
|
||||
* `susceptibility()` / `resistance()`: new `guideline` argument (default EUCAST) to ensure the 'I' category is interpreted correctly per guideline
|
||||
* Capped MIC handling in `as.sir()` reworked into four clearly defined options: `"none"`, `"conservative"` (new default), `"standard"`, `"lenient"` (#243)
|
||||
* `as.mic()` / `rescale_mic()`: new `round_to_next_log2` argument to round values up to the nearest log2 dilution level (#255)
|
||||
* `antimicrobials$group` now a `list`, so drugs belonging to multiple groups are fully represented; use `ab_group(all_groups = TRUE)` to retrieve all groups for a drug (#246)
|
||||
* New antimicrobials added: cefepime/taniborbactam (`FTA`), ceftibuten/avibactam (`CTA`), clorobiocin (`CLB`), kasugamycin (`KAS`), ostreogrycin (`OST`), taniborbactam (`TAN`), thiostrepton (`THS`), xeruborbactam (`XER`), zorbamycin (`ZOR`)
|
||||
* Improved console messages with clickable links throughout, powered by `cli` (#191, #265)
|
||||
* Extensive `cli` integration for better message handling and clickable links in messages and warnings (#191, #265)
|
||||
* `mdro()` now infers resistance for a _missing_ base drug column from an _available_ corresponding drug+inhibitor combination showing resistance (e.g., piperacillin is absent but required, while piperacillin/tazobactam available and resistant). Can be set with the new argument `infer_from_combinations`, which defaults to `TRUE` (#209). Note that this can yield a higher MDRO detection (which is a good thing as it has become more reliable).
|
||||
* `susceptibility()` and `resistance()` gained the argument `guideline`, which defaults to EUCAST, for interpreting the 'I' category correctly.
|
||||
* Added to the `antimicrobials` data set: cefepime/taniborbactam (`FTA`), ceftibuten/avibactam (`CTA`), clorobiocin (`CLB`), kasugamycin (`KAS`), ostreogrycin (`OST`), taniborbactam (`TAN`), thiostrepton (`THS`), xeruborbactam (`XER`), and zorbamycin (`ZOR`)
|
||||
* `as.mic()` and `rescale_mic()` gained the argument `round_to_next_log2`, which can be set to `TRUE` to round all values up to the nearest next log2 level (#255)
|
||||
* `antimicrobials$group` is now a `list` instead of a `character`, to contain any group the drug is in (#246)
|
||||
* `ab_group()` gained an argument `all_groups` to return all groups the antimicrobial drug is in (#246)
|
||||
* Added explaining message to `as.sir()` when interpreting numeric values (e.g., 1 for S, 2 for I, 3 for R) (#244)
|
||||
* Updated handling of capped MIC values (`<`, `<=`, `>`, `>=`) in `as.sir()` in the argument `capped_mic_handling`: (#243)
|
||||
* Introduced four clearly defined options: `"none"`, `"conservative"` (default), `"standard"`, and `"lenient"`
|
||||
* Interpretation of capped MIC values now consistently returns `"NI"` (non-interpretable) when the true MIC could be at either side of a breakpoint, depending on the selected handling mode
|
||||
* This results in more reliable behaviour compared to previous versions for capped MIC values
|
||||
* Removed the `"inverse"` option, which has now become redundant
|
||||
* `ab_group()` now returns values consist with the AMR selectors (#246)
|
||||
* Added two new `NA` objects, `NA_ab_` and `NA_mo_`, analogous to base R's `NA_character_` and `NA_integer_`, for use in pipelines that require typed missing values
|
||||
|
||||
|
||||
# AMR 3.0.1
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
# how to conduct AMR data analysis: https://amr-for-r.org #
|
||||
# ==================================================================== #
|
||||
|
||||
# add new version numbers here, and add the rules themselves to "data-raw/interpretive_rules.tsv" and clinical_breakpoints
|
||||
# add new version numbers here, and add the rules themselves to "data-raw/eucast_rules.tsv" and clinical_breakpoints
|
||||
# (sourcing "data-raw/_pre_commit_checks.R" will process the TSV file)
|
||||
EUCAST_VERSION_BREAKPOINTS <- list(
|
||||
"16.0" = list(
|
||||
@@ -221,7 +221,6 @@ globalVariables(c(
|
||||
"reference.rule",
|
||||
"reference.rule_group",
|
||||
"reference.version",
|
||||
"rule.provider",
|
||||
"rowid",
|
||||
"rule_group",
|
||||
"rule_name",
|
||||
|
||||
22
R/aa_helper_functions.R
Executable file → Normal file
22
R/aa_helper_functions.R
Executable file → Normal file
@@ -1681,6 +1681,28 @@ readRDS_AMR <- function(file, refhook = NULL) {
|
||||
readRDS(con, refhook = refhook)
|
||||
}
|
||||
|
||||
get_n_cores <- function(max_cores = Inf) {
|
||||
if (pkg_is_available("parallelly", min_version = "0.8.0", also_load = FALSE)) {
|
||||
available_cores <- import_fn("availableCores", "parallelly")
|
||||
n_cores <- min(available_cores(), na.rm = TRUE)
|
||||
} else {
|
||||
# `parallel` is part of base R since 2.14.0, but detectCores() is not very precise on exotic systems like Docker and quota-set Linux environments
|
||||
n_cores <- parallel::detectCores()[1]
|
||||
if (is.na(n_cores)) {
|
||||
n_cores <- 1
|
||||
}
|
||||
}
|
||||
max_cores <- floor(max_cores)
|
||||
if (max_cores == 0) {
|
||||
n_cores <- 1
|
||||
} else if (max_cores < 0) {
|
||||
n_cores <- max(1, n_cores - abs(max_cores))
|
||||
} else if (max_cores > 0) {
|
||||
n_cores <- min(n_cores, max_cores)
|
||||
}
|
||||
n_cores
|
||||
}
|
||||
|
||||
# Support `where()` if tidyselect not installed ----
|
||||
if (!is.null(import_fn("where", "tidyselect", error_on_fail = FALSE))) {
|
||||
# tidyselect::where() exists, retrieve from their namespace to make `where()`s work across the package in default arguments
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#' `options(AMR_guideline = "CLSI")`
|
||||
#' @section Options (alphabetical order):
|
||||
#' * `AMR_antibiogram_formatting_type` \cr A [numeric] (1-22) to use in [antibiogram()], to indicate which formatting type to use.
|
||||
#' * `AMR_breakpoint_type` \cr A [character] to use in [as.sir()], to indicate which breakpoint type to use. This must be either `r vector_or(clinical_breakpoints$type, documentation = TRUE)`.
|
||||
#' * `AMR_breakpoint_type` \cr A [character] to use in [as.sir()], to indicate which breakpoint type to use. This must be either `r vector_or(clinical_breakpoints$type)`.
|
||||
#' * `AMR_capped_mic_handling` \cr A [character] to use in [as.sir()], to indicate how capped MIC values (`<`, `<=`, `>`, `>=`) should be interpreted. Must be one of `"none"`, `"conservative"`, `"standard"`, or `"lenient"` - the default is `"conservative"`.
|
||||
#' * `AMR_cleaning_regex` \cr A [regular expression][base::regex] (case-insensitive) to use in [as.mo()] and all [`mo_*`][mo_property()] functions, to clean the user input. The default is the outcome of [mo_cleaning_regex()], which removes texts between brackets and texts such as "species" and "serovar".
|
||||
#' * `AMR_custom_ab` \cr A file location to an RDS file, to use custom antimicrobial drugs with this package. This is explained in [add_custom_antimicrobials()].
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#' Use these functions to return a specific property of an antibiotic from the [antimicrobials] data set. All input values will be evaluated internally with [as.ab()].
|
||||
#' @param x Any (vector of) text that can be coerced to a valid antibiotic drug code with [as.ab()].
|
||||
#' @param tolower A [logical] to indicate whether the first [character] of every output should be transformed to a lower case [character]. This will lead to e.g. "polymyxin B" and not "polymyxin b".
|
||||
#' @param property One of the column names of one of the [antimicrobials] data set: `r vector_or(colnames(antimicrobials), documentation = TRUE, sort = FALSE)`.
|
||||
#' @param property One of the column names of one of the [antimicrobials] data set: `vector_or(colnames(antimicrobials), sort = FALSE)`.
|
||||
#' @param language Language of the returned text - the default is the current system language (see [get_AMR_locale()]) and can also be set with the package option [`AMR_locale`][AMR-options]. Use `language = NULL` or `language = ""` to prevent translation.
|
||||
#' @param administration Way of administration, either `"oral"` or `"iv"`.
|
||||
#' @param open Browse the URL using [utils::browseURL()].
|
||||
@@ -361,7 +361,7 @@ ab_property <- function(x, property = "name", language = get_AMR_locale(), ...)
|
||||
meet_criteria(x, allow_NA = TRUE)
|
||||
meet_criteria(property, is_in = colnames(AMR::antimicrobials), has_length = 1)
|
||||
language <- validate_language(language)
|
||||
translate_into_language(ab_validate(x = x, property = property, ...), language = language, only_affect_ab_names = TRUE)
|
||||
translate_into_language(ab_validate(x = x, property = property, ...), language = language)
|
||||
}
|
||||
|
||||
#' @rdname ab_property
|
||||
|
||||
0
R/amr_course.R
Executable file → Normal file
0
R/amr_course.R
Executable file → Normal file
257
R/antibiogram.R
257
R/antibiogram.R
@@ -48,13 +48,13 @@
|
||||
#' - `carbapenems() + "GEN"`
|
||||
#' - `carbapenems() + c("", "GEN")`
|
||||
#' - `carbapenems() + c("", aminoglycosides())`
|
||||
#' @param mo_transform A character to transform microorganism input - must be `"name"`, `"shortname"` (default), `"gramstain"`, or one of the column names of the [microorganisms] data set: `r vector_or(colnames(microorganisms), sort = FALSE, documentation = TRUE)`. Can also be `NULL` to not transform the input or `NA` to consider all microorganisms 'unknown'.
|
||||
#' @param ab_transform A character to transform antimicrobial input - must be one of the column names of the [antimicrobials] data set (defaults to `"name"`): `r vector_or(colnames(antimicrobials), sort = FALSE, documentation = TRUE)`. Can also be `NULL` to not transform the input.
|
||||
#' @param mo_transform A character to transform microorganism input - must be `"name"`, `"shortname"` (default), `"gramstain"`, or one of the column names of the [microorganisms] data set: `r vector_or(colnames(microorganisms), sort = FALSE, quotes = TRUE)`. Can also be `NULL` to not transform the input or `NA` to consider all microorganisms 'unknown'.
|
||||
#' @param ab_transform A character to transform antimicrobial input - must be one of the column names of the [antimicrobials] data set (defaults to `"name"`): `r vector_or(colnames(antimicrobials), sort = FALSE, quotes = TRUE)`. Can also be `NULL` to not transform the input.
|
||||
#' @param syndromic_group A column name of `x`, or values calculated to split rows of `x`, e.g. by using [ifelse()] or [`case_when()`][dplyr::case_when()]. See *Examples*.
|
||||
#' @param add_total_n *(deprecated in favour of `formatting_type`)* A [logical] to indicate whether `n_tested` available numbers per pathogen should be added to the table (default is `TRUE`). This will add the lowest and highest number of available isolates per antimicrobial (e.g, if for *E. coli* 200 isolates are available for ciprofloxacin and 150 for amoxicillin, the returned number will be "150-200"). This option is unavailable when `wisca = TRUE`; in that case, use [retrieve_wisca_parameters()] to get the parameters used for WISCA.
|
||||
#' @param only_all_tested (for combination antibiograms): a [logical] to indicate that isolates must be tested for all antimicrobials, see *Details*.
|
||||
#' @param digits Number of digits to use for rounding the antimicrobial coverage, defaults to 1 for WISCA and 0 otherwise.
|
||||
#' @param formatting_type Numeric value (1-22 for WISCA, 1-12 for non-WISCA) indicating how the 'cells' of the antibiogram table should be formatted. See *Details* > *Formatting Type* for a list of options.
|
||||
#' @param formatting_type Numeric value (1–22 for WISCA, 1-12 for non-WISCA) indicating how the 'cells' of the antibiogram table should be formatted. See *Details* > *Formatting Type* for a list of options.
|
||||
#' @param col_mo Column name of the names or codes of the microorganisms (see [as.mo()]) - the default is the first column of class [`mo`]. Values will be coerced using [as.mo()].
|
||||
#' @param language Language to translate text, which defaults to the system language (see [get_AMR_locale()]).
|
||||
#' @param minimum The minimum allowed number of available (tested) isolates. Any isolate count lower than `minimum` will return `NA` with a warning. The default number of `30` isolates is advised by the Clinical and Laboratory Standards Institute (CLSI) as best practice, see *Source*.
|
||||
@@ -65,7 +65,6 @@
|
||||
#' @param simulations (for WISCA) a numerical value to set the number of Monte Carlo simulations.
|
||||
#' @param conf_interval A numerical value to set confidence interval (default is `0.95`).
|
||||
#' @param interval_side The side of the confidence interval, either `"two-tailed"` (default), `"left"` or `"right"`.
|
||||
#' @param parallel A [logical] to indicate if parallel computing must be used, defaults to `FALSE`. Requires the [`future.apply`][future.apply::future_lapply()] package. For WISCA, Monte Carlo simulations are distributed across workers; for grouped antibiograms, each group is processed by a separate worker. **A non-sequential [future::plan()] must already be active before setting `parallel = TRUE`** -- for example, `future::plan(future::multisession)`. An error is thrown if `parallel = TRUE` is used without a plan set by the user.
|
||||
#' @param info A [logical] to indicate info should be printed - the default is `TRUE` only in interactive mode.
|
||||
#' @param object An [antibiogram()] object.
|
||||
#' @param ... When used in [R Markdown or Quarto][knitr::kable()]: arguments passed on to [knitr::kable()] (otherwise, has no use).
|
||||
@@ -414,7 +413,6 @@ antibiogram <- function(x,
|
||||
conf_interval = 0.95,
|
||||
interval_side = "two-tailed",
|
||||
info = interactive(),
|
||||
parallel = FALSE,
|
||||
...) {
|
||||
UseMethod("antibiogram")
|
||||
}
|
||||
@@ -441,7 +439,6 @@ antibiogram.default <- function(x,
|
||||
conf_interval = 0.95,
|
||||
interval_side = "two-tailed",
|
||||
info = interactive(),
|
||||
parallel = FALSE,
|
||||
...) {
|
||||
meet_criteria(x, allow_class = "data.frame")
|
||||
x <- ascertain_sir_classes(x, "x")
|
||||
@@ -481,35 +478,6 @@ antibiogram.default <- function(x,
|
||||
meet_criteria(conf_interval, allow_class = c("numeric", "integer"), has_length = 1, is_finite = TRUE, is_positive = TRUE)
|
||||
meet_criteria(interval_side, allow_class = "character", has_length = 1, is_in = c("two-tailed", "left", "right"))
|
||||
meet_criteria(info, allow_class = "logical", has_length = 1)
|
||||
meet_criteria(parallel, allow_class = "logical", has_length = 1)
|
||||
|
||||
# parallel gate - identical pattern to as.sir()
|
||||
if (requireNamespace("future.apply", quietly = TRUE) && !inherits(future::plan(), "sequential")) {
|
||||
if (isFALSE(parallel)) {
|
||||
message_("Assuming {.code parallel = TRUE} since parallel computing has been set up using the {.pkg future} package before. Set {.help [{.fun plan}](future::plan)} to sequential to prevent this.")
|
||||
}
|
||||
parallel <- TRUE
|
||||
}
|
||||
if (isTRUE(parallel)) {
|
||||
stop_ifnot(
|
||||
requireNamespace("future.apply", quietly = TRUE),
|
||||
"Setting {.code parallel = TRUE} requires the {.pkg future.apply} package.\n",
|
||||
"Install it with {.code install.packages(\"future.apply\")}."
|
||||
)
|
||||
stop_if(inherits(future::plan(), "sequential"),
|
||||
"Setting {.code parallel = TRUE} requires a non-sequential {.help [{.fun future::plan}](future::plan)} to be active.\n",
|
||||
"For your system, you could first run: {.code library(future); ",
|
||||
ifelse(.Platform$OS.type == "windows" || in_rstudio(),
|
||||
"plan(multisession)",
|
||||
"plan(multicore)"
|
||||
),
|
||||
"}",
|
||||
call = FALSE
|
||||
)
|
||||
n_workers <- future::nbrOfWorkers()
|
||||
} else {
|
||||
n_workers <- 1L
|
||||
}
|
||||
|
||||
# try to find columns based on type
|
||||
if (is.null(col_mo)) {
|
||||
@@ -737,98 +705,53 @@ antibiogram.default <- function(x,
|
||||
|
||||
wisca_parameters <- out
|
||||
|
||||
# quantile probabilities are constant across all groups
|
||||
probs <- if (interval_side == "two-tailed") {
|
||||
c((1 - conf_interval) / 2, 1 - (1 - conf_interval) / 2)
|
||||
} else if (interval_side == "left") {
|
||||
c(0, conf_interval)
|
||||
} else {
|
||||
c(1 - conf_interval, 1)
|
||||
}
|
||||
progress <- progress_ticker(
|
||||
n = length(unique(wisca_parameters$group)) * simulations,
|
||||
n_min = 25,
|
||||
print = info,
|
||||
title = paste("Calculating WISCA for", length(unique(wisca_parameters$group)), "regimens")
|
||||
)
|
||||
on.exit(close(progress))
|
||||
|
||||
unique_groups <- as.character(unique(wisca_parameters$group))
|
||||
|
||||
use_parallel_wisca <- isTRUE(parallel) && n_workers > 1L && length(unique_groups) > 0L
|
||||
|
||||
if (use_parallel_wisca) {
|
||||
if (isTRUE(info)) {
|
||||
message_("Running WISCA in parallel mode using ", n_workers, " workers...", as_note = FALSE, appendLF = FALSE)
|
||||
# run WISCA per group
|
||||
for (group in unique(wisca_parameters$group)) {
|
||||
params_current <- wisca_parameters[wisca_parameters$group == group, , drop = FALSE]
|
||||
if (sum(params_current$n_tested, na.rm = TRUE) == 0) {
|
||||
next
|
||||
}
|
||||
# chunks_per_group gives ~n_workers total jobs so all workers stay busy
|
||||
# even when the number of regimens is smaller than n_workers
|
||||
chunks_per_group <- max(1L, ceiling(n_workers / length(unique_groups)))
|
||||
chunk_sizes <- diff(c(0L, round(seq_len(chunks_per_group) * simulations / chunks_per_group)))
|
||||
|
||||
# precompute priors per group and build (group, chunk) job list
|
||||
jobs <- unlist(lapply(unique_groups, function(g) {
|
||||
params_g <- wisca_parameters[wisca_parameters$group == g, , drop = FALSE]
|
||||
if (sum(params_g$n_tested, na.rm = TRUE) == 0L) {
|
||||
return(NULL)
|
||||
# prepare priors
|
||||
priors_current <- create_wisca_priors(params_current)
|
||||
|
||||
# Monte Carlo simulations
|
||||
coverage_simulations <- vapply(
|
||||
FUN.VALUE = double(1),
|
||||
seq_len(simulations), function(i) {
|
||||
progress$tick()
|
||||
simulate_coverage(priors_current)
|
||||
}
|
||||
priors_g <- create_wisca_priors(params_g)
|
||||
lapply(seq_along(chunk_sizes), function(ch) {
|
||||
list(group = g, priors = priors_g, n_sims = chunk_sizes[ch])
|
||||
})
|
||||
}), recursive = FALSE)
|
||||
jobs <- Filter(Negate(is.null), jobs)
|
||||
|
||||
flat <- future.apply::future_lapply(jobs, function(job) {
|
||||
vapply(FUN.VALUE = double(1), seq_len(job$n_sims), function(i) {
|
||||
simulate_coverage(job$priors)
|
||||
})
|
||||
}, future.seed = TRUE)
|
||||
|
||||
# reassemble per group: concatenate chunks, then summarise
|
||||
for (g in unique_groups) {
|
||||
g_idx <- vapply(jobs, function(j) identical(j$group, g), logical(1))
|
||||
if (!any(g_idx)) next
|
||||
sims <- unlist(flat[g_idx], use.names = FALSE)
|
||||
out_wisca$coverage[out_wisca$group == g] <- mean(sims)
|
||||
ci_vals <- unname(stats::quantile(sims, probs = probs))
|
||||
out_wisca$lower_ci[out_wisca$group == g] <- ci_vals[1]
|
||||
out_wisca$upper_ci[out_wisca$group == g] <- ci_vals[2]
|
||||
}
|
||||
|
||||
if (isTRUE(info)) message_(font_green_bg(" DONE "), as_note = FALSE)
|
||||
} else {
|
||||
progress <- progress_ticker(
|
||||
n = length(unique_groups) * simulations,
|
||||
n_min = 25,
|
||||
print = info,
|
||||
title = paste("Calculating WISCA for", length(unique_groups), "regimens")
|
||||
)
|
||||
on.exit(close(progress), add = TRUE)
|
||||
|
||||
for (group in unique_groups) {
|
||||
params_current <- wisca_parameters[wisca_parameters$group == group, , drop = FALSE]
|
||||
if (sum(params_current$n_tested, na.rm = TRUE) == 0) next
|
||||
priors_current <- create_wisca_priors(params_current)
|
||||
coverage_simulations <- vapply(
|
||||
FUN.VALUE = double(1),
|
||||
seq_len(simulations), function(i) {
|
||||
progress$tick()
|
||||
simulate_coverage(priors_current)
|
||||
}
|
||||
)
|
||||
out_wisca$coverage[out_wisca$group == group] <- mean(coverage_simulations)
|
||||
ci_vals <- unname(stats::quantile(coverage_simulations, probs = probs))
|
||||
out_wisca$lower_ci[out_wisca$group == group] <- ci_vals[1]
|
||||
out_wisca$upper_ci[out_wisca$group == group] <- ci_vals[2]
|
||||
}
|
||||
close(progress)
|
||||
if (isTRUE(info) && simulations >= 500 && length(unique_groups) >= 3) {
|
||||
suggest <- ifelse(.Platform$OS.type == "windows" || in_rstudio(),
|
||||
"plan(multisession)",
|
||||
"plan(multicore)"
|
||||
)
|
||||
if (requireNamespace("future.apply", quietly = TRUE)) {
|
||||
message_("Running in sequential mode. To speed up WISCA, set a parallel {.help [{.fun future::plan}](future::plan)} such as {.code ", suggest, "} and use {.code parallel = TRUE}.")
|
||||
} else {
|
||||
message_("Running in sequential mode. To speed up WISCA, install the {.pkg future.apply} package and then set {.code parallel = TRUE}.")
|
||||
}
|
||||
# summarise results
|
||||
coverage_mean <- mean(coverage_simulations)
|
||||
|
||||
if (interval_side == "two-tailed") {
|
||||
probs <- c((1 - conf_interval) / 2, 1 - (1 - conf_interval) / 2)
|
||||
} else if (interval_side == "left") {
|
||||
probs <- c(0, conf_interval)
|
||||
} else if (interval_side == "right") {
|
||||
probs <- c(1 - conf_interval, 1)
|
||||
}
|
||||
|
||||
coverage_ci <- unname(stats::quantile(coverage_simulations, probs = probs))
|
||||
|
||||
out_wisca$coverage[out_wisca$group == group] <- coverage_mean
|
||||
out_wisca$lower_ci[out_wisca$group == group] <- coverage_ci[1]
|
||||
out_wisca$upper_ci[out_wisca$group == group] <- coverage_ci[2]
|
||||
}
|
||||
|
||||
close(progress)
|
||||
|
||||
# final output preparation
|
||||
out <- out_wisca
|
||||
wisca_parameters <- wisca_parameters[, colnames(wisca_parameters)[!colnames(wisca_parameters) %in% c(levels(NA_sir_), "lower_ci", "upper_ci", "group")], drop = FALSE]
|
||||
@@ -1074,52 +997,30 @@ antibiogram.grouped_df <- function(x,
|
||||
conf_interval = 0.95,
|
||||
interval_side = "two-tailed",
|
||||
info = interactive(),
|
||||
parallel = FALSE,
|
||||
...) {
|
||||
stop_ifnot(is.null(mo_transform), "{.arg mo_transform} must not be set if creating an antibiogram using a grouped tibble. The groups will become the variables over which the antimicrobials are calculated, which could include the pathogen information (though not necessary). Nonetheless, this makes {.arg mo_transform} redundant.", call = FALSE)
|
||||
stop_ifnot(is.null(syndromic_group), "{.arg syndromic_group} must not be set if creating an antibiogram using a grouped tibble. The groups will become the variables over which the antimicrobials are calculated, making {.arg syndromic_group} redundant.", call = FALSE)
|
||||
meet_criteria(parallel, allow_class = "logical", has_length = 1)
|
||||
|
||||
groups <- attributes(x)$groups
|
||||
n_groups <- NROW(groups)
|
||||
progress <- progress_ticker(
|
||||
n = n_groups,
|
||||
n_min = 5,
|
||||
print = info,
|
||||
title = paste("Calculating AMR for", n_groups, "groups")
|
||||
)
|
||||
on.exit(close(progress))
|
||||
|
||||
# parallel gate - identical pattern to as.sir()
|
||||
if (requireNamespace("future.apply", quietly = TRUE) && !inherits(future::plan(), "sequential")) {
|
||||
if (isFALSE(parallel)) {
|
||||
message_("Assuming {.code parallel = TRUE} since parallel computing has been set up using the {.pkg future} package before. Set {.help [{.fun plan}](future::plan)} to sequential to prevent this.")
|
||||
}
|
||||
parallel <- TRUE
|
||||
}
|
||||
if (isTRUE(parallel)) {
|
||||
stop_ifnot(
|
||||
requireNamespace("future.apply", quietly = TRUE),
|
||||
"Setting {.code parallel = TRUE} requires the {.pkg future.apply} package.\n",
|
||||
"Install it with {.code install.packages(\"future.apply\")}."
|
||||
)
|
||||
stop_if(inherits(future::plan(), "sequential"),
|
||||
"Setting {.code parallel = TRUE} requires a non-sequential {.help [{.fun future::plan}](future::plan)} to be active.\n",
|
||||
"For your system, you could first run: {.code library(future); ",
|
||||
ifelse(.Platform$OS.type == "windows" || in_rstudio(),
|
||||
"plan(multisession)",
|
||||
"plan(multicore)"
|
||||
),
|
||||
"}",
|
||||
call = FALSE
|
||||
)
|
||||
n_workers <- future::nbrOfWorkers()
|
||||
} else {
|
||||
n_workers <- 1L
|
||||
}
|
||||
out <- NULL
|
||||
wisca_parameters <- NULL
|
||||
long_numeric <- NULL
|
||||
|
||||
use_parallel <- isTRUE(parallel) && n_workers > 1L && n_groups > 1L
|
||||
|
||||
x_df <- as.data.frame(x)
|
||||
run_group <- function(i) {
|
||||
for (i in seq_len(n_groups)) {
|
||||
progress$tick()
|
||||
rows <- unlist(groups[i, ]$.rows)
|
||||
if (length(rows) == 0L) {
|
||||
return(NULL)
|
||||
if (length(rows) == 0) {
|
||||
next
|
||||
}
|
||||
antibiogram(x_df[rows, , drop = FALSE],
|
||||
new_out <- antibiogram(as.data.frame(x)[rows, , drop = FALSE],
|
||||
antimicrobials = antimicrobials,
|
||||
mo_transform = NULL,
|
||||
ab_transform = ab_transform,
|
||||
@@ -1139,42 +1040,12 @@ antibiogram.grouped_df <- function(x,
|
||||
conf_interval = conf_interval,
|
||||
interval_side = interval_side,
|
||||
info = FALSE,
|
||||
parallel = FALSE # never nest parallelism in workers
|
||||
...
|
||||
)
|
||||
}
|
||||
|
||||
if (use_parallel) {
|
||||
if (isTRUE(info)) {
|
||||
message_("Running antibiogram for ", n_groups, " groups in parallel using ", n_workers, " workers...", as_note = FALSE, appendLF = FALSE)
|
||||
}
|
||||
results_raw <- future.apply::future_lapply(seq_len(n_groups), run_group, future.seed = TRUE)
|
||||
if (isTRUE(info)) message_(font_green_bg(" DONE "), as_note = FALSE)
|
||||
} else {
|
||||
progress <- progress_ticker(
|
||||
n = n_groups,
|
||||
n_min = 5,
|
||||
print = info,
|
||||
title = paste("Calculating AMR for", n_groups, "groups")
|
||||
)
|
||||
on.exit(close(progress), add = TRUE)
|
||||
results_raw <- vector("list", n_groups)
|
||||
for (i in seq_len(n_groups)) {
|
||||
progress$tick()
|
||||
results_raw[[i]] <- run_group(i)
|
||||
}
|
||||
close(progress)
|
||||
}
|
||||
|
||||
out <- NULL
|
||||
wisca_parameters <- NULL
|
||||
long_numeric <- NULL
|
||||
|
||||
for (i in seq_len(n_groups)) {
|
||||
new_out <- results_raw[[i]]
|
||||
new_wisca_parameters <- attributes(new_out)$wisca_parameters
|
||||
new_long_numeric <- attributes(new_out)$long_numeric
|
||||
|
||||
if (is.null(new_out) || NROW(new_out) == 0) {
|
||||
if (NROW(new_out) == 0) {
|
||||
next
|
||||
}
|
||||
|
||||
@@ -1200,7 +1071,8 @@ antibiogram.grouped_df <- function(x,
|
||||
new_long_numeric <- new_long_numeric[, c(col_name, setdiff(names(new_long_numeric), col_name))] # set place to 1st col
|
||||
}
|
||||
|
||||
if (is.null(out)) {
|
||||
if (i == 1) {
|
||||
# the first go
|
||||
out <- new_out
|
||||
wisca_parameters <- new_wisca_parameters
|
||||
long_numeric <- new_long_numeric
|
||||
@@ -1211,6 +1083,8 @@ antibiogram.grouped_df <- function(x,
|
||||
}
|
||||
}
|
||||
|
||||
close(progress)
|
||||
|
||||
out <- structure(as_original_data_class(out, class(x), extra_class = "antibiogram"),
|
||||
has_syndromic_group = FALSE,
|
||||
combine_SI = isTRUE(combine_SI),
|
||||
@@ -1242,7 +1116,6 @@ wisca <- function(x,
|
||||
conf_interval = 0.95,
|
||||
interval_side = "two-tailed",
|
||||
info = interactive(),
|
||||
parallel = FALSE,
|
||||
...) {
|
||||
antibiogram(
|
||||
x = x,
|
||||
@@ -1264,7 +1137,6 @@ wisca <- function(x,
|
||||
conf_interval = conf_interval,
|
||||
interval_side = interval_side,
|
||||
info = info,
|
||||
parallel = parallel,
|
||||
...
|
||||
)
|
||||
}
|
||||
@@ -1334,7 +1206,7 @@ retrieve_wisca_parameters <- function(wisca_model, ...) {
|
||||
#' @rawNamespace if(getRversion() >= "3.0.0") S3method(pillar::tbl_sum, antibiogram)
|
||||
tbl_sum.antibiogram <- function(x, ...) {
|
||||
dims <- paste(format(NROW(x), big.mark = ","), AMR_env$cross_icon, format(NCOL(x), big.mark = ","))
|
||||
names(dims) <- "An antibiogram"
|
||||
names(dims) <- "An Antibiogram"
|
||||
if (isTRUE(attributes(x)$wisca)) {
|
||||
dims <- c(dims, Type = paste0("WISCA with ", attributes(x)$conf_interval * 100, "% CI"))
|
||||
} else if (isTRUE(attributes(x)$formatting_type >= 13)) {
|
||||
@@ -1354,7 +1226,8 @@ tbl_format_footer.antibiogram <- function(x, ...) {
|
||||
}
|
||||
c(footer, font_subtle(paste0(
|
||||
"# Use `ggplot2::autoplot()` or base R `plot()` to create a plot of this antibiogram,\n",
|
||||
"# or use it directly in R Markdown or Quarto, see ", word_wrap("?antibiogram")
|
||||
"# or use it directly in R Markdown or ",
|
||||
font_url("https://quarto.org", "Quarto"), ", see ", word_wrap("?antibiogram")
|
||||
)))
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#' Use these functions to return a specific property of an antiviral drug from the [antivirals] data set. All input values will be evaluated internally with [as.av()].
|
||||
#' @param x Any (vector of) text that can be coerced to a valid antiviral drug code with [as.av()].
|
||||
#' @param tolower A [logical] to indicate whether the first [character] of every output should be transformed to a lower case [character].
|
||||
#' @param property One of the column names of one of the [antivirals] data set: `r vector_or(colnames(antivirals), documentation = TRUE, sort = FALSE)`.
|
||||
#' @param property One of the column names of one of the [antivirals] data set: `vector_or(colnames(antivirals), sort = FALSE)`.
|
||||
#' @param language Language of the returned text - the default is system language (see [get_AMR_locale()]) and can also be set with the package option [`AMR_locale`][AMR-options]. Use `language = NULL` or `language = ""` to prevent translation.
|
||||
#' @param administration Way of administration, either `"oral"` or `"iv"`.
|
||||
#' @param open Browse the URL using [utils::browseURL()].
|
||||
|
||||
@@ -129,21 +129,16 @@ bug_drug_combinations <- function(x,
|
||||
# turn and merge everything
|
||||
pivot <- lapply(x_mo_filter, function(x) {
|
||||
m <- as.matrix(table(as.sir(x), useNA = "always"))
|
||||
na_idx <- which(is.na(rownames(m)))
|
||||
get_row <- function(lbl) {
|
||||
idx <- which(rownames(m) == lbl)
|
||||
if (length(idx) == 1L) unname(m[idx, ]) else rep(0L, ncol(m))
|
||||
}
|
||||
data.frame(
|
||||
S = get_row("S"),
|
||||
SDD = get_row("SDD"),
|
||||
I = get_row("I"),
|
||||
R = get_row("R"),
|
||||
NI = get_row("NI"),
|
||||
WT = get_row("WT"),
|
||||
NWT = get_row("NWT"),
|
||||
NS = get_row("NS"),
|
||||
na = if (length(na_idx) == 1L) unname(m[na_idx, ]) else rep(0L, ncol(m)),
|
||||
S = m["S", ],
|
||||
SDD = m["SDD", ],
|
||||
I = m["I", ],
|
||||
R = m["R", ],
|
||||
NI = m["NI", ],
|
||||
WT = m["WT", ],
|
||||
NWT = m["NWT", ],
|
||||
NS = m["NS", ],
|
||||
na = m[which(is.na(rownames(m))), ],
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
})
|
||||
|
||||
@@ -27,27 +27,27 @@
|
||||
# how to conduct AMR data analysis: https://amr-for-r.org #
|
||||
# ==================================================================== #
|
||||
|
||||
#' Define Custom Interpretive Rules
|
||||
#' Define Custom EUCAST Rules
|
||||
#'
|
||||
#' Define custom interpretive rules for your organisation or specific analysis and use the output of this function in [interpretive_rules()].
|
||||
#' Define custom EUCAST rules for your organisation or specific analysis and use the output of this function in [eucast_rules()].
|
||||
#' @param ... Rules in [formula][base::tilde] notation, see below for instructions, and in *Examples*.
|
||||
#' @details
|
||||
#' Some organisations have their own adoption of interpretive rules. This function can be used to define custom rules to be used in the [interpretive_rules()] function.
|
||||
#' Some organisations have their own adoption of EUCAST rules. This function can be used to define custom EUCAST rules to be used in the [eucast_rules()] function.
|
||||
#'
|
||||
#' ### Basics
|
||||
#'
|
||||
#' If you are familiar with the [`case_when()`][dplyr::case_when()] function of the `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 *before* the tilde (`~`) and the consequence of the rule is written *after* the tilde:
|
||||
#'
|
||||
#' ```r
|
||||
#' x <- custom_interpretive_rules(TZP == "S" ~ aminopenicillins == "S",
|
||||
#' TZP == "R" ~ aminopenicillins == "R")
|
||||
#' x <- custom_eucast_rules(TZP == "S" ~ aminopenicillins == "S",
|
||||
#' TZP == "R" ~ aminopenicillins == "R")
|
||||
#' ```
|
||||
#'
|
||||
#' These are two custom interpretive 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:
|
||||
#' 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:
|
||||
#'
|
||||
#' ```r
|
||||
#' x
|
||||
#' #> A set of custom interpretive rules:
|
||||
#' #> A set of custom EUCAST rules:
|
||||
#' #>
|
||||
#' #> 1. If TZP is "S" then set to S :
|
||||
#' #> amoxicillin (AMX), ampicillin (AMP)
|
||||
@@ -68,11 +68,11 @@
|
||||
#' #> 1 Escherichia coli R S S
|
||||
#' #> 2 Klebsiella pneumoniae R S S
|
||||
#'
|
||||
#' interpretive_rules(df,
|
||||
#' rules = "custom",
|
||||
#' custom_rules = x,
|
||||
#' info = FALSE,
|
||||
#' overwrite = TRUE)
|
||||
#' eucast_rules(df,
|
||||
#' rules = "custom",
|
||||
#' custom_rules = x,
|
||||
#' info = FALSE,
|
||||
#' overwrite = TRUE)
|
||||
#' #> mo TZP ampi cipro
|
||||
#' #> 1 Escherichia coli R R S
|
||||
#' #> 2 Klebsiella pneumoniae R R S
|
||||
@@ -83,16 +83,16 @@
|
||||
#' There is one exception in columns used for the rules: all column names of the [microorganisms] data set can also be used, but do not have to exist in the data set. These column names are: `r vector_and(colnames(microorganisms), sort = FALSE, documentation = TRUE)`. Thus, this next example will work as well, despite the fact that the `df` data set does not contain a column `genus`:
|
||||
#'
|
||||
#' ```r
|
||||
#' y <- custom_interpretive_rules(
|
||||
#' y <- custom_eucast_rules(
|
||||
#' TZP == "S" & genus == "Klebsiella" ~ aminopenicillins == "S",
|
||||
#' TZP == "R" & genus == "Klebsiella" ~ aminopenicillins == "R"
|
||||
#' )
|
||||
#'
|
||||
#' interpretive_rules(df,
|
||||
#' rules = "custom",
|
||||
#' custom_rules = y,
|
||||
#' info = FALSE,
|
||||
#' overwrite = TRUE)
|
||||
#' eucast_rules(df,
|
||||
#' rules = "custom",
|
||||
#' custom_rules = y,
|
||||
#' info = FALSE,
|
||||
#' overwrite = TRUE)
|
||||
#' #> mo TZP ampi cipro
|
||||
#' #> 1 Escherichia coli R S S
|
||||
#' #> 2 Klebsiella pneumoniae R R S
|
||||
@@ -109,9 +109,9 @@
|
||||
#' Rules can also be applied to multiple antimicrobials and antimicrobial groups simultaneously. Use the `c()` function to combine multiple antimicrobials. For instance, the following example sets all aminopenicillins and ureidopenicillins to "R" if column TZP (piperacillin/tazobactam) is "R":
|
||||
#'
|
||||
#' ```r
|
||||
#' x <- custom_interpretive_rules(TZP == "R" ~ c(aminopenicillins, ureidopenicillins) == "R")
|
||||
#' x <- custom_eucast_rules(TZP == "R" ~ c(aminopenicillins, ureidopenicillins) == "R")
|
||||
#' x
|
||||
#' #> A set of custom interpretive rules:
|
||||
#' #> A set of custom EUCAST rules:
|
||||
#' #>
|
||||
#' #> 1. If TZP is "R" then set to "R":
|
||||
#' #> amoxicillin (AMX), ampicillin (AMP), azlocillin (AZL), mezlocillin (MEZ), piperacillin (PIP), piperacillin/tazobactam (TZP)
|
||||
@@ -123,7 +123,7 @@
|
||||
#' @returns A [list] containing the custom rules
|
||||
#' @export
|
||||
#' @examples
|
||||
#' x <- custom_interpretive_rules(
|
||||
#' x <- custom_eucast_rules(
|
||||
#' AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
|
||||
#' AMC == "I" & genus == "Klebsiella" ~ aminopenicillins == "I"
|
||||
#' )
|
||||
@@ -141,24 +141,24 @@
|
||||
#' # combine rule sets
|
||||
#' x2 <- c(
|
||||
#' x,
|
||||
#' custom_interpretive_rules(TZP == "R" ~ carbapenems == "R")
|
||||
#' custom_eucast_rules(TZP == "R" ~ carbapenems == "R")
|
||||
#' )
|
||||
#' x2
|
||||
custom_interpretive_rules <- function(...) {
|
||||
custom_eucast_rules <- function(...) {
|
||||
dots <- tryCatch(list(...),
|
||||
error = function(e) "error"
|
||||
)
|
||||
stop_if(
|
||||
identical(dots, "error"),
|
||||
"rules must be a valid formula inputs (e.g., using '~'), see {.help [{.fun custom_interpretive_rules}](AMR::custom_interpretive_rules)}"
|
||||
"rules must be a valid formula inputs (e.g., using '~'), see {.help [{.fun custom_eucast_rules}](AMR::custom_eucast_rules)}"
|
||||
)
|
||||
n_dots <- length(dots)
|
||||
stop_if(n_dots == 0, "no custom rules were set. Please read the documentation using {.help [{.fun custom_interpretive_rules}](AMR::custom_interpretive_rules)}.")
|
||||
stop_if(n_dots == 0, "no custom rules were set. Please read the documentation using {.help [{.fun custom_eucast_rules}](AMR::custom_eucast_rules)}.")
|
||||
out <- vector("list", n_dots)
|
||||
for (i in seq_len(n_dots)) {
|
||||
stop_ifnot(
|
||||
inherits(dots[[i]], "formula"),
|
||||
"rule ", i, " must be a valid formula input (e.g., using '~'), see {.help [{.fun custom_interpretive_rules}](AMR::custom_interpretive_rules)}"
|
||||
"rule ", i, " must be a valid formula input (e.g., using '~'), see {.help [{.fun custom_eucast_rules}](AMR::custom_eucast_rules)}"
|
||||
)
|
||||
|
||||
# Query
|
||||
@@ -180,7 +180,7 @@ custom_interpretive_rules <- function(...) {
|
||||
result <- dots[[i]][[3]]
|
||||
stop_ifnot(
|
||||
deparse(result) %like% "==",
|
||||
"the result of rule ", i, " (the part after the `~`) must contain `==`, such as in `... ~ ampicillin == \"R\"`, see {.help [{.fun custom_interpretive_rules}](AMR::custom_interpretive_rules)}"
|
||||
"the result of rule ", i, " (the part after the `~`) must contain `==`, such as in `... ~ ampicillin == \"R\"`, see {.help [{.fun custom_eucast_rules}](AMR::custom_eucast_rules)}"
|
||||
)
|
||||
result_group <- as.character(result)[[2]]
|
||||
result_group <- as.character(str2lang(result_group))
|
||||
@@ -230,13 +230,13 @@ custom_interpretive_rules <- function(...) {
|
||||
}
|
||||
|
||||
names(out) <- paste0("rule", seq_len(n_dots))
|
||||
set_clean_class(out, new_class = c("custom_interpretive_rules", "list"))
|
||||
set_clean_class(out, new_class = c("custom_eucast_rules", "list"))
|
||||
}
|
||||
|
||||
#' @method c custom_interpretive_rules
|
||||
#' @method c custom_eucast_rules
|
||||
#' @noRd
|
||||
#' @export
|
||||
c.custom_interpretive_rules <- function(x, ...) {
|
||||
c.custom_eucast_rules <- function(x, ...) {
|
||||
if (length(list(...)) == 0) {
|
||||
return(x)
|
||||
}
|
||||
@@ -245,21 +245,21 @@ c.custom_interpretive_rules <- function(x, ...) {
|
||||
out <- c(out, unclass(e))
|
||||
}
|
||||
names(out) <- paste0("rule", seq_len(length(out)))
|
||||
set_clean_class(out, new_class = c("custom_interpretive_rules", "list"))
|
||||
set_clean_class(out, new_class = c("custom_eucast_rules", "list"))
|
||||
}
|
||||
|
||||
#' @method as.list custom_interpretive_rules
|
||||
#' @method as.list custom_eucast_rules
|
||||
#' @noRd
|
||||
#' @export
|
||||
as.list.custom_interpretive_rules <- function(x, ...) {
|
||||
as.list.custom_eucast_rules <- function(x, ...) {
|
||||
c(x, ...)
|
||||
}
|
||||
|
||||
#' @method print custom_interpretive_rules
|
||||
#' @method print custom_eucast_rules
|
||||
#' @export
|
||||
#' @noRd
|
||||
print.custom_interpretive_rules <- function(x, ...) {
|
||||
cat("A set of custom interpretive rules:\n")
|
||||
print.custom_eucast_rules <- function(x, ...) {
|
||||
cat("A set of custom EUCAST rules:\n")
|
||||
for (i in seq_len(length(x))) {
|
||||
rule <- x[[i]]
|
||||
rule$query <- format_custom_query_rule(rule$query)
|
||||
@@ -291,19 +291,3 @@ print.custom_interpretive_rules <- function(x, ...) {
|
||||
cat("\n ", rule_if, "\n", rule_then, "\n", sep = "")
|
||||
}
|
||||
}
|
||||
|
||||
# Backward-compat S3 dispatch for objects created with the old custom_eucast_rules() function
|
||||
#' @method c custom_eucast_rules
|
||||
#' @noRd
|
||||
#' @export
|
||||
c.custom_eucast_rules <- function(x, ...) c.custom_interpretive_rules(x, ...)
|
||||
|
||||
#' @method as.list custom_eucast_rules
|
||||
#' @noRd
|
||||
#' @export
|
||||
as.list.custom_eucast_rules <- function(x, ...) as.list.custom_interpretive_rules(x, ...)
|
||||
|
||||
#' @method print custom_eucast_rules
|
||||
#' @export
|
||||
#' @noRd
|
||||
print.custom_eucast_rules <- function(x, ...) print.custom_interpretive_rules(x, ...)
|
||||
5
R/data.R
5
R/data.R
@@ -109,9 +109,8 @@
|
||||
#' - `status` \cr Status of the taxon, either `r vector_or(microorganisms$status, documentation = TRUE)`
|
||||
#' - `kingdom`, `phylum`, `class`, `order`, `family`, `genus`, `species`, `subspecies`\cr Taxonomic rank of the microorganism. Note that for fungi, *phylum* is equal to their taxonomic *division*. Also, for fungi, *subkingdom* and *subdivision* were left out since they do not occur in the bacterial taxonomy.
|
||||
#' - `rank`\cr Text of the taxonomic rank of the microorganism, such as `"species"` or `"genus"`
|
||||
#' - `ref`\cr Abbreviated authority citation for the nomenclatural act that established the current name combination, following ICNP conventions. For species described in their current genus (*sp. nov.*), this is the original description author(s) and year. For species transferred to a different genus (*comb. nov.*), this is the reclassification author(s) and year. Emendations are excluded. For synonyms, this is the authority under which the synonym was originally published. This field is directly retrieved from the source specified in the column `source`. Diacritics were removed to comply with CRAN, that only allows ASCII characters.
|
||||
#' - `ref`\cr Author(s) and year of related scientific publication. This contains only the *first surname* and year of the *latest* authors, e.g. "Wallis *et al.* 2006 *emend.* Smith and Jones 2018" becomes "Smith *et al.*, 2018". This field is directly retrieved from the source specified in the column `source`. Moreover, accents were removed to comply with CRAN that only allows ASCII characters.
|
||||
#' - `oxygen_tolerance` \cr Oxygen tolerance, either `r vector_or(microorganisms$oxygen_tolerance, documentation = TRUE)`. These data were retrieved from BacDive (see *Source*). Items that contain "likely" are missing from BacDive and were extrapolated from other species within the same genus to guess the oxygen tolerance. Currently `r round(length(microorganisms$oxygen_tolerance[which(!is.na(microorganisms$oxygen_tolerance))]) / nrow(microorganisms[which(microorganisms$kingdom == "Bacteria"), ]) * 100, 1)`% of all `r format_included_data_number(nrow(microorganisms[which(microorganisms$kingdom == "Bacteria"), ]))` bacteria in the data set contain an oxygen tolerance.
|
||||
#' - `morphology` \cr Morphology (cell shape), either `r vector_or(microorganisms$morphology, documentation = TRUE)`. These data were retrieved from BacDive (see *Source*). Genera that are clinically established as coccobacilli (the HACEK group and beyond, such as *Haemophilus* and *Acinetobacter*) are classified as such regardless of BacDive majority vote. Items that contain "likely" are missing from BacDive and were extrapolated from other species within the same genus. Currently `r round(length(microorganisms$morphology[which(!is.na(microorganisms$morphology))]) / nrow(microorganisms[which(microorganisms$kingdom == "Bacteria"), ]) * 100, 1)`% of all `r format_included_data_number(nrow(microorganisms[which(microorganisms$kingdom == "Bacteria"), ]))` bacteria in the data set contain a morphology.
|
||||
#' - `source`\cr Either `r vector_or(microorganisms$source, documentation = TRUE)` (see *Source*)
|
||||
#' - `lpsn`\cr Identifier ('Record number') of `r TAXONOMY_VERSION$LPSN$name`. This will be the first/highest LPSN identifier to keep one identifier per row. For example, *Acetobacter ascendens* has LPSN Record number 7864 and 11011. Only the first is available in the `microorganisms` data set. ***This is a unique identifier***, though available for only `r format_included_data_number(sum(!is.na(microorganisms$lpsn)))` records.
|
||||
#' - `lpsn_parent`\cr LPSN identifier of the parent taxon
|
||||
@@ -308,7 +307,7 @@
|
||||
#' - `is_SDD`\cr A [logical] value (`TRUE`/`FALSE`) to indicate whether the intermediate range between "S" and "R" should be interpreted as "SDD", instead of "I". This currently applies to `r sum(clinical_breakpoints$is_SDD)` breakpoints.
|
||||
#' @details
|
||||
#' ### Different Types of Breakpoints
|
||||
#' Supported types of breakpoints are `r vector_and(clinical_breakpoints$type, quotes = FALSE)`. ECOFF (Epidemiological cut-off) values are used in antimicrobial susceptibility testing to differentiate between wild-type and non-wild-type strains of bacteria or fungi.
|
||||
#' Supported types of breakpoints are `r vector_and(clinical_breakpoints$type, quote = FALSE)`. ECOFF (Epidemiological cut-off) values are used in antimicrobial susceptibility testing to differentiate between wild-type and non-wild-type strains of bacteria or fungi.
|
||||
#'
|
||||
#' The default is `"human"`, which can also be set with the package option [`AMR_breakpoint_type`][AMR-options]. Use [`as.sir(..., breakpoint_type = ...)`][as.sir()] to interpret raw data using a specific breakpoint type, e.g. `as.sir(..., breakpoint_type = "ECOFF")` to use ECOFFs.
|
||||
#'
|
||||
|
||||
0
R/first_isolate.R
Executable file → Normal file
0
R/first_isolate.R
Executable file → Normal file
0
R/get_episode.R
Executable file → Normal file
0
R/get_episode.R
Executable file → Normal file
@@ -62,17 +62,17 @@ format_eucast_version_nr <- function(version, markdown = TRUE) {
|
||||
#' @param x A data set with antimicrobials columns, such as `amox`, `AMX` and `AMC`.
|
||||
#' @param info A [logical] to indicate whether progress should be printed to the console - the default is only print while in interactive sessions.
|
||||
#' @param guideline A guideline name, either "EUCAST" (default) or "CLSI". This can be set with the package option [`AMR_guideline`][AMR-options].
|
||||
#' @param rules A [character] vector that specifies which rules should be applied. Must be one or more of `"breakpoints"`, `"expected_phenotypes"`, `"expert"`, `"other"`, `"custom"`, `"all"`, and defaults to `c("breakpoints", "expected_phenotypes")`. The default value can be set to another value using the package option [`AMR_interpretive_rules`][AMR-options]: `options(AMR_interpretive_rules = "all")`. If using `"custom"`, be sure to fill in argument `custom_rules` too. Custom rules can be created with [custom_interpretive_rules()].
|
||||
#' @param rules A [character] vector that specifies which rules should be applied. Must be one or more of `"breakpoints"`, `"expected_phenotypes"`, `"expert"`, `"other"`, `"custom"`, `"all"`, and defaults to `c("breakpoints", "expected_phenotypes")`. The default value can be set to another value using the package option [`AMR_interpretive_rules`][AMR-options]: `options(AMR_interpretive_rules = "all")`. If using `"custom"`, be sure to fill in argument `custom_rules` too. Custom rules can be created with [custom_eucast_rules()].
|
||||
#' @param verbose A [logical] to turn Verbose mode on and off (default is off). In Verbose mode, the function does not apply rules to the data, but instead returns a data set in logbook form with extensive info about which rows and columns would be effected and in which way. Using Verbose mode takes a lot more time.
|
||||
#' @param version_breakpoints The version number to use for the EUCAST Clinical Breakpoints guideline. Can be `r vector_or(names(EUCAST_VERSION_BREAKPOINTS), documentation = TRUE, reverse = TRUE)`.
|
||||
#' @param version_expected_phenotypes The version number to use for the EUCAST Expected Phenotypes. Can be `r vector_or(names(EUCAST_VERSION_EXPECTED_PHENOTYPES), documentation = TRUE, reverse = TRUE)`.
|
||||
#' @param version_expertrules The version number to use for the EUCAST Expert Rules and Intrinsic Resistance guideline. Can be `r vector_or(names(EUCAST_VERSION_EXPERT_RULES), documentation = TRUE, reverse = TRUE)`.
|
||||
#' @param ampc_cephalosporin_resistance (only applies when `rules` contains `"expert"` or `"all"`) a [character] value that should be applied to cefotaxime, ceftriaxone and ceftazidime for AmpC de-repressed cephalosporin-resistant mutants - the default is `NA`. Currently only works when `version_expertrules` is `3.2` and higher; these versions of '*EUCAST Expert Rules on Enterobacterales*' state that results of cefotaxime, ceftriaxone and ceftazidime should be reported with a note, or results should be suppressed (emptied) for these three drugs. A value of `NA` (the default) for this argument will remove results for these three drugs, while e.g. a value of `"R"` will make the results for these drugs resistant. Use `NULL` or `FALSE` to not alter results for these three drugs of AmpC de-repressed cephalosporin-resistant mutants. Using `TRUE` is equal to using `"R"`. \cr For *EUCAST Expert Rules* v3.2, this rule applies to: `r vector_and(gsub("[^a-zA-Z ]+", "", unlist(strsplit(INTERPRETIVE_RULES_DF[which(INTERPRETIVE_RULES_DF$reference.version %in% c(3.2, 3.3) & INTERPRETIVE_RULES_DF$reference.rule %like% "ampc"), "this_value"][1], "|", fixed = TRUE))), quotes = "*")`.
|
||||
#' @param version_expected_phenotypes The version number to use for the EUCAST Expected Phenotypes. Can be `r vector_or(names(EUCAST_VERSION_EXPECTED_PHENOTYPES), reverse = TRUE)`.
|
||||
#' @param version_expertrules The version number to use for the EUCAST Expert Rules and Intrinsic Resistance guideline. Can be `r vector_or(names(EUCAST_VERSION_EXPERT_RULES), reverse = TRUE)`.
|
||||
#' @param ampc_cephalosporin_resistance (only applies when `rules` contains `"expert"` or `"all"`) a [character] value that should be applied to cefotaxime, ceftriaxone and ceftazidime for AmpC de-repressed cephalosporin-resistant mutants - the default is `NA`. Currently only works when `version_expertrules` is `3.2` and higher; these versions of '*EUCAST Expert Rules on Enterobacterales*' state that results of cefotaxime, ceftriaxone and ceftazidime should be reported with a note, or results should be suppressed (emptied) for these three drugs. A value of `NA` (the default) for this argument will remove results for these three drugs, while e.g. a value of `"R"` will make the results for these drugs resistant. Use `NULL` or `FALSE` to not alter results for these three drugs of AmpC de-repressed cephalosporin-resistant mutants. Using `TRUE` is equal to using `"R"`. \cr For *EUCAST Expert Rules* v3.2, this rule applies to: `r vector_and(gsub("[^a-zA-Z ]+", "", unlist(strsplit(EUCAST_RULES_DF[which(EUCAST_RULES_DF$reference.version %in% c(3.2, 3.3) & EUCAST_RULES_DF$reference.rule %like% "ampc"), "this_value"][1], "|", fixed = TRUE))), quotes = "*")`.
|
||||
#' @param ... Column names of antimicrobials. To automatically detect antimicrobial column names, do not provide any named arguments; [guess_ab_col()] will then be used for detection. To manually specify a column, provide its name (case-insensitive) as an argument, e.g. `AMX = "amoxicillin"`. To skip a specific antimicrobial, set it to `NULL`, e.g. `TIC = NULL` to exclude ticarcillin. If a manually defined column does not exist in the data, it will be skipped with a warning.
|
||||
#' @param ab Any (vector of) text that can be coerced to a valid antimicrobial drug code with [as.ab()].
|
||||
#' @param administration Route of administration, either `r vector_or(dosage$administration, documentation = TRUE)`.
|
||||
#' @param administration Route of administration, either `r vector_or(dosage$administration)`.
|
||||
#' @param only_sir_columns A [logical] to indicate whether only antimicrobial columns must be included that were transformed to class [sir][as.sir()] on beforehand. Defaults to `FALSE` if no columns of `x` have a class [sir][as.sir()].
|
||||
#' @param custom_rules Custom rules to apply, created with [custom_interpretive_rules()].
|
||||
#' @param custom_rules Custom rules to apply, created with [custom_eucast_rules()].
|
||||
#' @param overwrite A [logical] indicating whether to overwrite existing SIR values (default: `FALSE`). When `FALSE`, only non-SIR values are modified (i.e., any value that is not already S, I or R). To ensure compliance with EUCAST guidelines, **this should remain** `FALSE`, as EUCAST notes often state that an organism "should be tested for susceptibility to individual agents or be reported resistant".
|
||||
#' @param add_if_missing A [logical] indicating whether rules should also be applied to missing (`NA`) values (default: `TRUE`). When `FALSE`, rules are only applied to cells that already contain an SIR value; cells with `NA` are left untouched. This is particularly useful when using `overwrite = TRUE` with custom rules and you want to update reported results without imputing values for untested drugs.
|
||||
#' @inheritParams first_isolate
|
||||
@@ -80,17 +80,17 @@ format_eucast_version_nr <- function(version, markdown = TRUE) {
|
||||
#' **Note:** This function does not translate MIC or disk values to SIR values. Use [as.sir()] for that. \cr
|
||||
#' **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 interpretive rules is located here: <https://github.com/msberends/AMR/blob/main/data-raw/interpretive_rules.tsv>. **Note:** Old taxonomic names are replaced with the current taxonomy where applicable. For example, *Ochrobactrum anthropi* was renamed to *Brucella anthropi* in 2020; the original EUCAST rules v3.1 and v3.2 did not yet contain this new taxonomic name. The `AMR` package contains the full microbial taxonomy updated until `r documentation_date(max(TAXONOMY_VERSION$GBIF$accessed_date, TAXONOMY_VERSION$LPSN$accessed_date))`, see [microorganisms].
|
||||
#' The file containing all EUCAST rules is located here: <https://github.com/msberends/AMR/blob/main/data-raw/eucast_rules.tsv>. **Note:** Old taxonomic names are replaced with the current taxonomy where applicable. For example, *Ochrobactrum anthropi* was renamed to *Brucella anthropi* in 2020; the original EUCAST rules v3.1 and v3.2 did not yet contain this new taxonomic name. The `AMR` package contains the full microbial taxonomy updated until `r documentation_date(max(TAXONOMY_VERSION$GBIF$accessed_date, TAXONOMY_VERSION$LPSN$accessed_date))`, see [microorganisms].
|
||||
#'
|
||||
#' ### Custom Rules
|
||||
#'
|
||||
#' Custom rules can be created using [custom_interpretive_rules()], e.g.:
|
||||
#' Custom rules can be created using [custom_eucast_rules()], e.g.:
|
||||
#'
|
||||
#' ```r
|
||||
#' x <- custom_interpretive_rules(AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
|
||||
#' AMC == "I" & genus == "Klebsiella" ~ aminopenicillins == "I")
|
||||
#' x <- custom_eucast_rules(AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
|
||||
#' AMC == "I" & genus == "Klebsiella" ~ aminopenicillins == "I")
|
||||
#'
|
||||
#' interpretive_rules(example_isolates, rules = "custom", custom_rules = x)
|
||||
#' eucast_rules(example_isolates, rules = "custom", custom_rules = x)
|
||||
#' ```
|
||||
#'
|
||||
#' ### 'Other' Rules
|
||||
@@ -102,7 +102,7 @@ format_eucast_version_nr <- function(version, markdown = TRUE) {
|
||||
#'
|
||||
#' Important examples include amoxicillin and amoxicillin/clavulanic acid, and trimethoprim and trimethoprim/sulfamethoxazole. Needless to say, for these rules to work, both drugs must be available in the data set.
|
||||
#'
|
||||
#' Since these rules are not officially approved by EUCAST, they are not applied at default. To use these rules, include `"other"` to the `rules` argument, or use `interpretive_rules(..., rules = "all")`. You can also set the package option [`AMR_interpretive_rules`][AMR-options], i.e. run `options(AMR_interpretive_rules = "all")`.
|
||||
#' Since these rules are not officially approved by EUCAST, they are not applied at default. To use these rules, include `"other"` to the `rules` argument, or use `eucast_rules(..., rules = "all")`. You can also set the package option [`AMR_interpretive_rules`][AMR-options], i.e. run `options(AMR_interpretive_rules = "all")`.
|
||||
#' @aliases EUCAST
|
||||
#' @rdname interpretive_rules
|
||||
#' @export
|
||||
@@ -184,7 +184,7 @@ interpretive_rules <- function(x,
|
||||
meet_criteria(version_expertrules, allow_class = c("numeric", "integer"), has_length = 1, is_in = as.double(names(EUCAST_VERSION_EXPERT_RULES)))
|
||||
meet_criteria(ampc_cephalosporin_resistance, allow_class = c("logical", "character", "sir"), has_length = 1, allow_NA = TRUE, allow_NULL = TRUE)
|
||||
meet_criteria(only_sir_columns, allow_class = "logical", has_length = 1)
|
||||
meet_criteria(custom_rules, allow_class = c("custom_interpretive_rules", "custom_eucast_rules"), allow_NULL = TRUE)
|
||||
meet_criteria(custom_rules, allow_class = "custom_eucast_rules", allow_NULL = TRUE)
|
||||
meet_criteria(overwrite, allow_class = "logical", has_length = 1)
|
||||
meet_criteria(add_if_missing, allow_class = "logical", has_length = 1)
|
||||
|
||||
@@ -193,6 +193,11 @@ interpretive_rules <- function(x,
|
||||
"Either set {.arg overwrite} or {.arg add_if_missing} to {.code TRUE}, or both."
|
||||
)
|
||||
|
||||
stop_if(
|
||||
guideline == "CLSI",
|
||||
"CLSI guideline is not yet supported."
|
||||
)
|
||||
|
||||
stop_if(
|
||||
!is.na(ampc_cephalosporin_resistance) && !any(c("expert", "all") %in% rules),
|
||||
"For the {.arg ampc_cephalosporin_resistance} argument to work, the {.arg rules} argument must contain {.code \"expert\"} or {.code \"all\"}."
|
||||
@@ -200,14 +205,8 @@ interpretive_rules <- function(x,
|
||||
|
||||
add_MO_lookup_to_AMR_env()
|
||||
|
||||
if (guideline %like% "EUCAST") {
|
||||
guideline <- "EUCAST"
|
||||
} else if (guideline %like% "CLSI") {
|
||||
guideline <- "CLSI"
|
||||
}
|
||||
|
||||
if ("custom" %in% rules && is.null(custom_rules)) {
|
||||
warning_("in {.help [{.fun interpretive_rules}](AMR::interpretive_rules)}: no custom rules were set with the {.arg custom_rules} argument",
|
||||
warning_("in {.help [{.fun eucast_rules}](AMR::eucast_rules)}: no custom rules were set with the {.arg custom_rules} argument",
|
||||
immediate = TRUE
|
||||
)
|
||||
rules <- rules[rules != "custom"]
|
||||
@@ -230,13 +229,13 @@ interpretive_rules <- function(x,
|
||||
|
||||
if (interactive() && isTRUE(verbose) && isTRUE(info)) {
|
||||
txt <- paste0(
|
||||
"WARNING: In Verbose mode, the interpretive_rules() function does not apply rules to the data, but instead returns a data set in logbook form with comprehensive info about which rows and columns would be effected and in which way.",
|
||||
"WARNING: In Verbose mode, the eucast_rules() function does not apply rules to the data, but instead returns a data set in logbook form with comprehensive info about which rows and columns would be effected and in which way.",
|
||||
"\n\nThis may overwrite your existing data if you use e.g.:",
|
||||
"\ndata <- interpretive_rules(data, verbose = TRUE)\n\nDo you want to continue?"
|
||||
"\ndata <- eucast_rules(data, verbose = TRUE)\n\nDo you want to continue?"
|
||||
)
|
||||
showQuestion <- import_fn("showQuestion", "rstudioapi", error_on_fail = FALSE)
|
||||
if (!is.null(showQuestion)) {
|
||||
q_continue <- showQuestion("Using verbose = TRUE with interpretive_rules()", txt)
|
||||
q_continue <- showQuestion("Using verbose = TRUE with eucast_rules()", txt)
|
||||
} else {
|
||||
q_continue <- utils::menu(choices = c("OK", "Cancel"), graphics = FALSE, title = txt)
|
||||
}
|
||||
@@ -331,7 +330,7 @@ interpretive_rules <- function(x,
|
||||
verbose = verbose,
|
||||
info = info,
|
||||
only_sir_columns = only_sir_columns,
|
||||
fn = "interpretive_rules",
|
||||
fn = "eucast_rules",
|
||||
...
|
||||
)
|
||||
|
||||
@@ -490,7 +489,7 @@ interpretive_rules <- function(x,
|
||||
"Rules by the ",
|
||||
font_bold(paste0("AMR package v", utils::packageDescription("AMR")$Version)),
|
||||
" (", format(as.Date(utils::packageDescription("AMR")$Date), format = "%Y"),
|
||||
"), see {.help [{.fun interpretive_rules}](AMR::interpretive_rules)}\n"
|
||||
"), see {.help [{.fun eucast_rules}](AMR::eucast_rules)}\n"
|
||||
)
|
||||
))
|
||||
cat("\n\n")
|
||||
@@ -612,62 +611,59 @@ interpretive_rules <- function(x,
|
||||
|
||||
if (!any(c("all", "custom") %in% rules) && !is.null(custom_rules)) {
|
||||
if (isTRUE(info)) {
|
||||
message_("Skipping custom interpretive rules, since the {.arg rules} argument does not contain {.code \"custom\"}.")
|
||||
message_("Skipping custom EUCAST rules, since the {.arg rules} argument does not contain {.code \"custom\"}.")
|
||||
}
|
||||
custom_rules <- NULL
|
||||
}
|
||||
|
||||
# >>> Apply Official interpretive rules <<< ---------------------------------------------------
|
||||
# >>> Apply Official EUCAST rules <<< ---------------------------------------------------
|
||||
eucast_notification_shown <- FALSE
|
||||
if (!is.null(list(...)$interpretive_rules_df)) {
|
||||
# this allows: interpretive_rules(x, interpretive_rules_df = AMR:::INTERPRETIVE_RULES_DF |> filter(is.na(have_these_values)))
|
||||
interpretive_rules_df_total <- list(...)$interpretive_rules_df
|
||||
} else if (!is.null(list(...)$eucast_rules_df)) {
|
||||
# deprecated parameter name kept for backward compatibility
|
||||
interpretive_rules_df_total <- list(...)$eucast_rules_df
|
||||
if (!is.null(list(...)$eucast_rules_df)) {
|
||||
# this allows: eucast_rules(x, eucast_rules_df = AMR:::EUCAST_RULES_DF %>% filter(is.na(have_these_values)))
|
||||
eucast_rules_df_total <- list(...)$eucast_rules_df
|
||||
} else {
|
||||
# internal data file, created in data-raw/_pre_commit_checks.R
|
||||
interpretive_rules_df_total <- INTERPRETIVE_RULES_DF
|
||||
# otherwise internal data file, created in data-raw/_pre_commit_checks.R
|
||||
eucast_rules_df_total <- EUCAST_RULES_DF
|
||||
}
|
||||
|
||||
## filter on guideline provider and user-set guideline versions ----
|
||||
interpretive_rules_df <- data.frame()
|
||||
## filter on user-set guideline versions ----
|
||||
eucast_rules_df <- data.frame()
|
||||
if (any(c("all", "breakpoints") %in% rules)) {
|
||||
interpretive_rules_df <- interpretive_rules_df %pm>%
|
||||
rbind_AMR(interpretive_rules_df_total %pm>%
|
||||
subset(rule.provider == guideline & reference.rule_group %like% "breakpoint" & reference.version == version_breakpoints))
|
||||
eucast_rules_df <- eucast_rules_df %pm>%
|
||||
rbind_AMR(eucast_rules_df_total %pm>%
|
||||
subset(reference.rule_group %like% "breakpoint" & reference.version == version_breakpoints))
|
||||
}
|
||||
if (any(c("all", "expected_phenotypes") %in% rules)) {
|
||||
interpretive_rules_df <- interpretive_rules_df %pm>%
|
||||
rbind_AMR(interpretive_rules_df_total %pm>%
|
||||
subset(rule.provider == guideline & reference.rule_group %like% "expected" & reference.version == version_expected_phenotypes))
|
||||
eucast_rules_df <- eucast_rules_df %pm>%
|
||||
rbind_AMR(eucast_rules_df_total %pm>%
|
||||
subset(reference.rule_group %like% "expected" & reference.version == version_expected_phenotypes))
|
||||
}
|
||||
if (any(c("all", "expert") %in% rules)) {
|
||||
interpretive_rules_df <- interpretive_rules_df %pm>%
|
||||
rbind_AMR(interpretive_rules_df_total %pm>%
|
||||
subset(rule.provider == guideline & reference.rule_group %like% "expert" & reference.version == version_expertrules))
|
||||
eucast_rules_df <- eucast_rules_df %pm>%
|
||||
rbind_AMR(eucast_rules_df_total %pm>%
|
||||
subset(reference.rule_group %like% "expert" & reference.version == version_expertrules))
|
||||
}
|
||||
## filter out AmpC de-repressed cephalosporin-resistant mutants ----
|
||||
# no need to filter on version number here - the rules contain these version number, so are inherently filtered
|
||||
# cefotaxime, ceftriaxone, ceftazidime
|
||||
if (is.null(ampc_cephalosporin_resistance) || isFALSE(ampc_cephalosporin_resistance)) {
|
||||
interpretive_rules_df <- subset(
|
||||
interpretive_rules_df,
|
||||
eucast_rules_df <- subset(
|
||||
eucast_rules_df,
|
||||
reference.rule %unlike% "ampc"
|
||||
)
|
||||
} else {
|
||||
if (isTRUE(ampc_cephalosporin_resistance)) {
|
||||
ampc_cephalosporin_resistance <- "R"
|
||||
}
|
||||
if (!is.null(interpretive_rules_df$reference.rule)) {
|
||||
interpretive_rules_df[which(interpretive_rules_df$reference.rule %like% "ampc"), "to_value"] <- as.character(ampc_cephalosporin_resistance)
|
||||
if (!is.null(eucast_rules_df$reference.rule)) {
|
||||
eucast_rules_df[which(eucast_rules_df$reference.rule %like% "ampc"), "to_value"] <- as.character(ampc_cephalosporin_resistance)
|
||||
}
|
||||
}
|
||||
|
||||
# sometimes, the screenings are missing but the names are actually available
|
||||
# we only hints on remaining rows in `interpretive_rules_df`
|
||||
# we only hints on remaining rows in `eucast_rules_df`
|
||||
screening_abx <- as.character(AMR::antimicrobials$ab[which(AMR::antimicrobials$ab %like% "-S$")])
|
||||
screening_abx <- screening_abx[screening_abx %in% unique(unlist(strsplit(interpretive_rules_df_total$and_these_antibiotics[!is.na(interpretive_rules_df_total$and_these_antibiotics)], ", *")))]
|
||||
screening_abx <- screening_abx[screening_abx %in% unique(unlist(strsplit(EUCAST_RULES_DF$and_these_antibiotics[!is.na(EUCAST_RULES_DF$and_these_antibiotics)], ", *")))]
|
||||
if (isTRUE(info)) {
|
||||
cat("\n")
|
||||
}
|
||||
@@ -686,12 +682,12 @@ interpretive_rules <- function(x,
|
||||
}
|
||||
|
||||
## Go over all rules and apply them ----
|
||||
for (i in seq_len(nrow(interpretive_rules_df))) {
|
||||
rule_previous <- interpretive_rules_df[max(1, i - 1), "reference.rule", drop = TRUE]
|
||||
rule_current <- interpretive_rules_df[i, "reference.rule", drop = TRUE]
|
||||
rule_next <- interpretive_rules_df[min(nrow(interpretive_rules_df), i + 1), "reference.rule", drop = TRUE]
|
||||
rule_group_previous <- interpretive_rules_df[max(1, i - 1), "reference.rule_group", drop = TRUE]
|
||||
rule_group_current <- interpretive_rules_df[i, "reference.rule_group", drop = TRUE]
|
||||
for (i in seq_len(nrow(eucast_rules_df))) {
|
||||
rule_previous <- eucast_rules_df[max(1, i - 1), "reference.rule", drop = TRUE]
|
||||
rule_current <- eucast_rules_df[i, "reference.rule", drop = TRUE]
|
||||
rule_next <- eucast_rules_df[min(nrow(eucast_rules_df), i + 1), "reference.rule", drop = TRUE]
|
||||
rule_group_previous <- eucast_rules_df[max(1, i - 1), "reference.rule_group", drop = TRUE]
|
||||
rule_group_current <- eucast_rules_df[i, "reference.rule_group", drop = TRUE]
|
||||
# don't apply rules if user doesn't want to apply them
|
||||
if (rule_group_current %like% "breakpoint" && !any(c("all", "breakpoints") %in% rules)) {
|
||||
next
|
||||
@@ -706,16 +702,16 @@ interpretive_rules <- function(x,
|
||||
if (isFALSE(info) || isFALSE(verbose)) {
|
||||
rule_text <- ""
|
||||
} else {
|
||||
if (is.na(interpretive_rules_df[i, "and_these_antibiotics", drop = TRUE])) {
|
||||
rule_text <- paste0("always report as '", interpretive_rules_df[i, "to_value", drop = TRUE], "': ", get_antibiotic_names(interpretive_rules_df[i, "then_change_these_antibiotics", drop = TRUE]))
|
||||
if (is.na(eucast_rules_df[i, "and_these_antibiotics", drop = TRUE])) {
|
||||
rule_text <- paste0("always report as '", eucast_rules_df[i, "to_value", drop = TRUE], "': ", get_antibiotic_names(eucast_rules_df[i, "then_change_these_antibiotics", drop = TRUE]))
|
||||
} else {
|
||||
rule_text <- paste0(
|
||||
"report as '", interpretive_rules_df[i, "to_value", drop = TRUE], "' when ",
|
||||
"report as '", eucast_rules_df[i, "to_value", drop = TRUE], "' when ",
|
||||
format_antibiotic_names(
|
||||
ab_names = get_antibiotic_names(interpretive_rules_df[i, "and_these_antibiotics", drop = TRUE]),
|
||||
ab_results = interpretive_rules_df[i, "have_these_values", drop = TRUE]
|
||||
ab_names = get_antibiotic_names(eucast_rules_df[i, "and_these_antibiotics", drop = TRUE]),
|
||||
ab_results = eucast_rules_df[i, "have_these_values", drop = TRUE]
|
||||
), ": ",
|
||||
get_antibiotic_names(interpretive_rules_df[i, "then_change_these_antibiotics", drop = TRUE])
|
||||
get_antibiotic_names(eucast_rules_df[i, "then_change_these_antibiotics", drop = TRUE])
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -724,7 +720,7 @@ interpretive_rules <- function(x,
|
||||
rule_previous <- ""
|
||||
rule_group_previous <- ""
|
||||
}
|
||||
if (i == nrow(interpretive_rules_df)) {
|
||||
if (i == nrow(eucast_rules_df)) {
|
||||
rule_next <- ""
|
||||
}
|
||||
|
||||
@@ -793,13 +789,13 @@ interpretive_rules <- function(x,
|
||||
}
|
||||
|
||||
## Get rule from file ------------------------------------------------------
|
||||
if_mo_property <- trimws(interpretive_rules_df[i, "if_mo_property", drop = TRUE])
|
||||
like_is_one_of <- trimws(interpretive_rules_df[i, "like.is.one_of", drop = TRUE])
|
||||
mo_value <- trimws(interpretive_rules_df[i, "this_value", drop = TRUE])
|
||||
source_antibiotics <- interpretive_rules_df[i, "and_these_antibiotics", drop = TRUE]
|
||||
source_value <- trimws(unlist(strsplit(interpretive_rules_df[i, "have_these_values", drop = TRUE], ",", fixed = TRUE)))
|
||||
target_antibiotics <- interpretive_rules_df[i, "then_change_these_antibiotics", drop = TRUE]
|
||||
target_value <- interpretive_rules_df[i, "to_value", drop = TRUE]
|
||||
if_mo_property <- trimws(eucast_rules_df[i, "if_mo_property", drop = TRUE])
|
||||
like_is_one_of <- trimws(eucast_rules_df[i, "like.is.one_of", drop = TRUE])
|
||||
mo_value <- trimws(eucast_rules_df[i, "this_value", drop = TRUE])
|
||||
source_antibiotics <- eucast_rules_df[i, "and_these_antibiotics", drop = TRUE]
|
||||
source_value <- trimws(unlist(strsplit(eucast_rules_df[i, "have_these_values", drop = TRUE], ",", fixed = TRUE)))
|
||||
target_antibiotics <- eucast_rules_df[i, "then_change_these_antibiotics", drop = TRUE]
|
||||
target_value <- eucast_rules_df[i, "to_value", drop = TRUE]
|
||||
|
||||
# if amo_value contains a group name, expand that name with all species in it
|
||||
if (any(trimws(strsplit(mo_value, ",")[[1]]) %in% AMR::microorganisms.groups$mo_group_name, na.rm = TRUE)) {
|
||||
@@ -898,7 +894,7 @@ interpretive_rules <- function(x,
|
||||
if (!is.null(custom_rules)) {
|
||||
if (isTRUE(info)) {
|
||||
cat("\n")
|
||||
cat(font_bold("Custom interpretive rules, set by user"), "\n")
|
||||
cat(font_bold("Custom EUCAST rules, set by user"), "\n")
|
||||
}
|
||||
for (i in seq_len(length(custom_rules))) {
|
||||
rule <- custom_rules[[i]]
|
||||
@@ -933,8 +929,8 @@ interpretive_rules <- function(x,
|
||||
to = target_value,
|
||||
rule = c(
|
||||
rule_text,
|
||||
"Custom interpretive rules",
|
||||
paste0("Custom interpretive rule ", i),
|
||||
"Custom EUCAST rules",
|
||||
paste0("Custom EUCAST rule ", i),
|
||||
paste0(
|
||||
"Object '", deparse(substitute(custom_rules)),
|
||||
"' consisting of ", length(custom_rules), " custom rules"
|
||||
@@ -1079,13 +1075,13 @@ interpretive_rules <- function(x,
|
||||
warn_lacking_sir_class <- warn_lacking_sir_class[order(colnames(x.bak))]
|
||||
warn_lacking_sir_class <- warn_lacking_sir_class[!is.na(warn_lacking_sir_class)]
|
||||
warning_(
|
||||
"in {.help [{.fun interpretive_rules}](AMR::interpretive_rules)}: not all columns with antimicrobial results are of class {.cls sir}. Transform them on beforehand, e.g.:\n\n",
|
||||
"\u00a0\u00a0", AMR_env$bullet_icon, " ", highlight_code(paste0(x_deparsed, " |> as.sir(", ifelse(length(warn_lacking_sir_class) == 1,
|
||||
"in {.help [{.fun eucast_rules}](AMR::eucast_rules)}: not all columns with antimicrobial results are of class {.cls sir}. Transform them on beforehand, e.g.:\n",
|
||||
" - ", highlight_code(paste0(x_deparsed, " %>% as.sir(", ifelse(length(warn_lacking_sir_class) == 1,
|
||||
warn_lacking_sir_class,
|
||||
paste0(warn_lacking_sir_class[1], ":", warn_lacking_sir_class[length(warn_lacking_sir_class)])
|
||||
), ")")), "\n\n",
|
||||
"\u00a0\u00a0", AMR_env$bullet_icon, " ", highlight_code(paste0(x_deparsed, " |> mutate_if(is_sir_eligible, as.sir)")), "\n\n",
|
||||
"\u00a0\u00a0", AMR_env$bullet_icon, " ", highlight_code(paste0(x_deparsed, " |> mutate(across(where(is_sir_eligible), as.sir))"))
|
||||
), ")")), "\n",
|
||||
" - ", highlight_code(paste0(x_deparsed, " %>% mutate_if(is_sir_eligible, as.sir)")), "\n",
|
||||
" - ", highlight_code(paste0(x_deparsed, " %>% mutate(across(where(is_sir_eligible), as.sir))"))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1143,7 +1139,6 @@ edit_sir <- function(x,
|
||||
overwrite,
|
||||
add_if_missing) {
|
||||
cols <- unique(cols[!is.na(cols) & !is.null(cols)])
|
||||
rows <- unique(rows)
|
||||
|
||||
# for Verbose Mode, keep track of all changes and return them
|
||||
track_changes <- list(
|
||||
@@ -1170,60 +1165,41 @@ edit_sir <- function(x,
|
||||
track_changes$sir_warn <- cols[!vapply(FUN.VALUE = logical(1), x[, cols, drop = FALSE], is.sir)]
|
||||
}
|
||||
isNA <- is.na(new_edits[rows, cols])
|
||||
isSIR <- !isNA &
|
||||
(new_edits[rows, cols] == "S" |
|
||||
new_edits[rows, cols] == "I" |
|
||||
new_edits[rows, cols] == "R" |
|
||||
new_edits[rows, cols] == "SDD" |
|
||||
new_edits[rows, cols] == "NI" |
|
||||
new_edits[rows, cols] == "WT" |
|
||||
new_edits[rows, cols] == "NWT" |
|
||||
new_edits[rows, cols] == "NS")
|
||||
isSIR <- !isNA & (new_edits[rows, cols] == "S" | new_edits[rows, cols] == "I" | new_edits[rows, cols] == "R" | new_edits[rows, cols] == "SDD" | new_edits[rows, cols] == "NI" | new_edits[rows, cols] == "WT" | new_edits[rows, cols] == "NWT" | new_edits[rows, cols] == "NS")
|
||||
non_SIR <- !isSIR
|
||||
if (isFALSE(overwrite) && any(isSIR) && message_not_thrown_before("edit_sir.warning_overwrite")) {
|
||||
warning_("in {.help [{.fun interpretive_rules}](AMR::interpretive_rules)}: some columns had SIR values which were not overwritten, since {.code overwrite = FALSE}.")
|
||||
warning_("Some values had SIR values and were not overwritten, since {.code overwrite = FALSE}.")
|
||||
}
|
||||
# determine which cells to modify based on overwrite and add_if_missing
|
||||
if (isTRUE(overwrite)) {
|
||||
if (isTRUE(add_if_missing)) {
|
||||
apply_mask <- rep(TRUE, length(isSIR))
|
||||
} else {
|
||||
apply_mask <- isSIR
|
||||
}
|
||||
apply_mask <- if (isTRUE(overwrite)) {
|
||||
if (isFALSE(add_if_missing)) !isNA else rep(TRUE, length(isNA))
|
||||
} else {
|
||||
# overwrite = FALSE, add_if_missing = TRUE: fill missing and placeholder cells only
|
||||
apply_mask <- !isSIR
|
||||
if (isFALSE(add_if_missing)) isSIR else non_SIR
|
||||
}
|
||||
|
||||
do_assign <- function() {
|
||||
subset <- new_edits[rows, cols, drop = FALSE]
|
||||
mask <- matrix(apply_mask, nrow = nrow(subset), ncol = ncol(subset))
|
||||
subset[mask] <- to
|
||||
new_edits[rows, cols] <<- subset
|
||||
}
|
||||
|
||||
warning_("test", call = T) # aaaaaaa
|
||||
tryCatch(
|
||||
do_assign(),
|
||||
# insert into original table
|
||||
new_edits[rows, cols][apply_mask] <- to,
|
||||
warning = function(w) {
|
||||
if (w$message %like% "invalid factor level") {
|
||||
vapply(FUN.VALUE = logical(1), cols, function(col) {
|
||||
xyz <- vapply(FUN.VALUE = logical(1), cols, function(col) {
|
||||
new_edits[, col] <<- factor(
|
||||
x = as.character(pm_pull(new_edits, col)),
|
||||
levels = unique(c(to, levels(pm_pull(new_edits, col))))
|
||||
)
|
||||
TRUE
|
||||
})
|
||||
suppressWarnings(do_assign())
|
||||
suppressWarnings(new_edits[rows, cols][apply_mask] <<- to)
|
||||
warning_(
|
||||
"in {.help [{.fun interpretive_rules}](AMR::interpretive_rules)}: value \"", to, "\" added to the factor levels of column",
|
||||
"in {.help [{.fun eucast_rules}](AMR::eucast_rules)}: value \"", to, "\" added to the factor levels of column",
|
||||
ifelse(length(cols) == 1, "", "s"),
|
||||
" ", vector_and(cols, quotes = "`", sort = FALSE),
|
||||
" because this value was not an existing factor level."
|
||||
)
|
||||
txt_warning()
|
||||
warned <<- FALSE
|
||||
warned <- FALSE
|
||||
} else {
|
||||
warning_("in {.help [{.fun interpretive_rules}](AMR::interpretive_rules)}: ", w$message)
|
||||
warning_("in {.help [{.fun eucast_rules}](AMR::eucast_rules)}: ", w$message)
|
||||
txt_warning()
|
||||
}
|
||||
},
|
||||
|
||||
25
R/mdro.R
25
R/mdro.R
@@ -84,7 +84,7 @@
|
||||
#'
|
||||
#' * `guideline = "BRMO 2024"` (or simply `guideline = "BRMO"`)
|
||||
#'
|
||||
#' The Dutch national guideline - Samenwerkingverband Richtlijnen Infectiepreventie (SRI) (2024) "Bijzonder Resistente Micro-Organismen (BRMO)" ([link](https://richtlijnendatabase.nl/richtlijn/bijzonder_resistente_micro-organismen_brmo))
|
||||
#' The Dutch national guideline - Samenwerkingverband Richtlijnen Infectiepreventie (SRI) (2024) "Bijzonder Resistente Micro-Organismen (BRMO)" ([link](https://www.sri-richtlijnen.nl/brmo))
|
||||
#'
|
||||
#' Also:
|
||||
#'
|
||||
@@ -379,7 +379,7 @@ mdro <- function(x = NULL,
|
||||
guideline$name <- "Bijzonder Resistente Micro-organismen (BRMO)"
|
||||
guideline$author <- "Samenwerkingsverband Richtlijnen Infectiepreventie (SRI)"
|
||||
guideline$version <- "November 2024"
|
||||
guideline$source_url <- font_url("https://richtlijnendatabase.nl/richtlijn/bijzonder_resistente_micro-organismen_brmo", "Direct link")
|
||||
guideline$source_url <- font_url("https://www.sri-richtlijnen.nl/brmo", "Direct link")
|
||||
guideline$type <- "BRMOs"
|
||||
} else if (guideline$code == "brmo2017") {
|
||||
guideline$name <- "WIP-Richtlijn Bijzonder Resistente Micro-organismen (BRMO)"
|
||||
@@ -510,13 +510,13 @@ mdro <- function(x = NULL,
|
||||
message_(
|
||||
"Inferring resistance for ",
|
||||
ab_name(.base_code, language = NULL, tolower = TRUE),
|
||||
" (", font_italic("missing"), ") from ",
|
||||
" (", font_bold(.base_code, collapse = NULL), ", ", font_italic("missing"), ") from ",
|
||||
vector_or(
|
||||
quotes = FALSE,
|
||||
last_sep = " and/or ",
|
||||
paste0(
|
||||
ab_name(.combos, language = NULL, tolower = TRUE),
|
||||
" ({.field ", font_bold(.combo_cols, collapse = NULL), "}, ", font_italic("available"), ")"
|
||||
" (", font_bold(.combos, collapse = NULL), ", ", font_italic("available"), ")"
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1558,13 +1558,12 @@ mdro <- function(x = NULL,
|
||||
reason = "Enterobacterales: carbapenemase"
|
||||
)
|
||||
c.freundii_complex <- AMR::microorganisms.groups$mo_name[AMR::microorganisms.groups$mo_group_name == "Citrobacter freundii complex"]
|
||||
c.freundii_complex <- paste(c.freundii_complex, collapse = "|")
|
||||
trans_tbl(
|
||||
3,
|
||||
rows = which(col_values(x, SXT) == "R" &
|
||||
(col_values(x, GEN) == "R" | col_values(x, TOB) == "R" | col_values(x, AMK) == "R") &
|
||||
(col_values(x, CIP) == "R" | col_values(x, NOR) == "R" | col_values(x, LVX) == "R") &
|
||||
(x$fullname %like_case% c.freundii_complex | x$genus %in% c("Enterobacter", "Providencia") | paste(x$genus, x$species) %in% c("Klebsiella aerogenes", "Hafnia alvei", "Morganella morganii"))),
|
||||
(x$genus %in% c("Enterobacter", "Providencia") | paste(x$genus, x$species) %in% c(c.freundii_complex, "Klebsiella aerogenes", "Hafnia alvei", "Morganella morganii"))),
|
||||
cols = c(SXT, aminoglycosides, fluoroquinolones),
|
||||
any_all = "any",
|
||||
reason = "Enterobacterales group II: aminoglycoside + fluoroquinolone + cotrimoxazol"
|
||||
@@ -1581,27 +1580,25 @@ mdro <- function(x = NULL,
|
||||
)
|
||||
|
||||
# Acinetobacter baumannii-calcoaceticus complex
|
||||
a.baumannii_complex <- AMR::microorganisms.groups$mo_name[AMR::microorganisms.groups$mo_group_name == "Acinetobacter baumannii complex"]
|
||||
a.baumannii_complex <- paste(a.baumannii_complex, collapse = "|")
|
||||
trans_tbl(
|
||||
3,
|
||||
rows = which((col_values(x, GEN) == "R" | col_values(x, TOB) == "R" | col_values(x, AMK) == "R") &
|
||||
(col_values(x, CIP) == "R" | col_values(x, LVX) == "R") &
|
||||
x$fullname %like_case% a.baumannii_complex),
|
||||
x[[col_mo]] %in% AMR::microorganisms.groups$mo[AMR::microorganisms.groups$mo_group_name == "Acinetobacter baumannii complex"]),
|
||||
cols = c(aminoglycosides, CIP, LVX),
|
||||
any_all = "any",
|
||||
reason = "A. baumannii-calcoaceticus complex: aminoglycoside + ciprofloxacin or levofloxacin"
|
||||
)
|
||||
trans_tbl(
|
||||
2, # unconfirmed
|
||||
rows = which(x$fullname %like_case% a.baumannii_complex & is.na(x$carbapenemase)),
|
||||
rows = which(x[[col_mo]] %in% AMR::microorganisms.groups$mo[AMR::microorganisms.groups$mo_group_name == "Acinetobacter baumannii complex"] & is.na(x$carbapenemase)),
|
||||
cols = carbapenems,
|
||||
any_all = "any",
|
||||
reason = "A. baumannii-calcoaceticus complex: potential carbapenemase"
|
||||
)
|
||||
trans_tbl(
|
||||
3,
|
||||
rows = which(x$fullname %like_case% a.baumannii_complex & x$carbapenemase == TRUE),
|
||||
rows = which(x[[col_mo]] %in% AMR::microorganisms.groups$mo[AMR::microorganisms.groups$mo_group_name == "Acinetobacter baumannii complex"] & x$carbapenemase == TRUE),
|
||||
cols = carbapenems,
|
||||
any_all = "any",
|
||||
reason = "A. baumannii-calcoaceticus complex: carbapenemase"
|
||||
@@ -1854,7 +1851,6 @@ mdro <- function(x = NULL,
|
||||
|
||||
if (isTRUE(info.bak)) {
|
||||
cat(group_msg)
|
||||
cat("\n")
|
||||
if (sum(!is.na(x$MDRO)) == 0) {
|
||||
cat(font_bold(paste0("=> Found 0 MDROs since no isolates are covered by the guideline")))
|
||||
} else {
|
||||
@@ -1877,15 +1873,14 @@ mdro <- function(x = NULL,
|
||||
))
|
||||
if (length(rows_empty) > 0) {
|
||||
if (isTRUE(info.bak)) {
|
||||
cat(font_italic(paste0("\n (another ", length(rows_empty), " isolates had no test results)\n")))
|
||||
cat(font_italic(paste0(" (", length(rows_empty), " isolates had no test results)\n")))
|
||||
}
|
||||
} else if (isTRUE(info.bak)) {
|
||||
cat("\n")
|
||||
}
|
||||
|
||||
if (isTRUE(info.bak) && !isTRUE(verbose)) {
|
||||
cat("\n")
|
||||
cat(format_inline_("Rerun with {.code verbose = TRUE} to retrieve detailed info and reasons for every MDRO classification.\n"))
|
||||
cat("\nRerun with 'verbose = TRUE' to retrieve detailed info and reasons for every MDRO classification.\n")
|
||||
}
|
||||
|
||||
# Results ----
|
||||
|
||||
47
R/mo.R
47
R/mo.R
@@ -322,15 +322,6 @@ as.mo <- function(x,
|
||||
return(as.character(MO_lookup_current$mo[match(x_out, MO_lookup_current$fullname_lower)]))
|
||||
}
|
||||
|
||||
# Issue #287: "X complex" is not a distinct taxon - strip " complex" and try "X"
|
||||
if (grepl(" complex$", x_out, ignore.case = FALSE)) {
|
||||
x_out <- sub(" complex$", "", x_out)
|
||||
x_search_cleaned <- sub(" [Cc]omplex$", "", x_search_cleaned)
|
||||
if (x_out %in% MO_lookup_current$fullname_lower) {
|
||||
return(as.character(MO_lookup_current$mo[match(x_out, MO_lookup_current$fullname_lower)]))
|
||||
}
|
||||
}
|
||||
|
||||
# input must not be too short
|
||||
if (nchar(x_out) < 3) {
|
||||
return("UNKNOWN")
|
||||
@@ -352,18 +343,6 @@ as.mo <- function(x,
|
||||
(MO_lookup_current$species_first == substr(x_parts[2], 1, 1) |
|
||||
MO_lookup_current$subspecies_first == substr(x_parts[2], 1, 1) |
|
||||
MO_lookup_current$subspecies_first == substr(x_parts[3], 1, 1)))
|
||||
# Issue #288: if the species (and subspecies) word(s) in the input exactly match
|
||||
# exactly one candidate, use only that candidate and bypass the 0.55 cutoff.
|
||||
# This prevents prevalent bacteria from outranking a rarer organism whose species
|
||||
# epithet is an unambiguous exact match, e.g. "S. apiospermum" → Scedosporium.
|
||||
sp_exact <- tolower(MO_lookup_current$species[filtr]) == x_parts[2]
|
||||
if (length(x_parts) == 3) {
|
||||
sp_exact <- sp_exact & tolower(MO_lookup_current$subspecies[filtr]) == x_parts[3]
|
||||
}
|
||||
if (sum(sp_exact) == 1) {
|
||||
filtr <- filtr[sp_exact]
|
||||
minimum_matching_score <- 0
|
||||
}
|
||||
} else {
|
||||
filtr <- which(MO_lookup_current$full_first == substr(x_parts[1], 1, 1) |
|
||||
MO_lookup_current$species_first == substr(x_parts[2], 1, 1) |
|
||||
@@ -813,7 +792,7 @@ print.mo <- function(x, print.shortnames = FALSE, ...) {
|
||||
names(x) <- x_names
|
||||
if (!all(x %in% c(AMR_env$MO_lookup$mo, NA))) {
|
||||
warning_(
|
||||
"Some MO codes are from another AMR package version. ",
|
||||
"Some MO codes are from a previous AMR package version. ",
|
||||
"Please update the MO codes with {.help [{.fun as.mo}](AMR::as.mo)}.",
|
||||
call = FALSE
|
||||
)
|
||||
@@ -847,7 +826,7 @@ as.data.frame.mo <- function(x, ...) {
|
||||
add_MO_lookup_to_AMR_env()
|
||||
if (!all(x %in% c(AMR_env$MO_lookup$mo, NA))) {
|
||||
warning_(
|
||||
"The data contains old MO codes (from another AMR package version). ",
|
||||
"The data contains old MO codes (from a previous AMR package version). ",
|
||||
"Please update your MO codes with {.help [{.fun as.mo}](AMR::as.mo)}."
|
||||
)
|
||||
}
|
||||
@@ -1023,19 +1002,17 @@ print.mo_uncertainties <- function(x, n = 10, ...) {
|
||||
message_(out2, as_note = FALSE)
|
||||
}
|
||||
|
||||
if (x[i, ]$candidates != "") {
|
||||
other_matches <- paste0(
|
||||
"Also matched: ",
|
||||
vector_and(
|
||||
paste0(
|
||||
candidates_formatted,
|
||||
font_blue(paste0(" (", scores_formatted, ")"), collapse = NULL)
|
||||
),
|
||||
quotes = FALSE, sort = FALSE
|
||||
)
|
||||
other_matches <- paste0(
|
||||
"Also matched: ",
|
||||
vector_and(
|
||||
paste0(
|
||||
candidates_formatted,
|
||||
font_blue(paste0(" (", scores_formatted, ")"), collapse = NULL)
|
||||
),
|
||||
quotes = FALSE, sort = FALSE
|
||||
)
|
||||
message_(other_matches, as_note = FALSE)
|
||||
}
|
||||
)
|
||||
message_(other_matches, as_note = FALSE)
|
||||
}
|
||||
|
||||
if (isTRUE(any_maxed_out)) {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#'
|
||||
#' Use these functions to return a specific property of a microorganism based on the latest accepted taxonomy. All input values will be evaluated internally with [as.mo()], which makes it possible to use microbial abbreviations, codes and names as input. See *Examples*.
|
||||
#' @param x Any [character] (vector) that can be coerced to a valid microorganism code with [as.mo()]. Can be left blank for auto-guessing the column containing microorganism codes if used in a data set, see *Examples*.
|
||||
#' @param property One of the column names of the [microorganisms] data set: `r vector_or(colnames(microorganisms), sort = FALSE, documentation = TRUE)`, or must be `"shortname"`.
|
||||
#' @param property One of the column names of the [microorganisms] data set: `r vector_or(colnames(microorganisms), sort = FALSE, quotes = TRUE)`, or must be `"shortname"`.
|
||||
#' @inheritParams as.mo
|
||||
#' @param ... Other arguments passed on to [as.mo()], such as 'minimum_matching_score', 'ignore_pattern', and 'remove_from_input'.
|
||||
#' @param ab Any (vector of) text that can be coerced to a valid antibiotic drug code with [as.ab()].
|
||||
@@ -42,23 +42,21 @@
|
||||
#' - `mo_ref("Enterobacter aerogenes")` will return `"Tindall et al., 2017"` (with a note about the renaming)
|
||||
#' - `mo_ref("Enterobacter aerogenes", keep_synonyms = TRUE)` will return `"Hormaeche et al., 1960"` (with a once-per-session warning that the name is outdated)
|
||||
#'
|
||||
#' [mo_ref()] returns the abbreviated authority of the nomenclatural act that created the queried name combination. When `keep_synonyms = FALSE` (default), this is the authority of the currently accepted name. When `keep_synonyms = TRUE`, this is the authority under which the queried (possibly outdated) name was published. Emendations (changes to the species description without a name change) are not reflected; only the combination or original description authority is returned.
|
||||
#'
|
||||
#' The short name ([mo_shortname()]) returns the first character of the genus and the full species, such as `"E. coli"`, for species and subspecies. Exceptions are abbreviations of staphylococci (such as *"CoNS"*, Coagulase-Negative Staphylococci) and beta-haemolytic streptococci (such as *"GBS"*, Group B Streptococci). Please bear in mind that e.g. *E. coli* could mean *Escherichia coli* (kingdom of Bacteria) as well as *Entamoeba coli* (kingdom of Protozoa). Returning to the full name will be done using [as.mo()] internally, giving priority to bacteria and human pathogens, i.e. `"E. coli"` will always be considered *Escherichia coli*. As a result, `mo_fullname(mo_shortname("Entamoeba coli"))` returns `"Escherichia coli"`.
|
||||
#' The short name ([mo_shortname()]) returns the first character of the genus and the full species, such as `"E. coli"`, for species and subspecies. Exceptions are abbreviations of staphylococci (such as *"CoNS"*, Coagulase-Negative Staphylococci) and beta-haemolytic streptococci (such as *"GBS"*, Group B Streptococci). Please bear in mind that e.g. *E. coli* could mean *Escherichia coli* (kingdom of Bacteria) as well as *Entamoeba coli* (kingdom of Protozoa). Returning to the full name will be done using [as.mo()] internally, giving priority to bacteria and human pathogens, i.e. `"E. coli"` will be considered *Escherichia coli*. As a result, `mo_fullname(mo_shortname("Entamoeba coli"))` returns `"Escherichia coli"`.
|
||||
#'
|
||||
#' Since the top-level of the taxonomy is sometimes referred to as 'kingdom' and sometimes as 'domain', the functions [mo_kingdom()] and [mo_domain()] return the exact same results.
|
||||
#'
|
||||
#' Determination of human pathogenicity ([mo_pathogenicity()]) is strongly based on Bartlett *et al.* (2022, \doi{10.1099/mic.0.001269}). This function returns a [factor] with the levels *Pathogenic*, *Potentially pathogenic*, *Non-pathogenic*, and *Unknown*.
|
||||
#'
|
||||
#' Determination of the Gram stain ([mo_gramstain()] is based on the taxonomic kingdom and phylum. Originally, Cavalier-Smith defined the so-called subkingdoms Negibacteria and Posibacteria (2002, [PMID 11837318](https://pubmed.ncbi.nlm.nih.gov/11837318/)), and only considered these phyla as Posibacteria: Actinobacteria, Chloroflexi, Firmicutes, and Tenericutes. These phyla were later renamed to Actinomycetota, Chloroflexota, Bacillota, and Mycoplasmatota (2021, [PMID 34694987](https://pubmed.ncbi.nlm.nih.gov/34694987/)). Bacteria in these phyla are considered Gram-positive in this `AMR` package, except for members of the class Negativicutes (within phylum Bacillota) which are Gram-negative. All other bacteria are considered Gram-negative. Species outside the kingdom of Bacteria will return a value `NA`. Functions [mo_is_gram_negative()] and [mo_is_gram_positive()] always return `TRUE` or `FALSE` (or `NA` when the input is `NA` or the MO code is `UNKNOWN`), thus always return `FALSE` for species outside the taxonomic kingdom of Bacteria.
|
||||
#' Determination of the Gram stain ([mo_gramstain()]) will be based on the taxonomic kingdom and phylum. Originally, Cavalier-Smith defined the so-called subkingdoms Negibacteria and Posibacteria (2002, [PMID 11837318](https://pubmed.ncbi.nlm.nih.gov/11837318/)), and only considered these phyla as Posibacteria: Actinobacteria, Chloroflexi, Firmicutes, and Tenericutes. These phyla were later renamed to Actinomycetota, Chloroflexota, Bacillota, and Mycoplasmatota (2021, [PMID 34694987](https://pubmed.ncbi.nlm.nih.gov/34694987/)). Bacteria in these phyla are considered Gram-positive in this `AMR` package, except for members of the class Negativicutes (within phylum Bacillota) which are Gram-negative. All other bacteria are considered Gram-negative. Species outside the kingdom of Bacteria will return a value `NA`. Functions [mo_is_gram_negative()] and [mo_is_gram_positive()] always return `TRUE` or `FALSE` (or `NA` when the input is `NA` or the MO code is `UNKNOWN`), thus always return `FALSE` for species outside the taxonomic kingdom of Bacteria.
|
||||
#'
|
||||
#' Determination of yeasts ([mo_is_yeast()]) is based on the taxonomic kingdom and class. *Budding yeasts* are yeasts that reproduce asexually through a process called budding, where a new cell develops from a small protrusion on the parent cell. Taxonomically, these are members of the phylum Ascomycota, class Saccharomycetes (also called Hemiascomycetes) or Pichiomycetes. *True yeasts* quite specifically refers to yeasts in the underlying order Saccharomycetales (such as *Saccharomyces cerevisiae*). Thus, for all microorganisms that are member of the taxonomic class Saccharomycetes or Pichiomycetes, the function will return `TRUE`. It returns `FALSE` otherwise (or `NA` when the input is `NA` or the MO code is `UNKNOWN`).
|
||||
#' Determination of yeasts ([mo_is_yeast()]) will be based on the taxonomic kingdom and class. *Budding yeasts* are yeasts that reproduce asexually through a process called budding, where a new cell develops from a small protrusion on the parent cell. Taxonomically, these are members of the phylum Ascomycota, class Saccharomycetes (also called Hemiascomycetes) or Pichiomycetes. *True yeasts* quite specifically refers to yeasts in the underlying order Saccharomycetales (such as *Saccharomyces cerevisiae*). Thus, for all microorganisms that are member of the taxonomic class Saccharomycetes or Pichiomycetes, the function will return `TRUE`. It returns `FALSE` otherwise (or `NA` when the input is `NA` or the MO code is `UNKNOWN`).
|
||||
#'
|
||||
#' Determination of intrinsic resistance ([mo_is_intrinsic_resistant()]) is based on the [intrinsic_resistant] data set, which is based on `r format_eucast_version_nr(names(EUCAST_VERSION_EXPECTED_PHENOTYPES[1]))`. The [mo_is_intrinsic_resistant()] function can be vectorised over both argument `x` (input for microorganisms) and `ab` (input for antimicrobials).
|
||||
#' Determination of intrinsic resistance ([mo_is_intrinsic_resistant()]) will be based on the [intrinsic_resistant] data set, which is based on `r format_eucast_version_nr(names(EUCAST_VERSION_EXPECTED_PHENOTYPES[1]))`. The [mo_is_intrinsic_resistant()] function can be vectorised over both argument `x` (input for microorganisms) and `ab` (input for antimicrobials).
|
||||
#'
|
||||
#' Determination of both bacterial oxygen tolerance ([mo_oxygen_tolerance()]) and morphology ([mo_morphology()]) are based on BacDive, see *Source*. The function [mo_is_anaerobic()] only returns `TRUE` if the oxygen tolerance is `"anaerobe"`, indicating an obligate anaerobic species or genus. It always returns `FALSE` for species outside the taxonomic kingdom of Bacteria.
|
||||
#' Determination of bacterial oxygen tolerance ([mo_oxygen_tolerance()]) will be based on BacDive, see *Source*. The function [mo_is_anaerobic()] only returns `TRUE` if the oxygen tolerance is `"anaerobe"`, indicting an obligate anaerobic species or genus. It always returns `FALSE` for species outside the taxonomic kingdom of Bacteria.
|
||||
#'
|
||||
#' The function [mo_url()] will return the direct URL to the online database entry, which also shows the scientific reference of the concerned species. [This MycoBank URL](`r TAXONOMY_VERSION$MycoBank$url`) is used for fungi wherever available , [this LPSN URL](`r TAXONOMY_VERSION$MycoBank$url`) for bacteria wherever available, and [this GBIF link](`r TAXONOMY_VERSION$GBIF$url`) otherwise.
|
||||
#' The function [mo_url()] will return the direct URL to the online database entry, which also shows the scientific reference of the concerned species. [This MycoBank URL](`r TAXONOMY_VERSION$MycoBank$url`) will be used for fungi wherever available , [this LPSN URL](`r TAXONOMY_VERSION$MycoBank$url`) for bacteria wherever available, and [this GBIF link](`r TAXONOMY_VERSION$GBIF$url`) otherwise.
|
||||
#'
|
||||
#' SNOMED codes ([mo_snomed()]) was last updated on `r documentation_date(TAXONOMY_VERSION$SNOMED$accessed_date)`. See *Source* and the [microorganisms] data set for more info.
|
||||
#'
|
||||
@@ -102,10 +100,8 @@
|
||||
#'
|
||||
#' # other properties ---------------------------------------------------------
|
||||
#'
|
||||
#' mo_morphology("Klebsiella pneumoniae")
|
||||
#' mo_gramstain("Klebsiella pneumoniae")
|
||||
#' mo_gramstain("Klebsiella pneumoniae", add_morphology = TRUE)
|
||||
#' mo_pathogenicity("Klebsiella pneumoniae")
|
||||
#' mo_gramstain("Klebsiella pneumoniae")
|
||||
#' mo_snomed("Klebsiella pneumoniae")
|
||||
#' mo_type("Klebsiella pneumoniae")
|
||||
#' mo_rank("Klebsiella pneumoniae")
|
||||
@@ -464,9 +460,8 @@ mo_pathogenicity <- function(x, language = get_AMR_locale(), keep_synonyms = get
|
||||
}
|
||||
|
||||
#' @rdname mo_property
|
||||
#' @param add_morphology a [logical] to indicate whether the morphology (from [mo_morphology()]) should be added to the Gram stain result, e.g. `"Gram-negative rods"` instead of `"Gram-negative"`. The default is `FALSE`.
|
||||
#' @export
|
||||
mo_gramstain <- function(x, language = get_AMR_locale(), keep_synonyms = getOption("AMR_keep_synonyms", FALSE), add_morphology = FALSE, ...) {
|
||||
mo_gramstain <- function(x, language = get_AMR_locale(), keep_synonyms = getOption("AMR_keep_synonyms", FALSE), ...) {
|
||||
if (missing(x)) {
|
||||
# this tries to find the data and an 'mo' column
|
||||
x <- find_mo_col(fn = "mo_gramstain")
|
||||
@@ -474,7 +469,6 @@ mo_gramstain <- function(x, language = get_AMR_locale(), keep_synonyms = getOpti
|
||||
meet_criteria(x, allow_NA = TRUE)
|
||||
language <- validate_language(language)
|
||||
meet_criteria(keep_synonyms, allow_class = "logical", has_length = 1)
|
||||
meet_criteria(add_morphology, allow_class = "logical", has_length = 1)
|
||||
|
||||
x.mo <- as.mo(x, language = language, keep_synonyms = keep_synonyms, ...)
|
||||
metadata <- get_mo_uncertainties()
|
||||
@@ -500,12 +494,6 @@ mo_gramstain <- function(x, language = get_AMR_locale(), keep_synonyms = getOpti
|
||||
# and of course our own ID for Gram-positives
|
||||
| x.mo %in% c("B_GRAMP", "B_ANAER-POS")] <- "Gram-positive"
|
||||
|
||||
if (isTRUE(add_morphology)) {
|
||||
morphs <- mo_morphology(x.mo, language = NULL)
|
||||
morphs[is.na(x)] <- ""
|
||||
x[!is.na(x)] <- paste(x[!is.na(x)], tolower(morphs[!is.na(x)]))
|
||||
}
|
||||
|
||||
load_mo_uncertainties(metadata)
|
||||
translate_into_language(x, language = language, only_unknown = FALSE)
|
||||
}
|
||||
@@ -646,20 +634,6 @@ mo_is_anaerobic <- function(x, language = get_AMR_locale(), keep_synonyms = getO
|
||||
out
|
||||
}
|
||||
|
||||
#' @rdname mo_property
|
||||
#' @export
|
||||
mo_morphology <- function(x, language = get_AMR_locale(), keep_synonyms = getOption("AMR_keep_synonyms", FALSE), ...) {
|
||||
if (missing(x)) {
|
||||
# this tries to find the data and an 'mo' column
|
||||
x <- find_mo_col(fn = "mo_morphology")
|
||||
}
|
||||
meet_criteria(x, allow_NA = TRUE)
|
||||
language <- validate_language(language)
|
||||
meet_criteria(keep_synonyms, allow_class = "logical", has_length = 1)
|
||||
|
||||
mo_validate(x = x, property = "morphology", language = language, keep_synonyms = keep_synonyms, ...)
|
||||
}
|
||||
|
||||
#' @rdname mo_property
|
||||
#' @export
|
||||
mo_snomed <- function(x, language = get_AMR_locale(), keep_synonyms = getOption("AMR_keep_synonyms", FALSE), ...) {
|
||||
|
||||
8
R/pca.R
8
R/pca.R
@@ -66,12 +66,12 @@
|
||||
#'
|
||||
#' # new ggplot2 plotting method using this package:
|
||||
#' if (require("dplyr") && require("ggplot2")) {
|
||||
#' ggplot_pca(pca_result)
|
||||
#' ggplot_pca(pca_result)
|
||||
#' }
|
||||
#' if (require("dplyr") && require("ggplot2")) {
|
||||
#' ggplot_pca(pca_result) +
|
||||
#' scale_colour_viridis_d() +
|
||||
#' labs(title = "Title here")
|
||||
#' ggplot_pca(pca_result) +
|
||||
#' scale_colour_viridis_d() +
|
||||
#' labs(title = "Title here")
|
||||
#' }
|
||||
#' }
|
||||
pca <- function(x,
|
||||
|
||||
@@ -200,7 +200,7 @@
|
||||
#' theme_minimal() +
|
||||
#' geom_boxplot(fill = NA, colour = "grey30") +
|
||||
#' geom_jitter(width = 0.25)
|
||||
#' labs(title = "scale_y_mic()/scale_colour_sir() automatically applied")
|
||||
#' labs(title = "scale_y_mic()/scale_colour_sir() automatically applied")
|
||||
#'
|
||||
#' mic_sir_plot
|
||||
#' }
|
||||
|
||||
0
R/proportion.R
Executable file → Normal file
0
R/proportion.R
Executable file → Normal file
378
R/sir.R
378
R/sir.R
@@ -65,11 +65,11 @@ VALID_SIR_LEVELS <- c("S", "SDD", "I", "R", "NI", "WT", "NWT", "NS")
|
||||
#' @param substitute_missing_r_breakpoint A [logical] to indicate that a missing clinical breakpoints for R (resistant) must be substituted with R - the default is `FALSE`. Some (especially CLSI) breakpoints only have a breakpoint for S, meaning that the outcome can only be `"S"` or `NA`. Setting this to `TRUE` will convert the `NA`s in these cases to `"R"`. Can also be set with the package option [`AMR_substitute_missing_r_breakpoint`][AMR-options].
|
||||
#' @param include_screening A [logical] to indicate that clinical breakpoints for screening are allowed - the default is `FALSE`. Can also be set with the package option [`AMR_include_screening`][AMR-options].
|
||||
#' @param include_PKPD A [logical] to indicate that PK/PD clinical breakpoints must be applied as a last resort - the default is `TRUE`. Can also be set with the package option [`AMR_include_PKPD`][AMR-options].
|
||||
#' @param breakpoint_type The type of breakpoints to use, either `r vector_or(clinical_breakpoints$type, documentation = TRUE)`. ECOFF stands for Epidemiological Cut-Off values. The default is `"human"`, which can also be set with the package option [`AMR_breakpoint_type`][AMR-options]. If `host` is set to values of veterinary species, this will automatically be set to `"animal"`.
|
||||
#' @param breakpoint_type The type of breakpoints to use, either `r vector_or(clinical_breakpoints$type)`. ECOFF stands for Epidemiological Cut-Off values. The default is `"human"`, which can also be set with the package option [`AMR_breakpoint_type`][AMR-options]. If `host` is set to values of veterinary species, this will automatically be set to `"animal"`.
|
||||
#' @param host A vector (or column name) with [character]s to indicate the host. Only useful for veterinary breakpoints, as it requires `breakpoint_type = "animal"`. The values can be any text resembling the animal species, even in any of the `r length(LANGUAGES_SUPPORTED)` supported languages of this package. For foreign languages, be sure to set the language with [set_AMR_locale()] (though it will be automatically guessed based on the system language).
|
||||
#' @param language Language to convert values set in `host` when using animal breakpoints. Use one of these supported language names or [ISO 639-1 codes](https://en.wikipedia.org/wiki/ISO_639-1): `r vector_or(paste0(sapply(LANGUAGES_SUPPORTED_NAMES, function(x) x[[1]]), " (" , LANGUAGES_SUPPORTED, ")"), quotes = FALSE, sort = FALSE)`.
|
||||
#' @param verbose A [logical] to indicate that all notes should be printed during interpretation of MIC values or disk diffusion values.
|
||||
#' @param reference_data A [data.frame] to be used for interpretation, which defaults to the [clinical_breakpoints] data set. Changing this argument allows for using own interpretation guidelines. This argument must have the same column names as the [clinical_breakpoints] data set. Column types are coerced automatically where possible: the `mo` column is passed through [as.mo()], the `ab` column through [as.ab()], and plain character, numeric, or logical columns are cast to the expected type. When `reference_data` is manually set, the `guideline` argument is optional: if omitted (or if its value does not match any row in the custom data), all rows in `reference_data` are considered. If `guideline` is set to a value that exists in the `guideline` column of the custom data, only matching rows are used — useful when a single custom table contains multiple guidelines. For the R classification, the EUCAST convention is used by default: MIC values `> breakpoint_R` and disk diffusion values `< breakpoint_R` are classified as R, with values between `breakpoint_S` and `breakpoint_R` classified as I (or SDD). Only when using the standard [clinical_breakpoints] with a CLSI guideline are the closed-interval rules (`>= breakpoint_R` for MIC, `<= breakpoint_R` for disk) applied; custom `reference_data` always uses the open-interval (EUCAST) convention regardless of the guideline name.
|
||||
#' @param reference_data A [data.frame] to be used for interpretation, which defaults to the [clinical_breakpoints] 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 [clinical_breakpoints] data set (same column names and column types). Please note that the `guideline` argument will be ignored when `reference_data` is manually set.
|
||||
#' @param threshold Maximum fraction of invalid antimicrobial interpretations of `x`, see *Examples*.
|
||||
#' @param conserve_capped_values Deprecated, use `capped_mic_handling` instead.
|
||||
#' @param ... For using on a [data.frame]: selection of columns to apply `as.sir()` to. Supports [tidyselect language][tidyselect::starts_with()] such as `where(is.mic)`, `starts_with(...)`, or `column1:column4`, and can thus also be [antimicrobial selectors][amr_selector()], e.g. `as.sir(df, penicillins())`.
|
||||
@@ -95,7 +95,7 @@ VALID_SIR_LEVELS <- c("S", "SDD", "I", "R", "NI", "WT", "NWT", "NS")
|
||||
#' # for veterinary breakpoints, also set `host`:
|
||||
#' your_data %>% mutate_if(is.mic, as.sir, host = "column_with_animal_species", guideline = "CLSI")
|
||||
#'
|
||||
#' # fast processing with parallel computing (requires future.apply):
|
||||
#' # fast processing with parallel computing:
|
||||
#' as.sir(your_data, ..., parallel = TRUE)
|
||||
#' ```
|
||||
#' * Operators like "<=" will be considered according to the `capped_mic_handling` setting. At default, an MIC value of e.g. ">2" will return "NI" (non-interpretable) if the breakpoint is 4-8; the *true* MIC could be at either side of the breakpoint. This is to prevent that capped values from raw laboratory data would not be treated conservatively.
|
||||
@@ -112,7 +112,7 @@ VALID_SIR_LEVELS <- c("S", "SDD", "I", "R", "NI", "WT", "NWT", "NS")
|
||||
#' # for veterinary breakpoints, also set `host`:
|
||||
#' your_data %>% mutate_if(is.disk, as.sir, host = "column_with_animal_species", guideline = "CLSI")
|
||||
#'
|
||||
#' # fast processing with parallel computing (requires future.apply):
|
||||
#' # fast processing with parallel computing:
|
||||
#' as.sir(your_data, ..., parallel = TRUE)
|
||||
#' ```
|
||||
#'
|
||||
@@ -220,6 +220,9 @@ VALID_SIR_LEVELS <- c("S", "SDD", "I", "R", "NI", "WT", "NWT", "NS")
|
||||
#' sir_interpretation_history()
|
||||
#'
|
||||
#' \donttest{
|
||||
#' # using parallel computing, which is available in base R:
|
||||
#' as.sir(df_wide, parallel = TRUE, info = TRUE)
|
||||
#'
|
||||
#'
|
||||
#' ## Using dplyr -------------------------------------------------
|
||||
#' if (require("dplyr")) {
|
||||
@@ -713,7 +716,8 @@ as.sir.disk <- function(x,
|
||||
}
|
||||
|
||||
#' @rdname as.sir
|
||||
#' @param parallel A [logical] to indicate if parallel computing must be used, defaults to `FALSE`. Requires the [`future.apply`][future.apply::future_lapply()] package. **A non-sequential [future::plan()] must already be active before setting `parallel = TRUE`** — for example, `future::plan(future::multisession)`. An error is thrown if `parallel = TRUE` is used without a plan set by the user. Parallelism distributes columns (and optionally row batches) across workers; it is most beneficial when there are many antibiotic columns and a large number of rows.
|
||||
#' @param parallel A [logical] to indicate if parallel computing must be used, defaults to `FALSE`. This requires no additional packages, as the used `parallel` package is part of base \R. On Windows and on \R < 4.0.0 [parallel::parLapply()] will be used, in all other cases the more efficient [parallel::mclapply()] will be used.
|
||||
#' @param max_cores Maximum number of cores to use if `parallel = TRUE`. Use a negative value to subtract that number from the available number of cores, e.g. a value of `-2` on an 8-core machine means that at most 6 cores will be used. Defaults to `-1`. There will never be used more cores than variables to analyse. The available number of cores are detected using [parallelly::availableCores()] if that package is installed, and base \R's [parallel::detectCores()] otherwise.
|
||||
#' @export
|
||||
as.sir.data.frame <- function(x,
|
||||
...,
|
||||
@@ -733,6 +737,7 @@ as.sir.data.frame <- function(x,
|
||||
verbose = FALSE,
|
||||
info = interactive(),
|
||||
parallel = FALSE,
|
||||
max_cores = -1,
|
||||
conserve_capped_values = NULL) {
|
||||
meet_criteria(x, allow_class = "data.frame") # will also check for dimensions > 0
|
||||
meet_criteria(col_mo, allow_class = "character", is_in = colnames(x), allow_NULL = TRUE)
|
||||
@@ -751,6 +756,7 @@ as.sir.data.frame <- function(x,
|
||||
meet_criteria(verbose, allow_class = "logical", has_length = 1)
|
||||
meet_criteria(info, allow_class = "logical", has_length = 1)
|
||||
meet_criteria(parallel, allow_class = "logical", has_length = 1)
|
||||
meet_criteria(max_cores, allow_class = c("numeric", "integer"), has_length = 1)
|
||||
x.bak <- x
|
||||
|
||||
if (isTRUE(info) && message_not_thrown_before("as.sir", "sir_interpretation_history")) {
|
||||
@@ -846,6 +852,7 @@ as.sir.data.frame <- function(x,
|
||||
i <- 0
|
||||
ab_cols <- colnames(x)[vapply(FUN.VALUE = logical(1), x, function(y) {
|
||||
i <<- i + 1
|
||||
check <- is.mic(y) | is.disk(y)
|
||||
ab <- colnames(x)[i]
|
||||
if (!is.null(col_mo) && ab == col_mo) {
|
||||
return(FALSE)
|
||||
@@ -854,30 +861,13 @@ as.sir.data.frame <- function(x,
|
||||
return(FALSE)
|
||||
}
|
||||
if (length(sel) == 0 || (length(sel) > 0 && ab %in% sel)) {
|
||||
# columns already carrying an AMR class are always included
|
||||
y_bak <- x.bak[, ab, drop = TRUE]
|
||||
if (is.mic(y_bak) || is.disk(y_bak) || is.sir(y_bak)) {
|
||||
return(TRUE)
|
||||
}
|
||||
ab_coerced <- suppressWarnings(as.ab(ab, info = FALSE))
|
||||
if (is.na(ab_coerced) || (length(sel) > 0 & !ab %in% sel)) {
|
||||
# not even a valid AB code
|
||||
return(FALSE)
|
||||
} else {
|
||||
return(TRUE)
|
||||
}
|
||||
# Name matches an antibiotic; also verify column content resembles AMR
|
||||
# data. This prevents false positives on metadata columns whose names
|
||||
# happen to match a drug code (e.g. 'patient' -> OXY, 'ward' -> PRU).
|
||||
# Note: all_valid_disks() is intentionally avoided here because it strips
|
||||
# non-numeric characters (as.disk("Pt_1") == 1), accepting patient IDs.
|
||||
y_char <- tryCatch(as.character(y), error = function(e) character(0))
|
||||
y_valid <- y_char[!is.na(y_char) & nzchar(trimws(y_char))]
|
||||
if (length(y_valid) == 0L) {
|
||||
return(FALSE)
|
||||
}
|
||||
y_numeric <- suppressWarnings(as.numeric(y_valid))
|
||||
all_valid_mics(y) ||
|
||||
all(!is.na(y_numeric)) ||
|
||||
any(y_valid %in% c("S", "SDD", "I", "R", "NI"))
|
||||
} else {
|
||||
return(FALSE)
|
||||
}
|
||||
@@ -885,7 +875,7 @@ as.sir.data.frame <- function(x,
|
||||
|
||||
stop_if(
|
||||
length(ab_cols) == 0,
|
||||
"no columns with MIC values, disk zones or antibiotic column names found in this data set. Use {.help [{.fun as.mic}](AMR::as.mic)} or {.help [{.fun as.disk}](AMR::as.disk)} to transform antimicrobial columns."
|
||||
"no columns with MIC values, disk zones or antibiotic column names found in this data set. Use as.mic() or as.disk() to transform antimicrobial columns."
|
||||
)
|
||||
# set type per column
|
||||
types <- character(length(ab_cols))
|
||||
@@ -893,7 +883,7 @@ as.sir.data.frame <- function(x,
|
||||
types[vapply(FUN.VALUE = logical(1), x.bak[, ab_cols, drop = FALSE], is.mic)] <- "mic"
|
||||
types[types == "" & vapply(FUN.VALUE = logical(1), x[, ab_cols, drop = FALSE], all_valid_disks)] <- "disk"
|
||||
types[types == "" & vapply(FUN.VALUE = logical(1), x[, ab_cols, drop = FALSE], all_valid_mics)] <- "mic"
|
||||
types[types == ""] <- "sir"
|
||||
types[types == "" & !vapply(FUN.VALUE = logical(1), x.bak[, ab_cols, drop = FALSE], is.sir)] <- "sir"
|
||||
if (any(types %in% c("mic", "disk"), na.rm = TRUE)) {
|
||||
# now we need an mo column
|
||||
stop_if(is.null(col_mo), "{.arg col_mo} must be set")
|
||||
@@ -905,161 +895,114 @@ as.sir.data.frame <- function(x,
|
||||
}
|
||||
|
||||
# set up parallel computing
|
||||
if (requireNamespace("future.apply", quietly = TRUE) && !inherits(future::plan(), "sequential")) {
|
||||
if (isFALSE(parallel)) {
|
||||
message_("Assuming {.code parallel = TRUE} since parallel computing has been set up using the {.pkg future} package before. Set {.help [{.fun plan}](future::plan)} to sequential to prevent this.")
|
||||
n_cores <- get_n_cores(max_cores = max_cores)
|
||||
n_cores <- min(n_cores, length(ab_cols)) # never more cores than variables required
|
||||
if (isTRUE(parallel) && (.Platform$OS.type == "windows" || getRversion() < "4.0.0")) {
|
||||
cl <- tryCatch(parallel::makeCluster(n_cores, type = "PSOCK"),
|
||||
error = function(e) {
|
||||
if (isTRUE(info)) {
|
||||
message_("Could not create parallel cluster, using single-core computation. Error message: ", conditionMessage(e))
|
||||
}
|
||||
return(NULL)
|
||||
}
|
||||
)
|
||||
if (is.null(cl)) {
|
||||
n_cores <- 1
|
||||
}
|
||||
parallel <- TRUE
|
||||
}
|
||||
if (isTRUE(parallel)) {
|
||||
stop_ifnot(
|
||||
requireNamespace("future.apply", quietly = TRUE),
|
||||
"Setting {.code parallel = TRUE} requires the {.pkg future.apply} package.\n",
|
||||
"Install it with {.code install.packages(\"future.apply\")}."
|
||||
)
|
||||
stop_if(inherits(future::plan(), "sequential"),
|
||||
"Setting {.code parallel = TRUE} requires a non-sequential {.help [{.fun future::plan}](future::plan)} to be active.\n",
|
||||
"For your system, you could first run: {.code library(future); ",
|
||||
ifelse(.Platform$OS.type == "windows" || in_rstudio(),
|
||||
"plan(multisession)",
|
||||
"plan(multicore)"
|
||||
),
|
||||
"}",
|
||||
call = FALSE
|
||||
)
|
||||
|
||||
n_workers <- future::nbrOfWorkers()
|
||||
n_cores <- min(n_workers, length(ab_cols))
|
||||
} else {
|
||||
n_workers <- 1L
|
||||
n_cores <- 1L
|
||||
}
|
||||
|
||||
# In parallel mode suppress per-column messages: workers print simultaneously and
|
||||
# their output would be interleaved on the console.
|
||||
is_parallel_run <- isTRUE(parallel) && n_cores > 1 && length(ab_cols) > 1
|
||||
effective_info <- if (is_parallel_run) FALSE else info
|
||||
|
||||
# Row-batch mode: when n_cols < n_workers we would leave workers idle under plain
|
||||
# column-parallel dispatch. Instead we split rows into pieces so every worker
|
||||
# gets work. pieces_per_col = ceil(n_workers / n_cols) gives ~n_workers jobs
|
||||
# total; each job processes one column on one row slice, which also reduces
|
||||
# per-worker memory pressure (smaller breakpoints search space).
|
||||
if (is_parallel_run && length(ab_cols) < n_workers) {
|
||||
pieces_per_col <- ceiling(n_workers / length(ab_cols))
|
||||
} else {
|
||||
pieces_per_col <- 1L
|
||||
if (isTRUE(info)) {
|
||||
message_(as_note = FALSE) # empty line
|
||||
message_("Processing columns:", as_note = FALSE)
|
||||
}
|
||||
|
||||
run_as_sir_column <- function(i, rows = NULL) {
|
||||
# Always resolve AMR_env from the package namespace so workers get the live
|
||||
# environment rather than a stale serialised copy from the closure.
|
||||
.amr_env <- get("AMR_env", envir = asNamespace("AMR"), inherits = FALSE)
|
||||
# In parallel mode each worker has its own copy of the history; record the
|
||||
# current length so we capture only the rows added by this as.sir() call.
|
||||
if (is_parallel_run) pre_log_n <- NROW(.amr_env$sir_interpretation_history)
|
||||
|
||||
run_as_sir_column <- function(i) {
|
||||
ab_col <- ab_cols[i]
|
||||
out <- list(result = NULL, log = NULL)
|
||||
|
||||
# row subsetting: NULL means all rows (column-mode), otherwise row-batch mode
|
||||
row_idx <- if (is.null(rows)) seq_len(nrow(x)) else rows
|
||||
|
||||
if (types[i] == "mic") {
|
||||
result <- as.sir(
|
||||
as.mic(as.character(x[row_idx, ab_col, drop = TRUE])),
|
||||
mo = x_mo[row_idx],
|
||||
mo.bak = x[row_idx, col_mo, drop = TRUE],
|
||||
ab = ab_col,
|
||||
guideline = guideline,
|
||||
uti = if (length(uti) > 1L) uti[row_idx] else uti,
|
||||
capped_mic_handling = capped_mic_handling,
|
||||
as_wt_nwt = as_wt_nwt,
|
||||
add_intrinsic_resistance = add_intrinsic_resistance,
|
||||
reference_data = reference_data,
|
||||
substitute_missing_r_breakpoint = substitute_missing_r_breakpoint,
|
||||
include_screening = include_screening,
|
||||
include_PKPD = include_PKPD,
|
||||
breakpoint_type = breakpoint_type,
|
||||
host = if (length(host) > 1L) host[row_idx] else host,
|
||||
verbose = verbose,
|
||||
info = effective_info,
|
||||
conserve_capped_values = conserve_capped_values,
|
||||
is_data.frame = TRUE
|
||||
)
|
||||
result <- x %pm>%
|
||||
pm_pull(ab_col) %pm>%
|
||||
as.character() %pm>%
|
||||
as.mic() %pm>%
|
||||
as.sir(
|
||||
mo = x_mo,
|
||||
mo.bak = x[, col_mo, drop = TRUE],
|
||||
ab = ab_col,
|
||||
guideline = guideline,
|
||||
uti = uti,
|
||||
capped_mic_handling = capped_mic_handling,
|
||||
as_wt_nwt = as_wt_nwt,
|
||||
add_intrinsic_resistance = add_intrinsic_resistance,
|
||||
reference_data = reference_data,
|
||||
substitute_missing_r_breakpoint = substitute_missing_r_breakpoint,
|
||||
include_screening = include_screening,
|
||||
include_PKPD = include_PKPD,
|
||||
breakpoint_type = breakpoint_type,
|
||||
host = host,
|
||||
verbose = verbose,
|
||||
info = info,
|
||||
conserve_capped_values = conserve_capped_values,
|
||||
is_data.frame = TRUE
|
||||
)
|
||||
out$result <- result
|
||||
if (is_parallel_run) {
|
||||
full_log <- .amr_env$sir_interpretation_history
|
||||
out$log <- if (pre_log_n < NROW(full_log)) {
|
||||
full_log[seq.int(pre_log_n + 1L, NROW(full_log)), , drop = FALSE]
|
||||
} else {
|
||||
full_log[0L, , drop = FALSE]
|
||||
}
|
||||
} else {
|
||||
out$log <- .amr_env$sir_interpretation_history
|
||||
.amr_env$sir_interpretation_history <- .amr_env$sir_interpretation_history[0L, , drop = FALSE]
|
||||
}
|
||||
out$log <- AMR_env$sir_interpretation_history
|
||||
AMR_env$sir_interpretation_history <- AMR_env$sir_interpretation_history[0, , drop = FALSE] # reset log
|
||||
return(out)
|
||||
} else if (types[i] == "disk") {
|
||||
result <- as.sir(
|
||||
as.disk(as.character(x[row_idx, ab_col, drop = TRUE])),
|
||||
mo = x_mo[row_idx],
|
||||
mo.bak = x[row_idx, col_mo, drop = TRUE],
|
||||
ab = ab_col,
|
||||
guideline = guideline,
|
||||
uti = if (length(uti) > 1L) uti[row_idx] else uti,
|
||||
as_wt_nwt = as_wt_nwt,
|
||||
add_intrinsic_resistance = add_intrinsic_resistance,
|
||||
reference_data = reference_data,
|
||||
substitute_missing_r_breakpoint = substitute_missing_r_breakpoint,
|
||||
include_screening = include_screening,
|
||||
include_PKPD = include_PKPD,
|
||||
breakpoint_type = breakpoint_type,
|
||||
host = if (length(host) > 1L) host[row_idx] else host,
|
||||
verbose = verbose,
|
||||
info = effective_info,
|
||||
is_data.frame = TRUE
|
||||
)
|
||||
result <- x %pm>%
|
||||
pm_pull(ab_col) %pm>%
|
||||
as.character() %pm>%
|
||||
as.disk() %pm>%
|
||||
as.sir(
|
||||
mo = x_mo,
|
||||
mo.bak = x[, col_mo, drop = TRUE],
|
||||
ab = ab_col,
|
||||
guideline = guideline,
|
||||
uti = uti,
|
||||
as_wt_nwt = as_wt_nwt,
|
||||
add_intrinsic_resistance = add_intrinsic_resistance,
|
||||
reference_data = reference_data,
|
||||
substitute_missing_r_breakpoint = substitute_missing_r_breakpoint,
|
||||
include_screening = include_screening,
|
||||
include_PKPD = include_PKPD,
|
||||
breakpoint_type = breakpoint_type,
|
||||
host = host,
|
||||
verbose = verbose,
|
||||
info = info,
|
||||
is_data.frame = TRUE
|
||||
)
|
||||
out$result <- result
|
||||
if (is_parallel_run) {
|
||||
full_log <- .amr_env$sir_interpretation_history
|
||||
out$log <- if (pre_log_n < NROW(full_log)) {
|
||||
full_log[seq.int(pre_log_n + 1L, NROW(full_log)), , drop = FALSE]
|
||||
} else {
|
||||
full_log[0L, , drop = FALSE]
|
||||
}
|
||||
} else {
|
||||
out$log <- .amr_env$sir_interpretation_history
|
||||
.amr_env$sir_interpretation_history <- .amr_env$sir_interpretation_history[0L, , drop = FALSE]
|
||||
}
|
||||
out$log <- AMR_env$sir_interpretation_history
|
||||
AMR_env$sir_interpretation_history <- AMR_env$sir_interpretation_history[0, , drop = FALSE]
|
||||
return(out)
|
||||
} else if (types[i] == "sir") {
|
||||
ab <- ab_col
|
||||
ab_coerced <- suppressWarnings(as.ab(ab, info = FALSE))
|
||||
show_message <- FALSE
|
||||
if (!all(x[row_idx, ab, drop = TRUE] %in% c(VALID_SIR_LEVELS, NA), na.rm = TRUE)) {
|
||||
if (!all(x[, ab, drop = TRUE] %in% c("S", "SDD", "I", "R", "NI", NA), na.rm = TRUE)) {
|
||||
show_message <- TRUE
|
||||
if (isTRUE(effective_info)) {
|
||||
message_("\u00a0\u00a0", .amr_env$bullet_icon, " Cleaning values in column ", paste0("{.field ", font_bold(ab), "}"), " (",
|
||||
if (isTRUE(info)) {
|
||||
message_("\u00a0\u00a0", AMR_env$bullet_icon, " Cleaning values in column ", paste0("{.field ", font_bold(ab), "}"), " (",
|
||||
ifelse(ab_coerced != toupper(ab), paste0(ab_coerced, ", "), ""),
|
||||
ab_name(ab_coerced, tolower = TRUE, info = effective_info), ")... ",
|
||||
ab_name(ab_coerced, tolower = TRUE, info = info), ")... ",
|
||||
appendLF = FALSE,
|
||||
as_note = FALSE
|
||||
)
|
||||
}
|
||||
} else if (!is.sir(x.bak[, ab, drop = TRUE])) {
|
||||
show_message <- TRUE
|
||||
if (isTRUE(effective_info)) {
|
||||
message_("\u00a0\u00a0", .amr_env$bullet_icon, " Assigning class {.cls sir} to already clean column ", paste0("{.field ", font_bold(ab), "}"), " (",
|
||||
if (isTRUE(info)) {
|
||||
message_("\u00a0\u00a0", AMR_env$bullet_icon, " Assigning class {.cls sir} to already clean column ", paste0("{.field ", font_bold(ab), "}"), " (",
|
||||
ifelse(ab_coerced != toupper(ab), paste0(ab_coerced, ", "), ""),
|
||||
ab_name(ab_coerced, tolower = TRUE, language = NULL, info = effective_info), ")... ",
|
||||
ab_name(ab_coerced, tolower = TRUE, language = NULL, info = info), ")... ",
|
||||
appendLF = FALSE,
|
||||
as_note = FALSE
|
||||
)
|
||||
}
|
||||
}
|
||||
result <- as.sir(as.character(x[row_idx, ab, drop = TRUE]))
|
||||
if (show_message == TRUE && isTRUE(effective_info)) {
|
||||
result <- as.sir.default(x = as.character(x[, ab, drop = TRUE]))
|
||||
if (show_message == TRUE && isTRUE(info)) {
|
||||
message_(font_green_bg("\u00a0OK\u00a0"), as_note = FALSE)
|
||||
}
|
||||
out$result <- result
|
||||
@@ -1070,60 +1013,38 @@ as.sir.data.frame <- function(x,
|
||||
return(out)
|
||||
}
|
||||
|
||||
if (is_parallel_run) {
|
||||
if (isTRUE(parallel) && n_cores > 1 && length(ab_cols) > 1) {
|
||||
if (isTRUE(info)) {
|
||||
message_(as_note = FALSE)
|
||||
if (pieces_per_col > 1L) {
|
||||
message_("Running in parallel mode using ", n_cores, " workers, on columns ", vector_and(paste0("{.field ", font_bold(ab_cols, collapse = NULL), "}"), quotes = FALSE, sort = FALSE), " (", pieces_per_col, " row slices per column)...", as_note = FALSE, appendLF = FALSE)
|
||||
} else {
|
||||
message_("Running in parallel mode using ", n_cores, " workers, on columns ", vector_and(paste0("{.field ", font_bold(ab_cols, collapse = NULL), "}"), quotes = FALSE, sort = FALSE), "...", as_note = FALSE, appendLF = FALSE)
|
||||
}
|
||||
message_("Running in parallel mode using ", n_cores, " out of ", get_n_cores(Inf), " cores, on columns ", vector_and(font_bold(ab_cols, collapse = NULL), quotes = "'", sort = FALSE), "...", as_note = FALSE, appendLF = FALSE)
|
||||
}
|
||||
if (pieces_per_col > 1L) {
|
||||
# Row-batch mode: build (col, row_slice) job pairs so all workers stay active
|
||||
row_cuts <- unique(round(seq(0, nrow(x), length.out = pieces_per_col + 1L)))
|
||||
row_ranges <- lapply(seq_len(length(row_cuts) - 1L), function(p) {
|
||||
seq.int(row_cuts[p] + 1L, row_cuts[p + 1L])
|
||||
})
|
||||
jobs <- do.call(c, lapply(seq_along(ab_cols), function(ci) {
|
||||
lapply(seq_along(row_ranges), function(p) list(col = ci, rows = row_ranges[[p]]))
|
||||
}))
|
||||
flat <- future.apply::future_lapply(jobs, function(job) {
|
||||
run_as_sir_column(job$col, job$rows)
|
||||
}, future.seed = TRUE)
|
||||
# Reassemble: for each column concatenate row pieces in order
|
||||
result_list <- lapply(seq_along(ab_cols), function(ci) {
|
||||
pieces <- flat[vapply(jobs, function(j) j$col == ci, logical(1L))]
|
||||
list(
|
||||
result = as.sir(do.call(c, lapply(pieces, function(p) as.character(p$result)))),
|
||||
log = {
|
||||
logs <- Filter(Negate(is.null), lapply(pieces, function(p) p$log))
|
||||
if (length(logs) > 0L) do.call(rbind_AMR, logs) else NULL
|
||||
}
|
||||
)
|
||||
})
|
||||
if (.Platform$OS.type == "windows" || getRversion() < "4.0.0") {
|
||||
# `cl` has been created in the part above before the `run_as_sir_column` function
|
||||
on.exit(parallel::stopCluster(cl), add = TRUE)
|
||||
parallel::clusterExport(cl, varlist = c(
|
||||
"x", "x.bak", "x_mo", "ab_cols", "types",
|
||||
"capped_mic_handling", "as_wt_nwt", "add_intrinsic_resistance",
|
||||
"reference_data", "substitute_missing_r_breakpoint", "include_screening", "include_PKPD",
|
||||
"breakpoint_type", "guideline", "host", "uti", "info", "verbose",
|
||||
"col_mo", "AMR_env", "conserve_capped_values",
|
||||
"run_as_sir_column"
|
||||
), envir = environment())
|
||||
result_list <- parallel::parLapply(cl, seq_along(ab_cols), run_as_sir_column)
|
||||
} else {
|
||||
# Column-parallel mode: one job per antibiotic column
|
||||
result_list <- future.apply::future_lapply(seq_along(ab_cols), run_as_sir_column, future.seed = TRUE)
|
||||
# R>=4.0 on unix
|
||||
result_list <- parallel::mclapply(seq_along(ab_cols), run_as_sir_column, mc.cores = n_cores)
|
||||
}
|
||||
if (isTRUE(info)) {
|
||||
message_(font_green_bg("\u00a0DONE\u00a0"), as_note = FALSE)
|
||||
message_(font_green_bg("\u00aDONE\u00a"), as_note = FALSE)
|
||||
message_(as_note = FALSE)
|
||||
message_("Run {.help [{.fun sir_interpretation_history}](AMR::sir_interpretation_history)} to retrieve a logbook with all details of the breakpoint interpretations.")
|
||||
}
|
||||
} else {
|
||||
# sequential mode (non-parallel)
|
||||
if (isTRUE(info) && n_cores > 1 && NROW(x) * NCOL(x) > 10000) {
|
||||
suggest <- ifelse(.Platform$OS.type == "windows" || in_rstudio(),
|
||||
"plan(multisession)",
|
||||
"plan(multicore)"
|
||||
)
|
||||
# give a note that parallel mode might be better
|
||||
message_(as_note = FALSE)
|
||||
if (requireNamespace("future.apply", quietly = TRUE)) {
|
||||
message_("Running in sequential mode. To speed up processing, set a parallel {.help [{.fun future::plan}](future::plan)} such as {.code ", suggest, "}.")
|
||||
} else {
|
||||
message_("Running in sequential mode. To speed up processing, install the {.pkg future.apply} package and then set {.code parallel = TRUE}.\n")
|
||||
}
|
||||
message_("Running in sequential mode. Consider setting {.arg parallel} to {.code TRUE} to speed up processing on multiple cores.\n")
|
||||
}
|
||||
# this will contain a progress bar already
|
||||
result_list <- lapply(seq_along(ab_cols), run_as_sir_column)
|
||||
@@ -1244,7 +1165,7 @@ as_sir_method <- function(method_short,
|
||||
meet_criteria(substitute_missing_r_breakpoint, allow_class = "logical", has_length = 1, .call_depth = -2)
|
||||
meet_criteria(include_screening, allow_class = "logical", has_length = 1, .call_depth = -2)
|
||||
meet_criteria(include_PKPD, allow_class = "logical", has_length = 1, .call_depth = -2)
|
||||
reference_data <- check_reference_data(reference_data, .call_depth = -2)
|
||||
check_reference_data(reference_data, .call_depth = -2)
|
||||
meet_criteria(breakpoint_type, allow_class = "character", is_in = reference_data$type, has_length = 1, .call_depth = -2)
|
||||
meet_criteria(host, allow_class = c("character", "factor"), allow_NULL = TRUE, allow_NA = TRUE, .call_depth = -2)
|
||||
language <- validate_language(language)
|
||||
@@ -1253,13 +1174,12 @@ as_sir_method <- function(method_short,
|
||||
|
||||
# backward compatibilty
|
||||
dots <- list(...)
|
||||
dots <- dots[which(!names(dots) %in% c("warn", "mo.bak", "is_data.frame", "as_wt_nwt"))]
|
||||
dots <- dots[which(!names(dots) %in% c("warn", "mo.bak", "is_data.frame"))]
|
||||
if (length(dots) != 0) {
|
||||
warning_("These arguments in {.help [{.fun as.sir}](AMR::as.sir)} are no longer used: ", vector_and(names(dots), quotes = "`"), ".", call = FALSE)
|
||||
}
|
||||
|
||||
current_sir_interpretation_history <- NROW(AMR_env$sir_interpretation_history)
|
||||
custom_breakpoints_set <- !identical(reference_data, AMR::clinical_breakpoints)
|
||||
|
||||
if (isTRUE(info) && message_not_thrown_before("as.sir", "sir_interpretation_history")) {
|
||||
message_("Run {.help [{.fun sir_interpretation_history}](AMR::sir_interpretation_history)} afterwards to retrieve a logbook with all details of the breakpoint interpretations.\n\n")
|
||||
@@ -1464,7 +1384,7 @@ as_sir_method <- function(method_short,
|
||||
"\u00a0\u00a0", AMR_env$bullet_icon, " Interpreting ", method_long, ": ", ifelse(isTRUE(list(...)$is_data.frame), "column ", ""),
|
||||
ifelse(length(unique(agent_formatted)) == 1, unique(agent_formatted), paste0(vector_and(agent_formatted, quotes = FALSE, sort = FALSE))),
|
||||
mo_var_found,
|
||||
ifelse(!custom_breakpoints_set,
|
||||
ifelse(identical(reference_data, AMR::clinical_breakpoints),
|
||||
paste0(", ", vector_and(font_bold(guideline_coerced, collapse = NULL), quotes = FALSE)),
|
||||
""
|
||||
),
|
||||
@@ -1481,7 +1401,7 @@ as_sir_method <- function(method_short,
|
||||
method_coerced <- toupper(method)
|
||||
ab_coerced <- as.ab(ab, info = FALSE)
|
||||
|
||||
if (!custom_breakpoints_set) {
|
||||
if (identical(reference_data, AMR::clinical_breakpoints)) {
|
||||
breakpoints <- reference_data %pm>%
|
||||
subset(guideline %in% guideline_coerced & method == method_coerced & ab %in% ab_coerced)
|
||||
if (any(ab_coerced == "AMX") && nrow(breakpoints[breakpoints$ab == "AMX", , drop = FALSE]) == 0) {
|
||||
@@ -1572,11 +1492,11 @@ as_sir_method <- function(method_short,
|
||||
add_intrinsic_resistance_to_AMR_env()
|
||||
}
|
||||
|
||||
if (isTRUE(info) && (nrow(df_unique) < 10 || nrow(breakpoints) == 0)) {
|
||||
if (isTRUE(info) && nrow(df_unique) < 10 || nrow(breakpoints) == 0) {
|
||||
# only print intro under 10 items, otherwise progressbar will print this and then it will be printed double
|
||||
message_(intro_txt, appendLF = FALSE, as_note = FALSE)
|
||||
}
|
||||
p <- progress_ticker(n = nrow(df_unique), n_min = 10, print = isTRUE(info), title = intro_txt, only_bar_percent = TRUE)
|
||||
p <- progress_ticker(n = nrow(df_unique), n_min = 10, title = intro_txt, only_bar_percent = TRUE)
|
||||
has_progress_bar <- !is.null(import_fn("progress_bar", "progress", error_on_fail = FALSE)) && nrow(df_unique) >= 10
|
||||
on.exit(close(p))
|
||||
|
||||
@@ -1664,15 +1584,8 @@ as_sir_method <- function(method_short,
|
||||
|
||||
# gather all available breakpoints for current MO
|
||||
# TODO for VET09 do not filter out E. coli and such
|
||||
# For custom reference_data: skip guideline filter when guideline_current is not in the data (#239)
|
||||
guideline_filter_current <- if (custom_breakpoints_set &&
|
||||
!guideline_current %in% breakpoints$guideline) {
|
||||
unique(breakpoints$guideline)
|
||||
} else {
|
||||
guideline_current
|
||||
}
|
||||
breakpoints_current <- breakpoints %pm>%
|
||||
subset(ab == ab_current & guideline %in% guideline_filter_current) %pm>%
|
||||
subset(ab == ab_current & guideline == guideline_current) %pm>%
|
||||
subset(mo %in% c(
|
||||
mo_current, mo_current_genus, mo_current_family,
|
||||
mo_current_order, mo_current_class,
|
||||
@@ -1682,13 +1595,8 @@ as_sir_method <- function(method_short,
|
||||
))
|
||||
|
||||
if (breakpoint_type == "animal") {
|
||||
host_matched <- breakpoints_current[which(breakpoints_current$host == host_current), , drop = FALSE]
|
||||
if (nrow(host_matched) > 0) {
|
||||
breakpoints_current <- host_matched
|
||||
} else {
|
||||
# fall back to host-agnostic rows (host = NA) for custom breakpoint tables (#239)
|
||||
breakpoints_current <- breakpoints_current[which(is.na(breakpoints_current$host)), , drop = FALSE]
|
||||
}
|
||||
# 2025-03-13/ for now, only strictly follow guideline for current host, no extrapolation
|
||||
breakpoints_current <- breakpoints_current[which(breakpoints_current$host == host_current), , drop = FALSE]
|
||||
}
|
||||
|
||||
## fall-back methods for veterinary guidelines ----
|
||||
@@ -1964,11 +1872,8 @@ as_sir_method <- function(method_short,
|
||||
|
||||
# otherwise: the normal (uncapped or ignored) interpretation
|
||||
input_clean <= breakpoints_current$breakpoint_S ~ as.sir("S"),
|
||||
# standard data: EUCAST open interval (>), CLSI closed interval (>=)
|
||||
!custom_breakpoints_set & guideline_current %like% "EUCAST" & input_clean > breakpoints_current$breakpoint_R ~ as.sir("R"),
|
||||
!custom_breakpoints_set & guideline_current %like% "CLSI" & input_clean >= breakpoints_current$breakpoint_R ~ as.sir("R"),
|
||||
# custom reference_data: always EUCAST open interval (>), regardless of guideline name
|
||||
custom_breakpoints_set & input_clean > breakpoints_current$breakpoint_R ~ as.sir("R"),
|
||||
guideline_current %like% "EUCAST" & input_clean > breakpoints_current$breakpoint_R ~ as.sir("R"),
|
||||
guideline_current %like% "CLSI" & input_clean >= breakpoints_current$breakpoint_R ~ as.sir("R"),
|
||||
|
||||
# return "I" or "SDD" when breakpoints are in the middle
|
||||
!is.na(breakpoints_current$breakpoint_S) & !is.na(breakpoints_current$breakpoint_R) & breakpoints_current$is_SDD == TRUE ~ as.sir("SDD"),
|
||||
@@ -1981,11 +1886,8 @@ as_sir_method <- function(method_short,
|
||||
new_sir <- case_when_AMR(
|
||||
is.na(input_clean) ~ NA_sir_,
|
||||
as.double(input_clean) >= as.double(breakpoints_current$breakpoint_S) ~ as.sir("S"),
|
||||
# standard data: EUCAST open interval (<), CLSI closed interval (<=)
|
||||
!custom_breakpoints_set & guideline_current %like% "EUCAST" & as.double(input_clean) < as.double(breakpoints_current$breakpoint_R) ~ as.sir("R"),
|
||||
!custom_breakpoints_set & guideline_current %like% "CLSI" & as.double(input_clean) <= as.double(breakpoints_current$breakpoint_R) ~ as.sir("R"),
|
||||
# custom reference_data: always EUCAST open interval (<), regardless of guideline name
|
||||
custom_breakpoints_set & as.double(input_clean) < as.double(breakpoints_current$breakpoint_R) ~ as.sir("R"),
|
||||
guideline_current %like% "EUCAST" & as.double(input_clean) < as.double(breakpoints_current$breakpoint_R) ~ as.sir("R"),
|
||||
guideline_current %like% "CLSI" & as.double(input_clean) <= as.double(breakpoints_current$breakpoint_R) ~ as.sir("R"),
|
||||
# return "I" or "SDD" when breakpoints are in the middle
|
||||
!is.na(breakpoints_current$breakpoint_S) & !is.na(breakpoints_current$breakpoint_R) & breakpoints_current$is_SDD == TRUE ~ as.sir("SDD"),
|
||||
!is.na(breakpoints_current$breakpoint_S) & !is.na(breakpoints_current$breakpoint_R) & breakpoints_current$is_SDD == FALSE ~ as.sir("I"),
|
||||
@@ -2094,7 +1996,7 @@ sir_interpretation_history <- function(clean = FALSE) {
|
||||
#' @noRd
|
||||
print.sir_log <- function(x, ...) {
|
||||
if (NROW(x) == 0) {
|
||||
message_("No results to print. First run {.help [{.fun as.sir}](AMR::as.sir)} on MIC values or disk diffusion zones (or on a {.cls data.frame} containing any of these) to print a 'logbook' data set here.")
|
||||
message_("No results to print. First run {.help [{.fun as.sir}](AMR::as.sir)} on MIC values or disk diffusion zones (or on a {.cls data.frame} containing any of these) to print a {.val logbook} data set here.")
|
||||
return(invisible(NULL))
|
||||
}
|
||||
class(x) <- class(x)[class(x) != "sir_log"]
|
||||
@@ -2332,36 +2234,13 @@ rep.sir <- function(x, ...) {
|
||||
y
|
||||
}
|
||||
|
||||
coerce_reference_data_columns <- function(x) {
|
||||
ref <- AMR::clinical_breakpoints
|
||||
for (col in names(ref)) {
|
||||
col_ref <- ref[[col]]
|
||||
col_x <- x[[col]]
|
||||
if (identical(class(col_ref), class(col_x))) next
|
||||
if (col == "mo") {
|
||||
x[[col]] <- suppressMessages(as.mo(col_x))
|
||||
} else if (col == "ab") {
|
||||
x[[col]] <- suppressMessages(as.ab(col_x))
|
||||
} else if (is.character(col_ref)) {
|
||||
x[[col]] <- as.character(col_x)
|
||||
} else if (is.numeric(col_ref)) {
|
||||
x[[col]] <- as.double(col_x)
|
||||
} else if (is.logical(col_ref)) {
|
||||
x[[col]] <- as.logical(col_x)
|
||||
}
|
||||
}
|
||||
x
|
||||
}
|
||||
|
||||
check_reference_data <- function(reference_data, .call_depth) {
|
||||
if (!identical(reference_data, AMR::clinical_breakpoints)) {
|
||||
if (!all(names(AMR::clinical_breakpoints) == names(reference_data))) {
|
||||
stop_("{.arg reference_data} must have the same column names as the {.help [clinical_breakpoints](AMR::clinical_breakpoints)} data set.", call = .call_depth)
|
||||
}
|
||||
# coerce mo, ab, and other columns to the expected types where possible
|
||||
reference_data <- coerce_reference_data_columns(reference_data)
|
||||
class_sir <- vapply(FUN.VALUE = character(1), AMR::clinical_breakpoints, function(x) paste0("<", class(x), ">", collapse = " and "))
|
||||
class_ref <- vapply(FUN.VALUE = character(1), reference_data, function(x) paste0("<", class(x), ">", collapse = " and "))
|
||||
if (!all(names(class_sir) == names(class_ref))) {
|
||||
stop_("{.arg reference_data} must have the same column names as the {.help [clinical_breakpoints](AMR::clinical_breakpoints)} data set.", call = .call_depth)
|
||||
}
|
||||
if (!all(class_sir == class_ref)) {
|
||||
bad_col <- names(class_ref[class_sir != class_ref][1])
|
||||
bad_cls <- gsub("<|>", "", class_ref[class_sir != class_ref][1])
|
||||
@@ -2369,5 +2248,4 @@ check_reference_data <- function(reference_data, .call_depth) {
|
||||
stop_("{.arg reference_data} must be the same structure as the {.help [clinical_breakpoints](AMR::clinical_breakpoints)} data set. Column ", paste0("{.field ", font_bold(bad_col, collapse = NULL), "}"), " is of class ", paste0("{.cls ", bad_cls, "}"), ", but should be of class ", paste0("{.cls ", exp_cls, "}"), call = .call_depth)
|
||||
}
|
||||
}
|
||||
reference_data
|
||||
}
|
||||
|
||||
BIN
R/sysdata.rda
BIN
R/sysdata.rda
Binary file not shown.
20
R/tidymodels.R
Executable file → Normal file
20
R/tidymodels.R
Executable file → Normal file
@@ -21,6 +21,7 @@
|
||||
#' @export
|
||||
#' @examples
|
||||
#' if (require("tidymodels")) {
|
||||
#'
|
||||
#' # The below approach formed the basis for this paper: DOI 10.3389/fmicb.2025.1582703
|
||||
#' # Presence of ESBL genes was predicted based on raw MIC values.
|
||||
#'
|
||||
@@ -39,10 +40,13 @@
|
||||
#'
|
||||
#' # Create and prep a recipe with MIC log2 transformation
|
||||
#' mic_recipe <- recipe(esbl ~ ., data = training_data) %>%
|
||||
#'
|
||||
#' # Optionally remove non-predictive variables
|
||||
#' remove_role(genus, old_role = "predictor") %>%
|
||||
#'
|
||||
#' # Apply the log2 transformation to all MIC predictors
|
||||
#' step_mic_log2(all_mic_predictors()) %>%
|
||||
#'
|
||||
#' # And apply the preparation steps
|
||||
#' prep()
|
||||
#'
|
||||
@@ -63,15 +67,13 @@
|
||||
#' bind_cols(out_testing)
|
||||
#'
|
||||
#' # Evaluate predictions using standard classification metrics
|
||||
#' our_metrics <- metric_set(
|
||||
#' accuracy,
|
||||
#' recall,
|
||||
#' precision,
|
||||
#' sensitivity,
|
||||
#' specificity,
|
||||
#' ppv,
|
||||
#' npv
|
||||
#' )
|
||||
#' our_metrics <- metric_set(accuracy,
|
||||
#' recall,
|
||||
#' precision,
|
||||
#' sensitivity,
|
||||
#' specificity,
|
||||
#' ppv,
|
||||
#' npv)
|
||||
#' metrics <- our_metrics(predictions, truth = esbl, estimate = .pred_class)
|
||||
#'
|
||||
#' # Show performance
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#' This function filters a data set to include only the top *n* microorganisms based on a specified property, such as taxonomic family or genus. For example, it can filter a data set to the top 3 species, or to any species in the top 5 genera, or to the top 3 species in each of the top 5 genera.
|
||||
#' @param x A data frame containing microbial data.
|
||||
#' @param n An integer specifying the maximum number of unique values of the `property` to include in the output.
|
||||
#' @param property A character string indicating the microorganism property to use for filtering. Must be one of the column names of the [microorganisms] data set: `r vector_or(colnames(microorganisms), sort = FALSE, documentation = TRUE)`. If `NULL`, the raw values from `col_mo` will be used without transformation. When using `"species"` (default) or `"subpecies"`, the genus will be added to make sure each (sub)species still belongs to the right genus.
|
||||
#' @param property A character string indicating the microorganism property to use for filtering. Must be one of the column names of the [microorganisms] data set: `r vector_or(colnames(microorganisms), sort = FALSE, quotes = TRUE)`. If `NULL`, the raw values from `col_mo` will be used without transformation. When using `"species"` (default) or `"subpecies"`, the genus will be added to make sure each (sub)species still belongs to the right genus.
|
||||
#' @param n_for_each An optional integer specifying the maximum number of rows to retain for each value of the selected property. If `NULL`, all rows within the top *n* groups will be included.
|
||||
#' @param col_mo A character string indicating the column in `x` that contains microorganism names or codes. Defaults to the first column of class [`mo`]. Values will be coerced using [as.mo()].
|
||||
#' @param ... Additional arguments passed on to [mo_property()] when `property` is not `NULL`.
|
||||
|
||||
@@ -70,13 +70,6 @@ as.data.frame.deprecated_amr_dataset <- function(x, ...) {
|
||||
# - `antibiotics` in `antibiogram()`
|
||||
# - `converse_capped_values` in `as.sir()`
|
||||
|
||||
#' @rdname AMR-deprecated
|
||||
#' @export
|
||||
custom_eucast_rules <- function(...) {
|
||||
deprecation_warning("custom_eucast_rules", "custom_interpretive_rules", is_function = TRUE)
|
||||
custom_interpretive_rules(...)
|
||||
}
|
||||
|
||||
#' @rdname AMR-deprecated
|
||||
#' @export
|
||||
ab_class <- function(...) {
|
||||
|
||||
10
_pkgdown.yml
10
_pkgdown.yml
@@ -156,17 +156,17 @@ reference:
|
||||
- "`atc_online_property`"
|
||||
- "`add_custom_antimicrobials`"
|
||||
|
||||
- title: "Interpreting data: antimicrobial results"
|
||||
- title: "Preparing data: antimicrobial results"
|
||||
desc: >
|
||||
With `as.mic()` and `as.disk()` you can transform your raw input to valid MIC or disk diffusion values.
|
||||
Use `as.sir()` for cleaning raw data to let it only contain "R", "I" and "S", or to interpret MIC or disk diffusion values as SIR based on the lastest EUCAST and CLSI guidelines.
|
||||
Afterwards, you can extend antibiotic interpretations by applying interpretive rules, for example [from EUCAST](https://www.eucast.org/expert_rules_and_intrinsic_resistance/) with `interpretive_rules()`.
|
||||
Afterwards, you can extend antibiotic interpretations by applying [EUCAST rules](https://www.eucast.org/expert_rules_and_intrinsic_resistance/) with `eucast_rules()`.
|
||||
contents:
|
||||
- "`as.sir`"
|
||||
- "`as.mic`"
|
||||
- "`as.disk`"
|
||||
- "`interpretive_rules`"
|
||||
- "`custom_interpretive_rules`"
|
||||
- "`eucast_rules`"
|
||||
- "`custom_eucast_rules`"
|
||||
|
||||
- title: "Analysing data"
|
||||
desc: >
|
||||
@@ -265,7 +265,7 @@ reference:
|
||||
|
||||
- title: "Other: statistical tests"
|
||||
desc: >
|
||||
Some statistical tests or methods usable for AMR analyses are not part of base R and were added to this package for convenience.
|
||||
Some statistical tests or methods are not part of base R and were added to this package for convenience.
|
||||
contents:
|
||||
- "`g.test`"
|
||||
- "`kurtosis`"
|
||||
|
||||
@@ -15,10 +15,8 @@ library(readr)
|
||||
library(tidyr)
|
||||
|
||||
# WHONET version of 16th Feb 2024
|
||||
whonet_breakpoints <- read_tsv("WHONET/Resources/Breakpoints.txt",
|
||||
na = c("", "NA", "-"),
|
||||
show_col_types = FALSE, guess_max = Inf
|
||||
) %>%
|
||||
whonet_breakpoints <- read_tsv("WHONET/Resources/Breakpoints.txt", na = c("", "NA", "-"),
|
||||
show_col_types = FALSE, guess_max = Inf) %>%
|
||||
filter(GUIDELINES %in% c("CLSI", "EUCAST"))
|
||||
|
||||
dim(whonet_breakpoints)
|
||||
@@ -50,9 +48,9 @@ whonet_breakpoints |>
|
||||
|
||||
```{r}
|
||||
whonet_breakpoints |>
|
||||
filter(HOST == "Cats", YEAR >= 2021) |>
|
||||
select(GUIDELINES, YEAR, TEST_METHOD, ORGANISM_CODE, R, S) |>
|
||||
mutate(MO_NAME = AMR::mo_shortname(ORGANISM_CODE), .before = R) |>
|
||||
filter(HOST == "Cats", YEAR >= 2021) |>
|
||||
select(GUIDELINES, YEAR, TEST_METHOD, ORGANISM_CODE, R, S) |>
|
||||
mutate(MO_NAME = AMR::mo_shortname(ORGANISM_CODE), .before = R) |>
|
||||
as.data.frame()
|
||||
```
|
||||
|
||||
@@ -60,14 +58,12 @@ whonet_breakpoints |>
|
||||
|
||||
```{r}
|
||||
whonet_breakpoints |>
|
||||
filter(HOST == "Cats", YEAR == 2023) |>
|
||||
mutate(
|
||||
MO = AMR::mo_shortname(ORGANISM_CODE),
|
||||
AB = AMR::ab_name(WHONET_ABX_CODE),
|
||||
SITE_OF_INFECTION = substr(SITE_OF_INFECTION, 1, 25)
|
||||
) |>
|
||||
arrange(MO, AB) |>
|
||||
select(MO, AB, SITE_OF_INFECTION) |>
|
||||
filter(HOST == "Cats", YEAR == 2023) |>
|
||||
mutate(MO = AMR::mo_shortname(ORGANISM_CODE),
|
||||
AB = AMR::ab_name(WHONET_ABX_CODE),
|
||||
SITE_OF_INFECTION = substr(SITE_OF_INFECTION, 1, 25)) |>
|
||||
arrange(MO, AB) |>
|
||||
select(MO, AB, SITE_OF_INFECTION) |>
|
||||
as.data.frame()
|
||||
```
|
||||
|
||||
|
||||
@@ -42,9 +42,9 @@ pre_commit_lst <- list()
|
||||
|
||||
usethis::ui_info(paste0("Updating internal package data"))
|
||||
|
||||
# See 'data-raw/interpretive_rules.tsv' for the interpretive rules reference file
|
||||
pre_commit_lst$INTERPRETIVE_RULES_DF <- utils::read.delim(
|
||||
file = "data-raw/interpretive_rules.tsv",
|
||||
# See 'data-raw/eucast_rules.tsv' for the EUCAST reference file
|
||||
pre_commit_lst$EUCAST_RULES_DF <- utils::read.delim(
|
||||
file = "data-raw/eucast_rules.tsv",
|
||||
skip = 9,
|
||||
sep = "\t",
|
||||
stringsAsFactors = FALSE,
|
||||
@@ -364,7 +364,7 @@ pre_commit_lst$MO_RELEVANT_GENERA <- c(
|
||||
)
|
||||
|
||||
# antibiotic groups
|
||||
# (these will also be used for interpretive_rules() and understanding data-raw/interpretive_rules.tsv)
|
||||
# (these will also be used for eucast_rules() and understanding data-raw/eucast_rules.tsv)
|
||||
pre_commit_lst$AB_AMINOGLYCOSIDES <- antimicrobials %>%
|
||||
filter(group %like% "aminoglycoside|paromomycin|spectinomycin") %>%
|
||||
pull(ab)
|
||||
@@ -406,7 +406,7 @@ pre_commit_lst$AB_GLYCOPEPTIDES <- antimicrobials %>%
|
||||
pre_commit_lst$AB_FUSIDANES <- antimicrobials %>%
|
||||
filter(name %like% "fusi") %>%
|
||||
pull(ab)
|
||||
pre_commit_lst$AB_IONOPHORES <- antimicrobials %>%
|
||||
pre_commit_lst$AB_IONOPHORES<- antimicrobials %>%
|
||||
filter(name %like% "alamethicin|beauvericin|calcimycin|chloroquine|clioquinol|diiodohydroxyquinoline|dithiocarbamates|enniatin|epigallocatechin|gramicidin|hinokitiol|ionomycin|laidlomycin|lasalocid|maduramicin|monensin|narasin|nigericin|nonactin|nystatin|pyrazole|pyrithione|quercetin|salinomycin|semduramicin|valinomycin|zincophorin") %>%
|
||||
pull(ab)
|
||||
pre_commit_lst$AB_ISOXAZOLYLPENICILLINS <- antimicrobials %>%
|
||||
@@ -478,8 +478,7 @@ pre_commit_lst$AB_BETALACTAMS <- sort(c(
|
||||
pre_commit_lst$AB_PENICILLINS,
|
||||
pre_commit_lst$AB_CEPHALOSPORINS,
|
||||
pre_commit_lst$AB_CARBAPENEMS,
|
||||
pre_commit_lst$AB_MONOBACTAMS
|
||||
))
|
||||
pre_commit_lst$AB_MONOBACTAMS))
|
||||
pre_commit_lst$AB_BETALACTAMASE_INHIBITORS <- antimicrobials %>%
|
||||
filter(atc_group2 %like% "Beta-lactamase inhibitors" | name %like% "bactam") %>%
|
||||
pull(ab)
|
||||
@@ -496,9 +495,8 @@ for (grp in pre_commit_lst$DEFINED_AB_GROUPS[pre_commit_lst$DEFINED_AB_GROUPS %u
|
||||
fn_name <- tolower(gsub("^AB_", "", grp))
|
||||
if (!fn_name %in% ls(envir = asNamespace("AMR"))) {
|
||||
stop("Group '", grp, "' has ", length(pre_commit_lst[[grp]]),
|
||||
" members (", toString(ab_name(pre_commit_lst[[grp]], tolower = T)), ") but no corresponding function '", fn_name, "()' exists in the AMR namespace.",
|
||||
call. = FALSE
|
||||
)
|
||||
" members (", toString(ab_name(pre_commit_lst[[grp]], tolower = T)), ") but no corresponding function '", fn_name, "()' exists in the AMR namespace.",
|
||||
call. = FALSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -536,48 +534,46 @@ for (i in seq_along(group_map)) {
|
||||
}
|
||||
|
||||
# create priority list for ab_group()
|
||||
pre_commit_lst$ABX_PRIORITY_LIST <- c(
|
||||
"Aminopenicillins",
|
||||
"Isoxazolylpenicillins",
|
||||
"Ureidopenicillins",
|
||||
"Oxazolidinones",
|
||||
"Carbapenems",
|
||||
"Cephalosporins (1st gen.)",
|
||||
"Cephalosporins (2nd gen.)",
|
||||
"Cephalosporins (3rd gen.)",
|
||||
"Cephalosporins (4th gen.)",
|
||||
"Cephalosporins (5th gen.)",
|
||||
"Cephalosporins",
|
||||
"Penicillins",
|
||||
"Monobactams",
|
||||
"Aminoglycosides",
|
||||
"Lipoglycopeptides",
|
||||
"Glycopeptides",
|
||||
"Peptides",
|
||||
"Lincosamides",
|
||||
"Streptogramins",
|
||||
"Macrolides",
|
||||
"Nitrofurans",
|
||||
"Phenicols",
|
||||
"Phosphonics",
|
||||
"Polymyxins",
|
||||
"Fluoroquinolones",
|
||||
"Quinolones",
|
||||
"Rifamycins",
|
||||
"Spiropyrimidinetriones",
|
||||
"Trimethoprims",
|
||||
"Sulfonamides",
|
||||
"Tetracyclines",
|
||||
"Ionophores",
|
||||
"Antifungals",
|
||||
"Antimycobacterials",
|
||||
"Fusidanes",
|
||||
"Beta-lactams",
|
||||
"Beta-lactamase inhibitors",
|
||||
"Pleuromutilins",
|
||||
"Aminocoumarins",
|
||||
"Other"
|
||||
)
|
||||
pre_commit_lst$ABX_PRIORITY_LIST <- c("Aminopenicillins",
|
||||
"Isoxazolylpenicillins",
|
||||
"Ureidopenicillins",
|
||||
"Oxazolidinones",
|
||||
"Carbapenems",
|
||||
"Cephalosporins (1st gen.)",
|
||||
"Cephalosporins (2nd gen.)",
|
||||
"Cephalosporins (3rd gen.)",
|
||||
"Cephalosporins (4th gen.)",
|
||||
"Cephalosporins (5th gen.)",
|
||||
"Cephalosporins",
|
||||
"Penicillins",
|
||||
"Monobactams",
|
||||
"Aminoglycosides",
|
||||
"Lipoglycopeptides",
|
||||
"Glycopeptides",
|
||||
"Peptides",
|
||||
"Lincosamides",
|
||||
"Streptogramins",
|
||||
"Macrolides",
|
||||
"Nitrofurans",
|
||||
"Phenicols",
|
||||
"Phosphonics",
|
||||
"Polymyxins",
|
||||
"Fluoroquinolones",
|
||||
"Quinolones",
|
||||
"Rifamycins",
|
||||
"Spiropyrimidinetriones",
|
||||
"Trimethoprims",
|
||||
"Sulfonamides",
|
||||
"Tetracyclines",
|
||||
"Ionophores",
|
||||
"Antifungals",
|
||||
"Antimycobacterials",
|
||||
"Fusidanes",
|
||||
"Beta-lactams",
|
||||
"Beta-lactamase inhibitors",
|
||||
"Pleuromutilins",
|
||||
"Aminocoumarins",
|
||||
"Other")
|
||||
if (!all(unlist(antimicrobials$group) %in% pre_commit_lst$ABX_PRIORITY_LIST)) {
|
||||
stop("Missing group(s) in priority list: ", paste(setdiff(unlist(antimicrobials$group), pre_commit_lst$ABX_PRIORITY_LIST), collapse = ", "))
|
||||
}
|
||||
@@ -593,17 +589,17 @@ pre_commit_lst$AV_LOOKUP <- create_AB_AV_lookup(antivirals)
|
||||
# Export to package as internal data ----
|
||||
# usethis::use_data() must receive unquoted object names, which is not flexible at all.
|
||||
# we'll use good old base::save() instead
|
||||
save(
|
||||
list = names(pre_commit_lst),
|
||||
file = "R/sysdata.rda",
|
||||
envir = as.environment(pre_commit_lst),
|
||||
compress = "xz",
|
||||
version = 2,
|
||||
ascii = FALSE
|
||||
)
|
||||
save(list = names(pre_commit_lst),
|
||||
file = "R/sysdata.rda",
|
||||
envir = as.environment(pre_commit_lst),
|
||||
compress = "xz",
|
||||
version = 2,
|
||||
ascii = FALSE)
|
||||
usethis::ui_done("Saved to {usethis::ui_value('R/sysdata.rda')}")
|
||||
|
||||
|
||||
|
||||
|
||||
# Export data sets to the repository in different formats -----------------
|
||||
|
||||
for (pkg in c("haven", "openxlsx2", "arrow")) {
|
||||
@@ -625,9 +621,7 @@ write_md5 <- function(object) {
|
||||
}
|
||||
changed_md5 <- function(object) {
|
||||
path <- paste0("data-raw/", deparse(substitute(object)), ".md5")
|
||||
if (!file.exists(path)) {
|
||||
return(TRUE)
|
||||
}
|
||||
if (!file.exists(path)) return(TRUE)
|
||||
tryCatch(
|
||||
{
|
||||
conn <- file(path)
|
||||
@@ -765,14 +759,11 @@ devtools::load_all(quiet = TRUE)
|
||||
suppressMessages(set_AMR_locale("English"))
|
||||
|
||||
files_changed <- function(paths = "^(R|data)/") {
|
||||
tryCatch(
|
||||
{
|
||||
changed_files <- system("git status", intern = TRUE)
|
||||
changed_files <- unlist(strsplit(changed_files, " "))
|
||||
any(changed_files %like% paths[paths != "R/sysdata.rda"])
|
||||
},
|
||||
error = function(e) TRUE
|
||||
)
|
||||
tryCatch({
|
||||
changed_files <- system("git status", intern = TRUE)
|
||||
changed_files <- unlist(strsplit(changed_files, " "))
|
||||
any(changed_files %like% paths[paths != "R/sysdata.rda"])
|
||||
}, error = function(e) TRUE)
|
||||
}
|
||||
|
||||
# Update URLs -------------------------------------------------------------
|
||||
@@ -810,10 +801,8 @@ if (files_changed()) {
|
||||
# Style pkg ---------------------------------------------------------------
|
||||
if (files_changed(paths = "^(R|tests)/")) {
|
||||
usethis::ui_info("Styling package")
|
||||
styler::style_pkg(
|
||||
include_roxygen_examples = FALSE,
|
||||
exclude_dirs = list.dirs(full.names = FALSE, recursive = FALSE)[!list.dirs(full.names = FALSE, recursive = FALSE) %in% c("R", "tests")]
|
||||
)
|
||||
styler::style_pkg(include_roxygen_examples = FALSE,
|
||||
exclude_dirs = list.dirs(full.names = FALSE, recursive = FALSE)[!list.dirs(full.names = FALSE, recursive = FALSE) %in% c("R", "tests")])
|
||||
}
|
||||
|
||||
# Document pkg ------------------------------------------------------------
|
||||
@@ -824,13 +813,13 @@ if (files_changed()) {
|
||||
|
||||
# Update index.md and README.md -------------------------------------------
|
||||
if (files_changed("README.Rmd") ||
|
||||
files_changed("index.Rmd") ||
|
||||
files_changed("man/microorganisms.Rd") ||
|
||||
files_changed("man/antimicrobials.Rd") ||
|
||||
files_changed("man/clinical_breakpoints.Rd") ||
|
||||
files_changed("man/antibiogram.Rd") ||
|
||||
files_changed("R/antibiogram.R") ||
|
||||
files_changed("data-raw/translations.tsv")) {
|
||||
files_changed("index.Rmd") ||
|
||||
files_changed("man/microorganisms.Rd") ||
|
||||
files_changed("man/antimicrobials.Rd") ||
|
||||
files_changed("man/clinical_breakpoints.Rd") ||
|
||||
files_changed("man/antibiogram.Rd") ||
|
||||
files_changed("R/antibiogram.R") ||
|
||||
files_changed("data-raw/translations.tsv")) {
|
||||
usethis::ui_info("Rendering {usethis::ui_field('index.md')} and {usethis::ui_field('README.md')}")
|
||||
suppressWarnings(rmarkdown::render("index.Rmd", quiet = TRUE))
|
||||
suppressWarnings(rmarkdown::render("README.Rmd", quiet = TRUE))
|
||||
|
||||
@@ -262,9 +262,9 @@ get_synonyms <- function(CID, clean = TRUE) {
|
||||
if (is.na(CID[i])) {
|
||||
next
|
||||
}
|
||||
|
||||
|
||||
all_cids <- CID[i]
|
||||
|
||||
|
||||
# we will now get the closest compounds with a 96% threshold
|
||||
similar_cids <- tryCatch(
|
||||
data.table::fread(
|
||||
@@ -281,7 +281,7 @@ get_synonyms <- function(CID, clean = TRUE) {
|
||||
# leave out all CIDs that we have in our antimicrobials dataset to prevent duplication
|
||||
similar_cids <- similar_cids[!similar_cids %in% antimicrobials$cid[!is.na(antimicrobials$cid)]]
|
||||
all_cids <- unique(c(all_cids, similar_cids))
|
||||
|
||||
|
||||
# for each one, we are getting the synonyms
|
||||
current_syns <- character(0)
|
||||
for (j in seq_len(length(all_cids))) {
|
||||
@@ -297,9 +297,9 @@ get_synonyms <- function(CID, clean = TRUE) {
|
||||
)[[1]],
|
||||
error = function(e) NA_character_
|
||||
)
|
||||
|
||||
|
||||
Sys.sleep(0.05)
|
||||
|
||||
|
||||
if (clean == TRUE) {
|
||||
# remove text between brackets
|
||||
synonyms_txt <- trimws(gsub(
|
||||
@@ -319,16 +319,16 @@ get_synonyms <- function(CID, clean = TRUE) {
|
||||
synonyms_txt <- gsub("[^a-z]+$", "", ignore.case = TRUE, synonyms_txt)
|
||||
# only length 5 to 20 and lower-case names starting with a capital letter
|
||||
synonyms_txt <- synonyms_txt[nchar(synonyms_txt) %in% c(5:20) &
|
||||
grepl("^[A-Z][a-z]+$", synonyms_txt, ignore.case = FALSE)]
|
||||
grepl("^[A-Z][a-z]+$", synonyms_txt, ignore.case = FALSE)]
|
||||
synonyms_txt <- unlist(strsplit(synonyms_txt, ";", fixed = TRUE))
|
||||
}
|
||||
|
||||
|
||||
# synonyms must not be set for other agents, so remove the duplicates
|
||||
synonyms_txt <- synonyms_txt[!synonyms_txt %in% unlist(synonyms)]
|
||||
|
||||
|
||||
current_syns <- c(current_syns, synonyms_txt)
|
||||
}
|
||||
|
||||
|
||||
current_syns <- unique(trimws(current_syns[tolower(current_syns) %in% unique(tolower(current_syns))]))
|
||||
synonyms[i] <- list(sort(current_syns))
|
||||
}
|
||||
@@ -763,12 +763,10 @@ antimicrobials[which(antimicrobials$ab %in% c("CYC", "LNZ", "THA", "TZD")), "gro
|
||||
# add efflux
|
||||
effl <- antimicrobials |>
|
||||
filter(ab == "ACM") |>
|
||||
mutate(
|
||||
ab = as.character("EFF"),
|
||||
cid = NA_real_,
|
||||
name = "Efflux",
|
||||
group = "Other"
|
||||
)
|
||||
mutate(ab = as.character("EFF"),
|
||||
cid = NA_real_,
|
||||
name = "Efflux",
|
||||
group = "Other")
|
||||
antimicrobials <- antimicrobials |>
|
||||
mutate(ab = as.character(ab)) |>
|
||||
bind_rows(effl)
|
||||
@@ -779,11 +777,9 @@ antimicrobials[which(antimicrobials$ab == "EFF"), "abbreviations"][[1]] <- list(
|
||||
# add clindamycin inducible screening
|
||||
clin <- antimicrobials |>
|
||||
filter(ab == "FOX1") |>
|
||||
mutate(
|
||||
ab = as.character("CLI-S"),
|
||||
name = "Clindamycin inducible screening",
|
||||
group = "Macrolides/lincosamides"
|
||||
)
|
||||
mutate(ab = as.character("CLI-S"),
|
||||
name = "Clindamycin inducible screening",
|
||||
group = "Macrolides/lincosamides")
|
||||
antimicrobials <- antimicrobials |>
|
||||
mutate(ab = as.character(ab)) |>
|
||||
bind_rows(clin)
|
||||
@@ -795,123 +791,109 @@ antimicrobials <- antimicrobials |>
|
||||
bind_rows(
|
||||
antimicrobials |>
|
||||
filter(ab == "EFF") |>
|
||||
mutate(
|
||||
ab = "BLA-S",
|
||||
name = paste("Beta-lactamase", "screening test"),
|
||||
cid = NA_real_,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("beta-lactamase", "betalactamase", "bl screen", "blt screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))
|
||||
),
|
||||
mutate(ab = "BLA-S",
|
||||
name = paste("Beta-lactamase", "screening test"),
|
||||
cid = NA_real_,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("beta-lactamase", "betalactamase", "bl screen", "blt screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))),
|
||||
antimicrobials |>
|
||||
filter(ab == "PEN") |>
|
||||
mutate(
|
||||
ab = "PEN-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("pen screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))
|
||||
),
|
||||
mutate(ab = "PEN-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("pen screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))),
|
||||
antimicrobials |>
|
||||
filter(ab == "OXA") |>
|
||||
mutate(
|
||||
ab = "OXA-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("oxa screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))
|
||||
),
|
||||
mutate(ab = "OXA-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("oxa screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))),
|
||||
antimicrobials |>
|
||||
filter(ab == "PEF") |>
|
||||
mutate(
|
||||
ab = "PEF-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("pef screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))
|
||||
),
|
||||
mutate(ab = "PEF-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("pef screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))),
|
||||
antimicrobials |>
|
||||
filter(ab == "NAL") |>
|
||||
mutate(
|
||||
ab = "NAL-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("nal screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))
|
||||
),
|
||||
mutate(ab = "NAL-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("nal screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))),
|
||||
antimicrobials |>
|
||||
filter(ab == "NOR") |>
|
||||
mutate(
|
||||
ab = "NOR-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("nor screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))
|
||||
),
|
||||
mutate(ab = "NOR-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("nor screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))),
|
||||
antimicrobials |>
|
||||
filter(ab == "TCY") |>
|
||||
mutate(
|
||||
ab = "TCY-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("tcy screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0))
|
||||
)
|
||||
mutate(ab = "TCY-S",
|
||||
name = paste(name, "screening test"),
|
||||
cid = NA,
|
||||
atc = list(character(0)),
|
||||
atc_group1 = NA_character_,
|
||||
atc_group2 = NA_character_,
|
||||
abbreviations = list(c("tcy screen")),
|
||||
synonyms = list(character(0)),
|
||||
oral_ddd = NA_real_,
|
||||
oral_units = NA_character_,
|
||||
iv_ddd = NA_real_,
|
||||
iv_units = NA_character_,
|
||||
loinc = list(character(0)))
|
||||
)
|
||||
|
||||
|
||||
@@ -937,20 +919,16 @@ antimicrobials <- antimicrobials |>
|
||||
antimicrobials |>
|
||||
filter(ab == "FPE") |>
|
||||
mutate(ab = as.character(ab)) |>
|
||||
mutate(
|
||||
ab = "FTA",
|
||||
name = "Cefepime/taniborbactam",
|
||||
cid = NA_real_
|
||||
),
|
||||
mutate(ab = "FTA",
|
||||
name = "Cefepime/taniborbactam",
|
||||
cid = NA_real_),
|
||||
antimicrobials |>
|
||||
filter(ab == "TBP") |>
|
||||
mutate(ab = as.character(ab)) |>
|
||||
mutate(
|
||||
ab = "TAN",
|
||||
name = "Taniborbactam",
|
||||
cid = 76902493,
|
||||
abbreviations = list("VNRX-5133")
|
||||
)
|
||||
mutate(ab = "TAN",
|
||||
name = "Taniborbactam",
|
||||
cid = 76902493,
|
||||
abbreviations = list("VNRX-5133"))
|
||||
)
|
||||
|
||||
antimicrobials <- antimicrobials |>
|
||||
@@ -958,51 +936,39 @@ antimicrobials <- antimicrobials |>
|
||||
bind_rows(
|
||||
antimicrobials |>
|
||||
filter(ab == "CTB") |>
|
||||
mutate(
|
||||
ab = "CTA",
|
||||
cid = NA_real_,
|
||||
name = "Ceftibuten/avibactam"
|
||||
) |>
|
||||
mutate(ab = "CTA",
|
||||
cid = NA_real_,
|
||||
name = "Ceftibuten/avibactam") |>
|
||||
select(1:4),
|
||||
antimicrobials |>
|
||||
filter(ab == "KAC") |>
|
||||
mutate(
|
||||
ab = "KAS",
|
||||
cid = NA_real_,
|
||||
name = "Kasugamycin"
|
||||
) |>
|
||||
mutate(ab = "KAS",
|
||||
cid = NA_real_,
|
||||
name = "Kasugamycin") |>
|
||||
select(1:4),
|
||||
antimicrobials |>
|
||||
filter(ab == "PRI") |>
|
||||
mutate(
|
||||
ab = "OST",
|
||||
cid = NA_real_,
|
||||
name = "Ostreogrycin"
|
||||
) |>
|
||||
mutate(ab = "OST",
|
||||
cid = NA_real_,
|
||||
name = "Ostreogrycin") |>
|
||||
select(1:4),
|
||||
antimicrobials |>
|
||||
filter(ab == "PRI") |>
|
||||
mutate(
|
||||
ab = "THS",
|
||||
cid = NA_real_,
|
||||
name = "Thiostrepton"
|
||||
) |>
|
||||
mutate(ab = "THS",
|
||||
cid = NA_real_,
|
||||
name = "Thiostrepton") |>
|
||||
select(1, 3),
|
||||
antimicrobials |>
|
||||
filter(ab == "CLA1") |>
|
||||
mutate(
|
||||
ab = "XER",
|
||||
cid = NA_real_,
|
||||
name = "Xeruborbactam"
|
||||
) |>
|
||||
mutate(ab = "XER",
|
||||
cid = NA_real_,
|
||||
name = "Xeruborbactam") |>
|
||||
select(1:4),
|
||||
antimicrobials |>
|
||||
filter(ab == "BLM") |>
|
||||
mutate(
|
||||
ab = "ZOR",
|
||||
cid = NA_real_,
|
||||
name = "Zorbamycin"
|
||||
) |>
|
||||
mutate(ab = "ZOR",
|
||||
cid = NA_real_,
|
||||
name = "Zorbamycin") |>
|
||||
select(1:4),
|
||||
)
|
||||
|
||||
@@ -1011,11 +977,9 @@ antimicrobials <- antimicrobials |>
|
||||
bind_rows(
|
||||
antimicrobials |>
|
||||
filter(ab == "NOV") |>
|
||||
mutate(
|
||||
ab = "CLB",
|
||||
cid = 54706138,
|
||||
name = "Clorobiocin"
|
||||
) |>
|
||||
mutate(ab = "CLB",
|
||||
cid = 54706138,
|
||||
name = "Clorobiocin") |>
|
||||
select(1:4),
|
||||
)
|
||||
|
||||
@@ -1026,7 +990,7 @@ get_atc_table <- function(ab_name, type = "human") {
|
||||
if (type == "human") {
|
||||
url <- "https://atcddd.fhi.no/atc_ddd_index/"
|
||||
} else if (type == "veterinary") {
|
||||
url <- "https://atcddd.fhi.no/atcvet/atcvet_index/"
|
||||
url <- "https://atcddd.fhi.no/atcvet/atcvet_index/"
|
||||
} else {
|
||||
stop("invalid type")
|
||||
}
|
||||
@@ -1091,10 +1055,8 @@ to_update <- 1:nrow(antimicrobials)
|
||||
# or just the empty ones:
|
||||
to_update <- which(sapply(antimicrobials$atc, function(x) length(x[!is.na(x)])) == 0)
|
||||
|
||||
updated_atc <- lapply(
|
||||
seq_len(length(to_update)),
|
||||
function(x) NA_character_
|
||||
)
|
||||
updated_atc <- lapply(seq_len(length(to_update)),
|
||||
function(x) NA_character_)
|
||||
|
||||
|
||||
# this takes around 10 minutes for the whole table (some ABx are skipped and go faster)
|
||||
|
||||
@@ -72,12 +72,12 @@ whonet_organisms <- whonet_organisms_raw |>
|
||||
ORGANISM = if_else(ORGANISM_CODE == "ckr", "Candida krusei", ORGANISM)
|
||||
) |>
|
||||
# try to match on GBIF identifier
|
||||
left_join(microorganisms |> distinct(mo, gbif, status) |> filter(!is.na(gbif)), by = c("GBIF_TAXON_ID" = "gbif")) |>
|
||||
left_join(microorganisms |> distinct(mo, gbif, status) |> filter(!is.na(gbif)), by = c("GBIF_TAXON_ID" = "gbif")) |>
|
||||
# remove duplicates
|
||||
arrange(ORGANISM_CODE, GBIF_TAXON_ID, status) |>
|
||||
distinct(ORGANISM_CODE, .keep_all = TRUE) |>
|
||||
distinct(ORGANISM_CODE, .keep_all = TRUE) |>
|
||||
# add Enterobacterales, which is a subkingdom code in their data
|
||||
bind_rows(data.frame(ORGANISM_CODE = "ebc", ORGANISM = "Enterobacterales", mo = as.mo("Enterobacterales"))) |>
|
||||
bind_rows(data.frame(ORGANISM_CODE = "ebc", ORGANISM = "Enterobacterales", mo = as.mo("Enterobacterales"))) |>
|
||||
arrange(ORGANISM)
|
||||
|
||||
|
||||
@@ -88,39 +88,31 @@ unmatched <- whonet_organisms |> filter(is.na(mo))
|
||||
|
||||
# generate the mo codes and add their names
|
||||
message("Getting MO codes for WHONET input...")
|
||||
unmatched <- unmatched |>
|
||||
mutate(
|
||||
mo = as.mo(gsub("(sero[a-z]*| nontypable| non[-][a-zA-Z]+|var[.]| not .*|sp[.],.*|, .*variant.*|, .*toxin.*|, microaer.*| beta-haem[.])", "", ORGANISM),
|
||||
minimum_matching_score = 0.55,
|
||||
keep_synonyms = TRUE,
|
||||
language = "en"
|
||||
),
|
||||
mo = case_when(
|
||||
ORGANISM %like% "Anaerobic" & ORGANISM %like% "negative" ~ as.mo("B_ANAER-NEG"),
|
||||
ORGANISM %like% "Anaerobic" & ORGANISM %like% "positive" ~ as.mo("B_ANAER-POS"),
|
||||
ORGANISM %like% "Anaerobic" ~ as.mo("B_ANAER"),
|
||||
TRUE ~ mo
|
||||
),
|
||||
mo_name = mo_name(mo,
|
||||
keep_synonyms = TRUE,
|
||||
language = "en"
|
||||
)
|
||||
)
|
||||
unmatched <- unmatched |>
|
||||
mutate(mo = as.mo(gsub("(sero[a-z]*| nontypable| non[-][a-zA-Z]+|var[.]| not .*|sp[.],.*|, .*variant.*|, .*toxin.*|, microaer.*| beta-haem[.])", "", ORGANISM),
|
||||
minimum_matching_score = 0.55,
|
||||
keep_synonyms = TRUE,
|
||||
language = "en"),
|
||||
mo = case_when(ORGANISM %like% "Anaerobic" & ORGANISM %like% "negative" ~ as.mo("B_ANAER-NEG"),
|
||||
ORGANISM %like% "Anaerobic" & ORGANISM %like% "positive" ~ as.mo("B_ANAER-POS"),
|
||||
ORGANISM %like% "Anaerobic" ~ as.mo("B_ANAER"),
|
||||
TRUE ~ mo),
|
||||
mo_name = mo_name(mo,
|
||||
keep_synonyms = TRUE,
|
||||
language = "en"))
|
||||
# check if coercion at least resembles the first part (genus)
|
||||
unmatched <- unmatched |>
|
||||
unmatched <- unmatched |>
|
||||
mutate(
|
||||
first_part = sapply(ORGANISM, function(x) strsplit(gsub("[^a-zA-Z _-]+", "", x), " ")[[1]][1], USE.NAMES = FALSE),
|
||||
keep = mo_name %like_case% first_part | ORGANISM %like% "Gram " | ORGANISM == "Other" | ORGANISM %like% "anaerobic"
|
||||
) |>
|
||||
keep = mo_name %like_case% first_part | ORGANISM %like% "Gram " | ORGANISM == "Other" | ORGANISM %like% "anaerobic") |>
|
||||
arrange(keep)
|
||||
unmatched |> View()
|
||||
unmatched <- unmatched |>
|
||||
filter(keep == TRUE)
|
||||
|
||||
organisms <- matched |>
|
||||
transmute(code = toupper(ORGANISM_CODE), group = SPECIES_GROUP, mo) |>
|
||||
bind_rows(unmatched |> transmute(code = toupper(ORGANISM_CODE), group = SPECIES_GROUP, mo)) |>
|
||||
mutate(name = mo_name(mo, keep_synonyms = TRUE)) |>
|
||||
organisms <- matched |> transmute(code = toupper(ORGANISM_CODE), group = SPECIES_GROUP, mo) |>
|
||||
bind_rows(unmatched |> transmute(code = toupper(ORGANISM_CODE), group = SPECIES_GROUP, mo)) |>
|
||||
mutate(name = mo_name(mo, keep_synonyms = TRUE)) |>
|
||||
arrange(code)
|
||||
|
||||
# self-defined codes in the MO table must be retained
|
||||
@@ -133,33 +125,25 @@ organisms <- organisms |>
|
||||
# some subspecies exist, while their upper species do not, add them as the species level:
|
||||
subspp <- organisms |>
|
||||
filter(mo_species(mo, keep_synonyms = TRUE) == mo_subspecies(mo, keep_synonyms = TRUE) &
|
||||
mo_species(mo, keep_synonyms = TRUE) != "" &
|
||||
mo_genus(mo, keep_synonyms = TRUE) != "Salmonella") |>
|
||||
mutate(
|
||||
mo = as.mo(
|
||||
paste(
|
||||
mo_genus(mo, keep_synonyms = TRUE),
|
||||
mo_species(mo, keep_synonyms = TRUE)
|
||||
),
|
||||
keep_synonyms = TRUE
|
||||
),
|
||||
name = mo_name(mo, keep_synonyms = TRUE)
|
||||
)
|
||||
mo_species(mo, keep_synonyms = TRUE) != "" &
|
||||
mo_genus(mo, keep_synonyms = TRUE) != "Salmonella") |>
|
||||
mutate(mo = as.mo(paste(mo_genus(mo, keep_synonyms = TRUE),
|
||||
mo_species(mo, keep_synonyms = TRUE)),
|
||||
keep_synonyms = TRUE),
|
||||
name = mo_name(mo, keep_synonyms = TRUE))
|
||||
organisms <- organisms |>
|
||||
filter(!code %in% subspp$code) |>
|
||||
bind_rows(subspp) |>
|
||||
arrange(code)
|
||||
|
||||
# add the groups
|
||||
organisms <- organisms |>
|
||||
bind_rows(tibble(
|
||||
code = organisms |> filter(!is.na(group)) |> pull(group) |> unique(),
|
||||
group = NA,
|
||||
mo = organisms |> filter(!is.na(group)) |> pull(group) |> unique() |> as.mo(keep_synonyms = TRUE),
|
||||
name = mo_name(mo, keep_synonyms = TRUE)
|
||||
)) |>
|
||||
arrange(code, group) |>
|
||||
select(-group) |>
|
||||
organisms <- organisms |>
|
||||
bind_rows(tibble(code = organisms |> filter(!is.na(group)) |> pull(group) |> unique(),
|
||||
group = NA,
|
||||
mo = organisms |> filter(!is.na(group)) |> pull(group) |> unique() |> as.mo(keep_synonyms = TRUE),
|
||||
name = mo_name(mo, keep_synonyms = TRUE))) |>
|
||||
arrange(code, group) |>
|
||||
select(-group) |>
|
||||
distinct()
|
||||
# no XXX
|
||||
organisms <- organisms |> filter(code != "XXX")
|
||||
@@ -169,7 +153,7 @@ organisms <- organisms |> filter(code != "XXX")
|
||||
# 2025-04-20 still the case
|
||||
# 2026-03-27 still the case, but fixed using `existing_codes` above
|
||||
organisms |> filter(code == "SGM")
|
||||
# organisms <- organisms |>
|
||||
# organisms <- organisms |>
|
||||
# filter(!(code == "SGM" & name %like% "Streptococcus"))
|
||||
# this must be empty:
|
||||
organisms$code[organisms$code |> duplicated()]
|
||||
@@ -181,12 +165,12 @@ saveRDS(organisms, "data-raw/organisms.rds", version = 2)
|
||||
#---
|
||||
|
||||
# update microorganisms.codes with the latest WHONET codes
|
||||
microorganisms.codes2 <- microorganisms.codes |>
|
||||
microorganisms.codes2 <- microorganisms.codes |>
|
||||
# remove all old WHONET codes, whether we (in the end) keep them or not
|
||||
filter(!toupper(code) %in% toupper(organisms$code)) |>
|
||||
filter(!toupper(code) %in% toupper(organisms$code)) |>
|
||||
# and add the new ones
|
||||
bind_rows(organisms |> select(code, mo)) |>
|
||||
arrange(code) |>
|
||||
bind_rows(organisms |> select(code, mo)) |>
|
||||
arrange(code) |>
|
||||
distinct(code, .keep_all = TRUE)
|
||||
# new codes:
|
||||
microorganisms.codes2$code[which(!microorganisms.codes2$code %in% microorganisms.codes$code)]
|
||||
@@ -230,53 +214,47 @@ devtools::load_all()
|
||||
|
||||
# now that we have the correct MO codes, get the breakpoints and convert them
|
||||
|
||||
whonet_breakpoints_raw |>
|
||||
count(GUIDELINES, BREAKPOINT_TYPE) |>
|
||||
pivot_wider(names_from = BREAKPOINT_TYPE, values_from = n) |>
|
||||
whonet_breakpoints_raw |>
|
||||
count(GUIDELINES, BREAKPOINT_TYPE) |>
|
||||
pivot_wider(names_from = BREAKPOINT_TYPE, values_from = n) |>
|
||||
janitor::adorn_totals(where = c("row", "col"))
|
||||
whonet_breakpoints_raw |>
|
||||
whonet_breakpoints_raw |>
|
||||
filter(YEAR == format(Sys.Date(), "%Y")) |>
|
||||
count(GUIDELINES, YEAR, BREAKPOINT_TYPE) |>
|
||||
pivot_wider(names_from = BREAKPOINT_TYPE, values_from = n) |>
|
||||
count(GUIDELINES, YEAR, BREAKPOINT_TYPE) |>
|
||||
pivot_wider(names_from = BREAKPOINT_TYPE, values_from = n) |>
|
||||
janitor::adorn_totals(where = c("row", "col"))
|
||||
# compared to current
|
||||
AMR::clinical_breakpoints |>
|
||||
count(GUIDELINES = gsub("[^a-zA-Z]", "", guideline), type) |>
|
||||
arrange(tolower(type)) |>
|
||||
pivot_wider(names_from = type, values_from = n) |>
|
||||
pivot_wider(names_from = type, values_from = n) |>
|
||||
as.data.frame() |>
|
||||
janitor::adorn_totals(where = c("row", "col"))
|
||||
|
||||
breakpoints <- whonet_breakpoints_raw |>
|
||||
mutate(code = toupper(ORGANISM_CODE)) |>
|
||||
left_join(bind_rows(
|
||||
microorganisms.codes |> filter(!code %in% c("ALL", "GEN")),
|
||||
# GEN (Generic) and ALL (All) are PK/PD codes
|
||||
data.frame(
|
||||
code = c("ALL", "GEN"),
|
||||
mo = rep(as.mo("UNKNOWN"), 2)
|
||||
)
|
||||
))
|
||||
left_join(bind_rows(microorganisms.codes |> filter(!code %in% c("ALL", "GEN")),
|
||||
# GEN (Generic) and ALL (All) are PK/PD codes
|
||||
data.frame(code = c("ALL", "GEN"),
|
||||
mo = rep(as.mo("UNKNOWN"), 2))))
|
||||
# these ones lack an MO name, they cannot be used:
|
||||
unknown <- breakpoints |>
|
||||
filter(is.na(mo)) |>
|
||||
pull(code) |>
|
||||
unique()
|
||||
breakpoints |>
|
||||
filter(code %in% unknown) |>
|
||||
breakpoints |>
|
||||
filter(code %in% unknown) |>
|
||||
count(GUIDELINES, YEAR, ORGANISM_CODE, BREAKPOINT_TYPE, sort = TRUE)
|
||||
# 2025-04-20: these codes are currently: cps, fso. No clue (are not in MO list of WHONET), and they are only ECOFFs, so remove them:
|
||||
breakpoints <- breakpoints |>
|
||||
breakpoints <- breakpoints |>
|
||||
filter(!is.na(mo))
|
||||
|
||||
# and these ones have unknown antibiotics according to WHONET itself:
|
||||
breakpoints |>
|
||||
filter(!WHONET_ABX_CODE %in% whonet_antibiotics_raw$WHONET_ABX_CODE) |>
|
||||
breakpoints |>
|
||||
filter(!WHONET_ABX_CODE %in% whonet_antibiotics_raw$WHONET_ABX_CODE) |>
|
||||
count(GUIDELINES, WHONET_ABX_CODE) |>
|
||||
mutate(
|
||||
ab = as.ab(WHONET_ABX_CODE, fast_mode = TRUE),
|
||||
ab_name = ab_name(ab)
|
||||
)
|
||||
mutate(ab = as.ab(WHONET_ABX_CODE, fast_mode = TRUE),
|
||||
ab_name = ab_name(ab))
|
||||
# 2025-04-20: these codes are currently: CFC, ROX, FIX, and N/A. All have the right replacements in `antimicrobials`, so we can safely use as.ab() later on
|
||||
# the NAs are for M. tuberculosis, they are empty breakpoints
|
||||
breakpoints <- breakpoints |>
|
||||
@@ -286,7 +264,7 @@ breakpoints <- breakpoints |>
|
||||
## Build new breakpoints table ----
|
||||
|
||||
breakpoints_new <- breakpoints |>
|
||||
filter(!is.na(WHONET_ABX_CODE)) |>
|
||||
filter(!is.na(WHONET_ABX_CODE)) |>
|
||||
transmute(
|
||||
guideline = paste(GUIDELINES, YEAR),
|
||||
type = ifelse(BREAKPOINT_TYPE == "ECOFF", "ECOFF", tolower(BREAKPOINT_TYPE)),
|
||||
@@ -323,26 +301,22 @@ breakpoints_new <- breakpoints |>
|
||||
distinct(guideline, type, host, ab, mo, method, site, breakpoint_S, .keep_all = TRUE)
|
||||
|
||||
# fix reference table names
|
||||
breakpoints_new |>
|
||||
filter(guideline %like% "EUCAST", is.na(ref_tbl)) |>
|
||||
View()
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
mutate(ref_tbl = case_when(
|
||||
is.na(ref_tbl) & guideline %like% "EUCAST 202" ~ lead(ref_tbl),
|
||||
is.na(ref_tbl) ~ "Unknown",
|
||||
TRUE ~ ref_tbl
|
||||
))
|
||||
breakpoints_new |> filter(guideline %like% "EUCAST", is.na(ref_tbl)) |> View()
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
mutate(ref_tbl = case_when(is.na(ref_tbl) & guideline %like% "EUCAST 202" ~ lead(ref_tbl),
|
||||
is.na(ref_tbl) ~ "Unknown",
|
||||
TRUE ~ ref_tbl))
|
||||
|
||||
# clean disk zones
|
||||
breakpoints_new[which(breakpoints_new$method == "DISK"), "breakpoint_S"] <- as.double(as.disk(breakpoints_new[which(breakpoints_new$method == "DISK"), "breakpoint_S", drop = TRUE]))
|
||||
breakpoints_new[which(breakpoints_new$method == "DISK"), "breakpoint_R"] <- as.double(as.disk(breakpoints_new[which(breakpoints_new$method == "DISK"), "breakpoint_R", drop = TRUE]))
|
||||
|
||||
# regarding animal breakpoints, CLSI has adults and foals for horses, but only for amikacin - only keep adult horses
|
||||
breakpoints_new |>
|
||||
breakpoints_new |>
|
||||
filter(host %like% "foal") |>
|
||||
count(guideline, host, ab)
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
filter(host %unlike% "foal") |>
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
filter(host %unlike% "foal") |>
|
||||
mutate(host = ifelse(host %like% "horse", "horse", host))
|
||||
|
||||
# FIXES FOR WHONET ERRORS ----
|
||||
@@ -350,12 +324,8 @@ m <- unique(as.double(as.mic(levels(as.mic(1)))))
|
||||
|
||||
# WHONET has no >1024 but instead uses 1025, 513, and 129, so as.mic() cannot be used to clean.
|
||||
# instead, raise these one higher valid MIC factor level:
|
||||
breakpoints_new |>
|
||||
filter(method == "MIC" & (!breakpoint_S %in% c(m, NA))) |>
|
||||
distinct(breakpoint_S)
|
||||
breakpoints_new |>
|
||||
filter(method == "MIC" & (!breakpoint_R %in% c(m, NA))) |>
|
||||
distinct(breakpoint_R)
|
||||
breakpoints_new |> filter(method == "MIC" & (!breakpoint_S %in% c(m, NA))) |> distinct(breakpoint_S)
|
||||
breakpoints_new |> filter(method == "MIC" & (!breakpoint_R %in% c(m, NA))) |> distinct(breakpoint_R)
|
||||
breakpoints_new[which(breakpoints_new$breakpoint_R == 129), "breakpoint_R"] <- m[which(m == 128) + 1]
|
||||
breakpoints_new[which(breakpoints_new$breakpoint_R == 257), "breakpoint_R"] <- m[which(m == 256) + 1]
|
||||
breakpoints_new[which(breakpoints_new$breakpoint_R == 513), "breakpoint_R"] <- m[which(m == 512) + 1]
|
||||
@@ -383,12 +353,12 @@ breakpoints_new$mo[breakpoints_new$guideline %like% "EUCAST" & breakpoints_new$m
|
||||
breakpoints_new |>
|
||||
filter(method == "MIC" & guideline %like% "EUCAST" & mo %like% as.mo("B_HMPHL")) |>
|
||||
count(guideline, mo)
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
bind_rows(
|
||||
breakpoints_new |>
|
||||
filter(guideline %like% "EUCAST", mo == "B_HMPHL_INFL") |>
|
||||
filter(guideline %like% "EUCAST", mo == "B_HMPHL_INFL") |>
|
||||
mutate(mo = as.mo("B_HMPHL_PRNF"))
|
||||
) |>
|
||||
) |>
|
||||
arrange(desc(guideline), mo, ab, type, host, method) |>
|
||||
distinct()
|
||||
# Achromobacter denitrificans is in WHONET included in their A. xylosoxidans table, must be removed
|
||||
@@ -417,9 +387,7 @@ breakpoints_new <- breakpoints_new |> filter(!wrong)
|
||||
# 2025-04-20/ fixed now
|
||||
|
||||
# WHONET sets for EUCAST 2026 TMP breakpoints for all Klebsiella, but this is now only for non-aerogenes species
|
||||
kleb_spp <- microorganisms |>
|
||||
filter(rank == "species", genus == "Klebsiella", !species %in% c("", "aerogenes")) |>
|
||||
pull(mo)
|
||||
kleb_spp <- microorganisms |> filter(rank == "species", genus == "Klebsiella", !species %in% c("", "aerogenes")) |> pull(mo)
|
||||
kleb_tmp_mic <- breakpoints_new |>
|
||||
filter(guideline == "EUCAST 2026", method == "MIC", ab == "TMP", mo == as.mo("Klebsiella")) |>
|
||||
uncount(length(kleb_spp)) |>
|
||||
@@ -430,10 +398,8 @@ kleb_tmp_disk <- breakpoints_new |>
|
||||
mutate(mo = kleb_spp)
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
filter(!(guideline == "EUCAST 2026" & method == "MIC" & ab == "TMP" & mo == as.mo("Klebsiella"))) |>
|
||||
bind_rows(
|
||||
kleb_tmp_mic,
|
||||
kleb_tmp_disk
|
||||
)
|
||||
bind_rows(kleb_tmp_mic,
|
||||
kleb_tmp_disk)
|
||||
|
||||
# WHONET contains wrong EUCAST breakpoints for enterococci/SXT: disk should be 23/23, not 21/50, and MIC should be 1/1, not 0.032/1
|
||||
# applies to all previous years, since v11 (2011)
|
||||
@@ -475,14 +441,14 @@ breakpoints_new <- breakpoints_new |>
|
||||
|
||||
|
||||
# check the strange duplicates
|
||||
breakpoints_new |>
|
||||
breakpoints_new |>
|
||||
mutate(id = paste(guideline, type, host, method, site, mo, ab, uti)) %>%
|
||||
filter(id %in% .$id[which(duplicated(id))]) |>
|
||||
filter(id %in% .$id[which(duplicated(id))]) |>
|
||||
arrange(desc(guideline)) |>
|
||||
View()
|
||||
# 2024-06-19/ mostly ECOFFs, but there's no explanation in the whonet_breakpoints_raw df, we have to remove duplicates
|
||||
# 2025-04-20/ same, most important one seems M. tuberculosis in CLSI (also in 2025)
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
distinct(guideline, type, host, method, site, mo, ab, uti, .keep_all = TRUE)
|
||||
|
||||
|
||||
@@ -503,7 +469,7 @@ dim(clinical_breakpoints)
|
||||
# SAVE TO PACKAGE ----
|
||||
|
||||
# determine rank again now that some changes were made on taxonomic level (genus -> species)
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
breakpoints_new <- breakpoints_new |>
|
||||
mutate(rank_index = case_when(
|
||||
mo_rank(mo, keep_synonyms = TRUE) %like% "(infra|sub)" ~ 1,
|
||||
mo_rank(mo, keep_synonyms = TRUE) == "species" ~ 2,
|
||||
|
||||
@@ -122,8 +122,8 @@ get_author_year <- function(ref) {
|
||||
authors <- gsub("[A-Z-][a-z-]?[.]", "", authors, ignore.case = FALSE)
|
||||
# remove trailing and leading spaces
|
||||
authors <- trimws(authors)
|
||||
# strip emend. and everything after it to retain the combination authority
|
||||
authors <- gsub(" ?emend[.]?.*", "", authors)
|
||||
# keep only the part after last 'emend.' to get the latest authors
|
||||
authors <- gsub(".*emend[.] ?", "", authors)
|
||||
# only keep first author and replace all others by 'et al'
|
||||
authors <- gsub("(,| and| et| &| ex| emend\\.?) .*", " et al.", authors)
|
||||
# et al. always with ending dot
|
||||
@@ -649,9 +649,7 @@ taxonomy_mycobank <- taxonomy_mycobank %>%
|
||||
arrange(fullname)
|
||||
|
||||
taxonomy_mycobank %>% count(rank, sort = TRUE)
|
||||
taxonomy_mycobank %>%
|
||||
filter(rank %like% "#") %>%
|
||||
count(rank)
|
||||
taxonomy_mycobank %>% filter(rank %like% "#") %>% count(rank)
|
||||
|
||||
taxonomy_mycobank3 <- taxonomy_mycobank
|
||||
|
||||
@@ -746,7 +744,7 @@ taxonomy_mycobank <- taxonomy_mycobank %>%
|
||||
tax_h,
|
||||
tax_i %in% taxonomy_mycobank$fullname[taxonomy_mycobank$rank == "genus"] ~
|
||||
tax_i,
|
||||
tax_j %in% taxonomy_mycobank$fullname[taxonomy_mycobank$rank == "genus"] ~
|
||||
tax_k %in% taxonomy_mycobank$fullname[taxonomy_mycobank$rank == "genus"] ~
|
||||
tax_j,
|
||||
tax_k %in% taxonomy_mycobank$fullname[taxonomy_mycobank$rank == "genus"] ~
|
||||
tax_k,
|
||||
@@ -2548,9 +2546,7 @@ taxonomy %>%
|
||||
arrange(mo) %>%
|
||||
View()
|
||||
# keep the firsts
|
||||
taxonomy <- taxonomy %>%
|
||||
arrange(mo) %>%
|
||||
distinct(mo, .keep_all = TRUE)
|
||||
taxonomy <- taxonomy %>% arrange(mo) %>% distinct(mo, .keep_all = TRUE)
|
||||
|
||||
# are fullnames unique?
|
||||
taxonomy %>%
|
||||
@@ -2858,135 +2854,6 @@ taxonomy <- taxonomy %>%
|
||||
relocate(oxygen_tolerance, .after = ref)
|
||||
|
||||
|
||||
# Add morphology ---------------------------------------------------------------------
|
||||
|
||||
# We will use the BacDive data base for this:
|
||||
# - go to https://bacdive.dsmz.de/advsearch
|
||||
# - filter 'Cell shape' on "*" and click Submit
|
||||
# - click on the 'Download table as CSV' button
|
||||
bacdive_shape <- vroom::vroom("data-raw/bacdive_shape.csv", skip = 2) %>%
|
||||
select(species, shape = `Cell shape`)
|
||||
bacdive_shape <- bacdive_shape %>%
|
||||
# fill in missing species from previous rows
|
||||
mutate(fullname = if_else(is.na(species), lag(species), species)) %>%
|
||||
filter(
|
||||
!is.na(species),
|
||||
!is.na(shape),
|
||||
species %unlike% "unclassified"
|
||||
) %>%
|
||||
select(-species)
|
||||
bacdive_shape <- bacdive_shape %>%
|
||||
# map raw BacDive values to a controlled vocabulary
|
||||
mutate(
|
||||
shape = case_when(
|
||||
shape %in% c("coccus-shaped", "sphere-shaped", "diplococcus-shaped") ~ "cocci",
|
||||
shape %in% c("oval-shaped", "ovoid-shaped") ~ "coccobacilli",
|
||||
shape %in% c("rod-shaped", "curved-shaped", "vibrio-shaped", "flask-shaped") ~ "rods",
|
||||
shape %in% c("spiral-shaped", "helical-shaped") ~ "spirilla",
|
||||
shape == "filament-shaped" ~ "filamentous",
|
||||
TRUE ~ NA_character_
|
||||
)
|
||||
) %>%
|
||||
filter(!is.na(shape)) %>%
|
||||
# now determine shape per species by majority vote
|
||||
group_by(fullname) %>%
|
||||
summarise(
|
||||
morphology = names(sort(table(shape), decreasing = TRUE))[1]
|
||||
)
|
||||
# now find all synonyms and copy them from their current taxonomic names
|
||||
synonyms_shape <- taxonomy %>%
|
||||
filter(status == "synonym") %>%
|
||||
transmute(
|
||||
mo,
|
||||
fullname_old = fullname,
|
||||
current = synonym_mo_to_accepted_mo(
|
||||
mo,
|
||||
fill_in_accepted = FALSE,
|
||||
dataset = taxonomy
|
||||
)
|
||||
) %>%
|
||||
filter(!is.na(current)) %>%
|
||||
mutate(fullname = taxonomy$fullname[match(current, taxonomy$mo)]) %>%
|
||||
left_join(bacdive_shape, by = "fullname") %>%
|
||||
filter(!is.na(morphology)) %>%
|
||||
select(fullname, morphology)
|
||||
|
||||
bacdive_shape <- bacdive_shape %>%
|
||||
bind_rows(synonyms_shape) %>%
|
||||
distinct()
|
||||
|
||||
bacdive_shape_genus <- bacdive_shape %>%
|
||||
mutate(
|
||||
shape_raw = morphology,
|
||||
genus = taxonomy$genus[match(fullname, taxonomy$fullname)]
|
||||
) %>%
|
||||
group_by(fullname = genus) %>%
|
||||
summarise(
|
||||
morphology = names(sort(table(shape_raw), decreasing = TRUE))[1]
|
||||
)
|
||||
bacdive_shape <- bacdive_shape %>%
|
||||
bind_rows(bacdive_shape_genus) %>%
|
||||
arrange(fullname)
|
||||
|
||||
bacdive_shape_other <- taxonomy %>%
|
||||
filter(
|
||||
kingdom == "Bacteria",
|
||||
rank == "species",
|
||||
!fullname %in% bacdive_shape$fullname,
|
||||
genus %in% bacdive_shape$fullname
|
||||
) %>%
|
||||
select(fullname, genus) %>%
|
||||
left_join(bacdive_shape, by = c("genus" = "fullname")) %>%
|
||||
mutate(
|
||||
morphology = paste("likely", morphology)
|
||||
) %>%
|
||||
select(fullname, morphology) %>%
|
||||
distinct(fullname, .keep_all = TRUE)
|
||||
|
||||
bacdive_shape <- bacdive_shape %>%
|
||||
bind_rows(bacdive_shape_other) %>%
|
||||
arrange(fullname) %>%
|
||||
distinct(fullname, .keep_all = TRUE)
|
||||
|
||||
taxonomy <- taxonomy %>%
|
||||
left_join(bacdive_shape, by = "fullname") %>%
|
||||
relocate(morphology, .after = oxygen_tolerance)
|
||||
|
||||
# Override: genera that are clinically established coccobacilli but where BacDive
|
||||
# majority vote yields "rods" due to observer disagreement on the rod/oval boundary.
|
||||
# These genera are universally reported as coccobacilli on Gram stain in clinical
|
||||
# microbiology practice.
|
||||
coccobacilli_genera <- c(
|
||||
"Acinetobacter", "Aggregatibacter", "Brucella",
|
||||
"Gardnerella", "Haemophilus", "Kingella",
|
||||
"Moraxella", "Pasteurella"
|
||||
)
|
||||
taxonomy <- taxonomy %>%
|
||||
mutate(
|
||||
morphology = case_when(
|
||||
genus %in% coccobacilli_genera & is.na(morphology) ~ "likely coccobacilli",
|
||||
genus %in% coccobacilli_genera &
|
||||
morphology %in% c("rods", "cocci") ~ "coccobacilli",
|
||||
genus %in% coccobacilli_genera &
|
||||
morphology %in% c("likely rods", "likely cocci") ~ "likely coccobacilli",
|
||||
TRUE ~ morphology
|
||||
)
|
||||
)
|
||||
|
||||
# Spirochaetes: the entire phylum is spirochaete by definition, fill in where missing
|
||||
taxonomy <- taxonomy %>%
|
||||
mutate(
|
||||
morphology = case_when(
|
||||
phylum %in% c("Spirochaetota", "Spirochaetes") & is.na(morphology) ~ "likely spirilla",
|
||||
phylum %in% c("Spirochaetota", "Spirochaetes") &
|
||||
morphology %in% c("rods", "likely rods") ~ "spirilla",
|
||||
TRUE ~ morphology
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
# Restore 'synonym' microorganisms to 'accepted' --------------------------------------------------
|
||||
|
||||
# If there are some synonyms that need to be corrected to 'accepted', you can do that here.
|
||||
@@ -3130,9 +2997,7 @@ taxonomy$rank[which(taxonomy$fullname %like% "unknown")] <- "(unknown rank)"
|
||||
|
||||
# this happened in early 2025, check that MO codes do not have repeated elements
|
||||
# fixed it then like this: microorganisms$mo <- gsub("B_SCLLM_CNNM_LNSM_LNSM_LNSM_LNSM", "B_SCLLM_CNNM", microorganisms$mo)
|
||||
taxonomy |>
|
||||
filter(mo %like% "_.*_.*_.*_") |>
|
||||
View()
|
||||
taxonomy |> filter(mo %like% "_.*_.*_.*_") |> View()
|
||||
|
||||
|
||||
fix_old_mos <- function(dataset) {
|
||||
@@ -3220,9 +3085,7 @@ microorganisms <- taxonomy
|
||||
|
||||
# set class <mo>
|
||||
class(microorganisms$mo) <- c("mo", "character")
|
||||
microorganisms <- microorganisms %>%
|
||||
arrange(fullname) %>%
|
||||
df_remove_nonASCII()
|
||||
microorganisms <- microorganisms %>% arrange(fullname) %>% df_remove_nonASCII()
|
||||
usethis::use_data(
|
||||
microorganisms,
|
||||
overwrite = TRUE,
|
||||
|
||||
@@ -59,101 +59,72 @@ whonet_organisms <- whonet_organisms %>%
|
||||
mutate(
|
||||
# this one was called Issatchenkia orientalis, but it should be:
|
||||
ORGANISM = if_else(ORGANISM_CODE == "ckr", "Candida krusei", ORGANISM)
|
||||
) %>%
|
||||
) %>%
|
||||
# try to match on GBIF identifier
|
||||
left_join(microorganisms %>% distinct(mo, gbif, status) %>% filter(!is.na(gbif)), by = c("GBIF_TAXON_ID" = "gbif")) %>%
|
||||
left_join(microorganisms %>% distinct(mo, gbif, status) %>% filter(!is.na(gbif)), by = c("GBIF_TAXON_ID" = "gbif")) %>%
|
||||
# remove duplicates
|
||||
arrange(ORGANISM_CODE, GBIF_TAXON_ID, status) %>%
|
||||
distinct(ORGANISM_CODE, .keep_all = TRUE) %>%
|
||||
distinct(ORGANISM_CODE, .keep_all = TRUE) %>%
|
||||
# add Enterobacterales, which is a subkingdom code in their data
|
||||
bind_rows(data.frame(ORGANISM_CODE = "ebc", ORGANISM = "Enterobacterales", mo = as.mo("Enterobacterales"))) %>%
|
||||
bind_rows(data.frame(ORGANISM_CODE = "ebc", ORGANISM = "Enterobacterales", mo = as.mo("Enterobacterales"))) %>%
|
||||
arrange(ORGANISM)
|
||||
|
||||
# check non-existing species groups in the microorganisms table
|
||||
whonet_organisms %>%
|
||||
filter(!is.na(SPECIES_GROUP)) %>%
|
||||
group_by(SPECIES_GROUP) %>%
|
||||
summarise(
|
||||
complex = ORGANISM[ORGANISM %like% " (group|complex)"][1],
|
||||
organisms = paste0(n(), ": ", paste(sort(unique(ORGANISM)), collapse = ", "))
|
||||
) %>%
|
||||
summarise(complex = ORGANISM[ORGANISM %like% " (group|complex)"][1],
|
||||
organisms = paste0(n(), ": ", paste(sort(unique(ORGANISM)), collapse = ", "))) %>%
|
||||
filter(!SPECIES_GROUP %in% microorganisms.codes$code)
|
||||
|
||||
# create the species group data set ----
|
||||
microorganisms.groups <- whonet_organisms %>%
|
||||
# these will not be translated well
|
||||
filter(!ORGANISM %in% c(
|
||||
"Trueperella pyogenes-like bacteria",
|
||||
"Mycobacterium suricattae",
|
||||
"Mycobacterium canetti"
|
||||
)) %>%
|
||||
filter(!ORGANISM %in% c("Trueperella pyogenes-like bacteria",
|
||||
"Mycobacterium suricattae",
|
||||
"Mycobacterium canetti")) %>%
|
||||
filter(!is.na(SPECIES_GROUP), SPECIES_GROUP != ORGANISM_CODE) %>%
|
||||
transmute(
|
||||
mo_group = as.mo(SPECIES_GROUP),
|
||||
mo = ifelse(is.na(mo),
|
||||
as.character(as.mo(ORGANISM, keep_synonyms = TRUE, minimum_matching_score = 0)),
|
||||
mo
|
||||
)
|
||||
) %>%
|
||||
transmute(mo_group = as.mo(SPECIES_GROUP),
|
||||
mo = ifelse(is.na(mo),
|
||||
as.character(as.mo(ORGANISM, keep_synonyms = TRUE, minimum_matching_score = 0)),
|
||||
mo)) %>%
|
||||
# add our own CoNS and CoPS, WHONET does not strictly follow Becker et al. (2014, 2019, 2020)
|
||||
filter(mo_group != as.mo("CoNS")) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("CoNS"), mo = MO_CONS)) %>%
|
||||
filter(mo_group != as.mo("CoPS")) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("CoPS"), mo = MO_COPS)) %>%
|
||||
filter(mo_group != as.mo("CoNS")) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("CoNS"), mo = MO_CONS)) %>%
|
||||
filter(mo_group != as.mo("CoPS")) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("CoPS"), mo = MO_COPS)) %>%
|
||||
# at least all our Lancefield-grouped streptococci must be in the beta-haemolytic group:
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Beta-haemolytic streptococcus"),
|
||||
mo = c(
|
||||
MO_LANCEFIELD,
|
||||
microorganisms %>% filter(fullname %like% "^Streptococcus Group") %>% pull(mo)
|
||||
)
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Beta-haemolytic streptococcus"),
|
||||
mo = c(MO_LANCEFIELD,
|
||||
microorganisms %>% filter(fullname %like% "^Streptococcus Group") %>% pull(mo)))) %>%
|
||||
# and per Streptococcus group as well:
|
||||
# group A - S. pyogenes
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Streptococcus Group A"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_PYGN(_|$)")]
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Streptococcus Group A"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_PYGN(_|$)")])) %>%
|
||||
# group B - S. agalactiae
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Streptococcus Group B"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_AGLC(_|$)")]
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Streptococcus Group B"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_AGLC(_|$)")])) %>%
|
||||
# group C - all subspecies within S. dysgalactiae and S. equi (such as S. equi zooepidemicus)
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Streptococcus Group C"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_(DYSG|EQUI)(_|$)")]
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Streptococcus Group C"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_(DYSG|EQUI)(_|$)")])) %>%
|
||||
# group F - Milleri group == S. anginosus group, which incl. S. anginosus, S. constellatus, S. intermedius
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Streptococcus Group F"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_(ANGN|CNST|INTR)(_|$)")]
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Streptococcus Group F"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_(ANGN|CNST|INTR)(_|$)")])) %>%
|
||||
# group G - S. dysgalactiae and S. canis (though dysgalactiae is also group C and will be matched there)
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Streptococcus Group G"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_(DYSG|CANS)(_|$)")]
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Streptococcus Group G"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_(DYSG|CANS)(_|$)")])) %>%
|
||||
# group H - S. sanguinis
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Streptococcus Group H"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_SNGN(_|$)")]
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Streptococcus Group H"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_SNGN(_|$)")])) %>%
|
||||
# group K - S. salivarius, incl. S. salivarius salivariuss and S. salivarius thermophilus
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Streptococcus Group K"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_SLVR(_|$)")]
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Streptococcus Group K"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_SLVR(_|$)")])) %>%
|
||||
# group L - only S. dysgalactiae
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Streptococcus Group L"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_DYSG(_|$)")]
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Streptococcus Group L"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_DYSG(_|$)")])) %>%
|
||||
# and for EUCAST: Strep group A, B, C, G
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("Streptococcus Group A, B, C, G"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_(PYGN|AGLC|DYSG|EQUI|CANS|GRPA|GRPB|GRPC|GRPG)(_|$)")]
|
||||
)) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("Streptococcus Group A, B, C, G"),
|
||||
mo = microorganisms$mo[which(microorganisms$mo %like% "^B_STRPT_(PYGN|AGLC|DYSG|EQUI|CANS|GRPA|GRPB|GRPC|GRPG)(_|$)")])) %>%
|
||||
# HACEK is:
|
||||
# - Haemophilus species
|
||||
# - Aggregatibacter species
|
||||
@@ -162,46 +133,38 @@ microorganisms.groups <- whonet_organisms %>%
|
||||
# - Kingella species
|
||||
# - and previously Actinobacillus actinomycetemcomitans
|
||||
# see https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3656887/
|
||||
filter(mo_group != as.mo("HACEK")) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("HACEK"), mo = microorganisms %>% filter(genus == "Haemophilus") %>% pull(mo))) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("HACEK"), mo = microorganisms %>% filter(genus == "Aggregatibacter") %>% pull(mo))) %>%
|
||||
filter(mo_group != as.mo("HACEK")) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("HACEK"), mo = microorganisms %>% filter(genus == "Haemophilus") %>% pull(mo))) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("HACEK"), mo = microorganisms %>% filter(genus == "Aggregatibacter") %>% pull(mo))) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("HACEK"), mo = as.mo("Cardiobacterium hominis", keep_synonyms = TRUE))) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("HACEK"), mo = as.mo("Eikenella corrodens", keep_synonyms = TRUE))) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("HACEK"), mo = microorganisms %>% filter(genus == "Kingella") %>% pull(mo))) %>%
|
||||
bind_rows(tibble(mo_group = as.mo("HACEK"), mo = as.mo("Actinobacillus actinomycetemcomitans", keep_synonyms = TRUE))) %>%
|
||||
# Citrobacter freundii complex in the NCBI Taxonomy Browser:
|
||||
# https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?id=1344959
|
||||
filter(mo_group != "B_CTRBC_FRND-C") %>%
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("B_CTRBC_FRND-C"),
|
||||
mo = paste("Citrobacter", c("freundii", "braakii", "gillenii", "murliniae", "portucalensis", "sedlakii", "werkmanii", "youngae")) %>% as.mo(keep_synonyms = TRUE)
|
||||
)) %>%
|
||||
filter(mo_group != "B_CTRBC_FRND-C") %>%
|
||||
bind_rows(tibble(mo_group = as.mo("B_CTRBC_FRND-C"),
|
||||
mo = paste("Citrobacter", c("freundii", "braakii", "gillenii", "murliniae", "portucalensis", "sedlakii", "werkmanii", "youngae")) %>% as.mo(keep_synonyms = TRUE))) %>%
|
||||
# Klebsiella pneumoniae complex
|
||||
filter(mo_group != "B_KLBSL_PNMN-C") %>%
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("B_KLBSL_PNMN-C"),
|
||||
mo = paste("Klebsiella", c("africana", "pneumoniae", "quasipneumoniae", "quasivariicola", "variicola")) %>% as.mo(keep_synonyms = TRUE)
|
||||
)) %>%
|
||||
filter(mo_group != "B_KLBSL_PNMN-C") %>%
|
||||
bind_rows(tibble(mo_group = as.mo("B_KLBSL_PNMN-C"),
|
||||
mo = paste("Klebsiella", c("africana", "pneumoniae", "quasipneumoniae", "quasivariicola", "variicola")) %>% as.mo(keep_synonyms = TRUE))) %>%
|
||||
# Yersinia pseudotuberculosis complex in the NCBI Taxonomy Browser:
|
||||
# https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?id=1649845
|
||||
filter(mo_group != "B_YERSN_PSDT-C") %>%
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("B_YERSN_PSDT-C"),
|
||||
mo = paste("Yersinia", c("pseudotuberculosis", "pestis", "similis", "wautersii")) %>% as.mo(keep_synonyms = TRUE)
|
||||
)) %>%
|
||||
filter(mo_group != "B_YERSN_PSDT-C") %>%
|
||||
bind_rows(tibble(mo_group = as.mo("B_YERSN_PSDT-C"),
|
||||
mo = paste("Yersinia", c("pseudotuberculosis", "pestis", "similis", "wautersii")) %>% as.mo(keep_synonyms = TRUE))) %>%
|
||||
# RGM are Rapidly-growing Mycobacteria, see https://pubmed.ncbi.nlm.nih.gov/28084211/
|
||||
filter(mo_group != "B_MYCBC_RGM") %>%
|
||||
bind_rows(tibble(
|
||||
mo_group = as.mo("B_MYCBC_RGM"),
|
||||
mo = paste("Mycobacterium", c("abscessus abscessus", "abscessus bolletii", "abscessus massiliense", "agri", "aichiense", "algericum", "alvei", "anyangense", "arabiense", "aromaticivorans", "aubagnense", "aubagnense", "aurum", "austroafricanum", "bacteremicum", "boenickei", "bourgelatii", "brisbanense", "brumae", "canariasense", "celeriflavum", "chelonae", "chitae", "chlorophenolicum", "chubuense", "confluentis", "cosmeticum", "crocinum", "diernhoferi", "duvalii", "elephantis", "fallax", "flavescens", "fluoranthenivorans", "fortuitum", "franklinii", "frederiksbergense", "gadium", "gilvum", "goodii", "hassiacum", "hippocampi", "hodleri", "holsaticum", "houstonense", "immunogenum", "insubricum", "iranicum", "komossense", "litorale", "llatzerense", "madagascariense", "mageritense", "monacense", "moriokaense", "mucogenicum", "mucogenicum", "murale", "neoaurum", "neworleansense", "novocastrense", "obuense", "pallens", "parafortuitum", "peregrinum", "phlei", "phocaicum", "phocaicum", "porcinum", "poriferae", "psychrotolerans", "pyrenivorans", "rhodesiae", "rufum", "rutilum", "salmoniphilum", "sediminis", "senegalense", "septicum", "setense", "smegmatis", "sphagni", "thermoresistibile", "tokaiense", "vaccae", "vanbaalenii", "wolinskyi")) %>% as.mo(keep_synonyms = TRUE)
|
||||
))
|
||||
filter(mo_group != "B_MYCBC_RGM") %>%
|
||||
bind_rows(tibble(mo_group = as.mo("B_MYCBC_RGM"),
|
||||
mo = paste("Mycobacterium", c( "abscessus abscessus", "abscessus bolletii", "abscessus massiliense", "agri", "aichiense", "algericum", "alvei", "anyangense", "arabiense", "aromaticivorans", "aubagnense", "aubagnense", "aurum", "austroafricanum", "bacteremicum", "boenickei", "bourgelatii", "brisbanense", "brumae", "canariasense", "celeriflavum", "chelonae", "chitae", "chlorophenolicum", "chubuense", "confluentis", "cosmeticum", "crocinum", "diernhoferi", "duvalii", "elephantis", "fallax", "flavescens", "fluoranthenivorans", "fortuitum", "franklinii", "frederiksbergense", "gadium", "gilvum", "goodii", "hassiacum", "hippocampi", "hodleri", "holsaticum", "houstonense", "immunogenum", "insubricum", "iranicum", "komossense", "litorale", "llatzerense", "madagascariense", "mageritense", "monacense", "moriokaense", "mucogenicum", "mucogenicum", "murale", "neoaurum", "neworleansense", "novocastrense", "obuense", "pallens", "parafortuitum", "peregrinum", "phlei", "phocaicum", "phocaicum", "porcinum", "poriferae", "psychrotolerans", "pyrenivorans", "rhodesiae", "rufum", "rutilum", "salmoniphilum", "sediminis", "senegalense", "septicum", "setense", "smegmatis", "sphagni", "thermoresistibile", "tokaiense", "vaccae", "vanbaalenii", "wolinskyi")) %>% as.mo(keep_synonyms = TRUE)))
|
||||
|
||||
# add subspecies to all species
|
||||
for (group in unique(microorganisms.groups$mo_group)) {
|
||||
spp <- microorganisms.groups %>%
|
||||
filter(mo_group == group & mo_rank(mo, keep_synonyms = TRUE) == "species") %>%
|
||||
pull(mo) %>%
|
||||
paste0(collapse = "|") %>%
|
||||
filter(mo_group == group & mo_rank(mo, keep_synonyms = TRUE) == "species") %>%
|
||||
pull(mo) %>%
|
||||
paste0(collapse = "|") %>%
|
||||
paste0("^(", ., ")")
|
||||
mos <- microorganisms %>%
|
||||
filter(mo %like% spp & rank == "subspecies") %>%
|
||||
@@ -212,11 +175,9 @@ for (group in unique(microorganisms.groups$mo_group)) {
|
||||
|
||||
# add full names, arrange and clean
|
||||
microorganisms.groups <- microorganisms.groups %>%
|
||||
mutate(
|
||||
mo_group_name = mo_name(mo_group, keep_synonyms = TRUE, language = NULL),
|
||||
mo_name = mo_name(mo, keep_synonyms = TRUE, language = NULL)
|
||||
) %>%
|
||||
arrange(mo_group_name, mo_name) %>%
|
||||
mutate(mo_group_name = mo_name(mo_group, keep_synonyms = TRUE, language = NULL),
|
||||
mo_name = mo_name(mo, keep_synonyms = TRUE, language = NULL)) %>%
|
||||
arrange(mo_group_name, mo_name) %>%
|
||||
filter(mo_group != mo) %>%
|
||||
distinct() %>%
|
||||
dataset_UTF8_to_ASCII()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -68,11 +68,9 @@ new_ab <- complete_tbl |>
|
||||
) |>
|
||||
mutate(name = paste0(substr(toupper(name), 1, 1), substr(name, 2, 999))) |>
|
||||
mutate(name = gsub(" and ", "/", name)) |>
|
||||
filter(
|
||||
name %unlike% "^Combinations",
|
||||
name %unlike% "/beta[-]lactamase inhibitor",
|
||||
name %unlike% "combinations"
|
||||
) |>
|
||||
filter(name %unlike% "^Combinations",
|
||||
name %unlike% "/beta[-]lactamase inhibitor",
|
||||
name %unlike% "combinations") |>
|
||||
arrange(name)
|
||||
|
||||
new_atcs <- new_ab |>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
990cbdfa55a1c2340aecfa67e8ac84d6
|
||||
2af32dd70120441a2c041b74b374c8a1
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
# Steps to reproduce:
|
||||
# 1. Create a fake account at https://loinc.org (sad you have to create one...)
|
||||
# 2. Download the CSV from https://loinc.org/download/loinc-complete/
|
||||
# 2. Download the CSV from https://loinc.org/download/loinc-complete/
|
||||
# 3. Read file LoincTable/Loinc.csv
|
||||
loinc_df <- read.csv("data-raw/Loinc.csv",
|
||||
row.names = NULL,
|
||||
@@ -47,7 +47,7 @@ loinc_df %>%
|
||||
filter(COMPONENT %like% "ampicillin|fluconazol|meropenem") %>%
|
||||
count(CLASS, sort = TRUE)
|
||||
loinc_df <- loinc_df %>%
|
||||
filter(CLASS %in% c("DRUG/TOX", "ABXBACT")) %>%
|
||||
filter(CLASS %in% c("DRUG/TOX", "ABXBACT")) %>%
|
||||
mutate(name = generalise_antibiotic_name(COMPONENT), .before = 1)
|
||||
|
||||
# antimicrobials
|
||||
|
||||
@@ -1,470 +1,470 @@
|
||||
codes <- tibble::tribble(
|
||||
~code, ~name,
|
||||
"ABT773", "Abbott 773",
|
||||
"AESCUL", "Aesculin",
|
||||
"AGMATI", "Agmatine",
|
||||
"AMDPEN", "Amidinopenicillin subclass",
|
||||
"AMICYC", "Aminocyclitol class",
|
||||
"AMIFLO", "Amifloxacin",
|
||||
"AMIGLY", "Aminoglycoside class",
|
||||
"AMIKAC", "Amikacin",
|
||||
"AMIPEN", "Aminopenicillin subclass",
|
||||
"AMOCL2", "Amoxicillin/ Clav.Acid */2",
|
||||
"AMOCL4", "Amoxicillin/ Clav. Acid 4:1",
|
||||
"AMOCLA", "Amoxicillin/ Clavulanic Acid",
|
||||
"AMOXIC", "Amoxicillin",
|
||||
"AMP100", "Ampicillin 100 ug/ml",
|
||||
"AMP200", "Ampicillin 200 ug/ml",
|
||||
"AMPHOT", "Amphotericin B",
|
||||
"AMPICI", "Ampicillin",
|
||||
"AMPSUL", "Ampicillin/ Sulbactam",
|
||||
"ANIDUL", "Anidulafungin",
|
||||
"ANSAMY", "Rifabutin",
|
||||
"ANSMYC", "Ansamycin class",
|
||||
"APALCI", "Apalcillin",
|
||||
"APOXIC", "Apoxicillin",
|
||||
"APRAMY", "Apramycin",
|
||||
"ARABIN", "Arabinose",
|
||||
"ARABIT", "Arabitol",
|
||||
"ARBEKA", "Arbekacin",
|
||||
"ARGINI", "Arginine",
|
||||
"ASPOXI", "Aspoxicillin",
|
||||
"ASTROM", "Astromycin",
|
||||
"AVILAM", "Avilamycin",
|
||||
"AZD256", "AZD2563",
|
||||
"AZITHR", "Azithromycin",
|
||||
"AZLOCI", "Azlocillin",
|
||||
"AZT1", "Aztreonam 1 ug/ml",
|
||||
"AZTREO", "Aztreonam",
|
||||
"BACAMP", "Bacampicillin",
|
||||
"BACITR", "Bacitracin",
|
||||
"BAMMYC", "Bambermycin class",
|
||||
"BAY12", "BAY12-8039",
|
||||
"BERBER", "Berberine",
|
||||
"BESIFL", "Besifloxacin",
|
||||
"BETA", "Beta-lactamase",
|
||||
"B", "HAEM Beta-haemolysis",
|
||||
"BIAPEN", "Biapenem (L-627)",
|
||||
"BLACT", "Beta-lactam class",
|
||||
"BLINHB", "Beta-lactam Inhibitor class",
|
||||
"B", "MGLU B-Methyl Glucoside",
|
||||
"CAPREO", "Capreomycin",
|
||||
"CAPRYL", "Caprylic Acid",
|
||||
"CARBAD", "Carbadox",
|
||||
"CARBAP", "Carbapenem class",
|
||||
"CARBEN", "Carbenicillin",
|
||||
"CARPEN", "Carboxypenicillin subclass",
|
||||
"CASPOF", "Caspofungin",
|
||||
"CATALA", "Catalase",
|
||||
"CCARB", "Carbacephem subclass",
|
||||
"CEFACL", "Cefaclor",
|
||||
"CEFADR", "Cefadroxil",
|
||||
"CEFAMA", "Cefamandole",
|
||||
"CEFATR", "Cefatrizine",
|
||||
"CEFAXE", "Cefuroxime (axetil)",
|
||||
"CEFAZE", "Cefazedon",
|
||||
"CEFAZO", "Cefazolin",
|
||||
"CEFBUP", "Cefbuperazone",
|
||||
"CEFCAP", "Cefcapene",
|
||||
"CEFCLA", "Cefepime/ Clavulanic Acid",
|
||||
"CEFCLI", "Cefclidin",
|
||||
"CEFDIN", "Cefdinir",
|
||||
"CEFDIT", "Cefditoren",
|
||||
"CEFEP4", "Cefepime 4 ug/ml",
|
||||
"CEFEPI", "Cefepime",
|
||||
"CEFETA", "Cefetamet",
|
||||
"CEFIXI", "Cefixime",
|
||||
"CEFMEN", "Cefmenoxime",
|
||||
"CEFMET", "Cefmetazole",
|
||||
"CEFMIN", "Cefminox",
|
||||
"CEFMTM", "Cefmetamet",
|
||||
"CEFO32", "Cefotaxime 32 ug/ml",
|
||||
"CEFONI", "Cefonicid",
|
||||
"CEFOPE", "Cefoperazone",
|
||||
"CEFORA", "Ceforanide",
|
||||
"CEFOSE", "Cefoselis",
|
||||
"CEFOTA", "Cefotaxime",
|
||||
"CEFOTE", "Cefotetan",
|
||||
"CEFOTI", "Cefotiam",
|
||||
"CEFOVE", "Cefovecin",
|
||||
"CEFOXI", "Cefoxitin",
|
||||
"CEFOZO", "Cefozopran",
|
||||
"CEFPAM", "Cefpiramide",
|
||||
"CEFPIM", "Cefpimizole",
|
||||
"CEFPOD", "Cefpodoxime",
|
||||
"CEFPOM", "Cefpirome",
|
||||
"CEFPRO", "Cefprozil",
|
||||
"CEFQUI", "Cefquinome",
|
||||
"CEFROX", "Cefroxidime",
|
||||
"CEFSUL", "Cefsulodin",
|
||||
"CEFTAR", "Ceftaroline",
|
||||
"CEFTAZ", "Ceftazidime",
|
||||
"CEFTER", "Cefteram",
|
||||
"CEFTEZ", "Ceftezole",
|
||||
"CEFTIB", "Ceftibuten",
|
||||
"CEFTIF", "Ceftiofur",
|
||||
"CEFTIX", "Ceftioxadine",
|
||||
"CEFTIZ", "Ceftizoxime",
|
||||
"CEFTOB", "Ceftobiprole",
|
||||
"CEFTRI", "Ceftriaxone",
|
||||
"CEFURO", "Cefuroxime (sodium)",
|
||||
"CEFUZO", "Cefuzonam",
|
||||
"CELLOB", "Cellobiose",
|
||||
"CEPALE", "Cefalexin",
|
||||
"CEPHAC", "Cephacetril",
|
||||
"CEPHAL", "Cephalothin",
|
||||
"CEPHAP", "Cephapirin",
|
||||
"CEPHEM", "Cephem class",
|
||||
"CEPHOR", "Cephem (oral) class",
|
||||
"CEPHPA", "Cephem (parenteral) class",
|
||||
"CEPHRA", "Cephradine",
|
||||
"CEPLOR", "Cephaloridine",
|
||||
"CHLORA", "Chloramphenicol",
|
||||
"CHLTET", "Chlortetracycline",
|
||||
"CI983", "CI-983",
|
||||
"CINOXA", "Cinoxacin",
|
||||
"CIPROF", "Ciprofloxacin",
|
||||
"CIPROP", "CIPROP",
|
||||
"CITRAT", "Citrate",
|
||||
"CLARYT", "Clarithromycin",
|
||||
"CLIN32", "Clindamycin 32 ug/ml",
|
||||
"CLINAF", "Clinafloxacin",
|
||||
"CLINDA", "Clindamycin",
|
||||
"CLISPE", "Clindamycin/ Spectinomycin",
|
||||
"CLOFAM", "Clofazimine",
|
||||
"CLOXAC", "Cloxacillin",
|
||||
"CMYC", "Cephamycin subclass",
|
||||
"COAGUL", "Coagulase",
|
||||
"COLFAZ", "Colfazamine",
|
||||
"COLIST", "Colistin",
|
||||
"COLMET", "Colistimethate",
|
||||
"COMBO", "Combination class",
|
||||
"CORAL", "Cephem (oral) class",
|
||||
"COUMER", "Coumermycin",
|
||||
"COXA", "Oxacephem subclass",
|
||||
"CPAREN", "Cephem (parenteral) class",
|
||||
"CPCA", "Cond. Pyridone Carboxylic Acid class",
|
||||
"CSPOR", "Cephalosporin class",
|
||||
"CSPOR1", "Cephalosporin I-Generation subclass",
|
||||
"CSPOR2", "Cephalosporin II-Generation subclass",
|
||||
"CSPOR3", "Cephalosporin III-Generation subclass",
|
||||
"CSPOR4", "Cephalosporin IV-Generation subclass",
|
||||
"CSPOR5", "Cephalosporin V-Generation subclass",
|
||||
"CYCLAC", "Cyclacillin",
|
||||
"CYCLOS", "Cycloserine",
|
||||
"DALBAV", "Dalbavancin",
|
||||
"DALFOP", "Dalfopristin",
|
||||
"DANOFL", "Danofloxacin",
|
||||
"DAPT25", "Daptomycin 25mg/L Ca",
|
||||
"DAPT50", "Daptomycin 50mg/L Ca",
|
||||
"DAPTOM", "Daptomycin",
|
||||
"DEMECY", "Demeclocycline",
|
||||
"DIBEKA", "Dibekacin",
|
||||
"DICLOX", "Dicloxacillin",
|
||||
"DIFLOX", "Difloxacin",
|
||||
"DIRITH", "Dirithromycin",
|
||||
"DORIPE", "Doripenem",
|
||||
"DOXYCY", "Doxycycline",
|
||||
"DTEST1", "DTest1",
|
||||
"DTEST2", "DTest2",
|
||||
"ENOXA", "Enoxacin",
|
||||
"ENROFL", "Enrofloxacin",
|
||||
"ERTAPE", "Ertapenem",
|
||||
"ERY32", "Erythromycin 32 ug/ml",
|
||||
"ERYSCH", "Erythromycin/ Sulphachloropyrid",
|
||||
"ERYSDI", "Erythromycin/ Sulphadimethoxine",
|
||||
"ERYSPE", "Erythromycin/ Spectinomycin",
|
||||
"ERYSUL", "Erythromycin/ Sulfizoxazole",
|
||||
"ERYTH", "Erythromycin",
|
||||
"ESBL", "Extended spectrum beta-lactamase",
|
||||
"ETHAMB", "Ethambutol",
|
||||
"ETHION", "Ethionamide",
|
||||
"FAROPE", "Faropenem",
|
||||
"FLAVOM", "Flavomycin",
|
||||
"FLEROX", "Fleroxacin",
|
||||
"FLOMOX", "Flomoxef",
|
||||
"FLORFE", "Florfenicol",
|
||||
"FLQUIN", "Fluoroquinolone class",
|
||||
"FLUCLO", "Flucloxacillin",
|
||||
"FLUCON", "Fluconazole",
|
||||
"FLUCYT", "5-Flucytosine",
|
||||
"FLUMEQ", "Flumequine",
|
||||
"FOPSUL", "Cefoperazone/ Sulbactam",
|
||||
"FOSFOM", "Fosfomycin",
|
||||
"FOSG6P", "Fosfomycin + Glucose6Phosphate",
|
||||
"FOSMYC", "Fosfomycin class",
|
||||
"FOSTRO", "Fosfomycin-trometamol",
|
||||
"FOT1", "Cefotaxime 1 ug/ml",
|
||||
"FOXSCR", "Cefoxitin Screen Test",
|
||||
"FPINHB", "Folate Pathway Inhibitor class",
|
||||
"FR1", "FR1",
|
||||
"FR10", "FR10",
|
||||
"FR12", "FR12",
|
||||
"FR13", "FR13",
|
||||
"FR14", "FR14",
|
||||
"FR15", "FR15",
|
||||
"FR16", "FR16",
|
||||
"FR17", "FR17",
|
||||
"FR18", "FR18",
|
||||
"FR19", "FR19",
|
||||
"FR20", "FR20",
|
||||
"FR21", "FR21",
|
||||
"FR22", "FR22",
|
||||
"FR23", "FR23",
|
||||
"FR24", "FR24",
|
||||
"FR25", "FR25",
|
||||
"FR26", "FR26",
|
||||
"FR27", "FR27",
|
||||
"FR28", "FR28",
|
||||
"FR29", "FR29",
|
||||
"FR3", "FR3",
|
||||
"FR30", "FR30",
|
||||
"FR31", "FR31",
|
||||
"FR32", "FR32",
|
||||
"FR5", "FR5",
|
||||
"FR6", "FR6",
|
||||
"FR7", "FR7",
|
||||
"FR8", "FR8",
|
||||
"FR9", "FR9",
|
||||
"FRAMYC", "Framycetin",
|
||||
"FRUCTO", "Fructose",
|
||||
"FURALT", "Furaltadone",
|
||||
"FURAZO", "Furazolidone",
|
||||
"FUSACI", "Fusidic Acid",
|
||||
"FUSIDA", "Fusidate",
|
||||
"GARENO", "Garenoxacin",
|
||||
"GARLIC", "Garlic",
|
||||
"GATIFL", "Gatifloxacin",
|
||||
"GE1000", "Gentamicin 1000 ug/ml",
|
||||
"GE2000", "Gentamicin 2000 ug/ml",
|
||||
"GEMIFL", "Gemifloxacin",
|
||||
"GEN128", "Gentamicin 128 ug/ml",
|
||||
"GEN500", "Gentamicin 500 ug/ml",
|
||||
"GENTA1", "Gentamicin 1024 ug/ml",
|
||||
"GENTAM", "Gentamicin",
|
||||
"GLUCOS", "Glucose",
|
||||
"GLYCER", "Glycerol",
|
||||
"GLYCO", "Glycopeptide class",
|
||||
"GREPAF", "Grepafloxacin",
|
||||
"HETACI", "Hetacillin",
|
||||
"HIPPUR", "Hippurate hydrolysis",
|
||||
"HODGE", "Hodge Test",
|
||||
"IB367", "IB-367",
|
||||
"IBAFLO", "Ibafloxacin",
|
||||
"ICLAPR", "Iclaprim",
|
||||
"IMIDAZ", "Imidazole class",
|
||||
"IMIP32", "Imipenem 32 ug/ml",
|
||||
"IMIPEN", "Imipenem",
|
||||
"INDOLE", "Indole",
|
||||
"INOSIT", "Inositol",
|
||||
"ISEPAM", "Isepamycin",
|
||||
"ISONIA", "Isoniazid",
|
||||
"ISOPEN", "Isoxazolyl Penicillin subclass",
|
||||
"ITRACO", "Itraconazole",
|
||||
"JOSAMY", "Josamycin",
|
||||
"KANAMY", "Kanamycin",
|
||||
"KETOCO", "Ketoconazole",
|
||||
"KETOLI", "Ketolide class",
|
||||
"LEVOFL", "Levofloxacin",
|
||||
"LINCOM", "Lincomycin",
|
||||
"LINCOS", "Lincosamide class",
|
||||
"LINEZO", "Linezolid",
|
||||
"LINFLO", "Linopristin-Flopristin",
|
||||
"LINNEO", "Lincomycin/ Neomycin 2:1 ratio",
|
||||
"LINSPE", "Lincomycin/ Spectinomycin",
|
||||
"LIPGLY", "Lipoglycopeptide subclass",
|
||||
"LIPOPE", "Lipopeptide class",
|
||||
"LOMEFL", "Lomefloxacin",
|
||||
"LORACA", "Loracarbef",
|
||||
"LYSINE", "Lysine",
|
||||
"MACCON", "Growth on MacConkey",
|
||||
"MACRO", "Macrolide class",
|
||||
"MALONA", "Malonate",
|
||||
"MALTOS", "Maltose",
|
||||
"MANNIT", "Mannitol",
|
||||
"MARBOF", "Marbofloxacin",
|
||||
"MECILL", "Mecillinam",
|
||||
"MEROPE", "Meropenem",
|
||||
"METHCY", "Methacycline",
|
||||
"METHIC", "Methicillin",
|
||||
"METRON", "Metronidazole",
|
||||
"MEZLO", "Mezlocillin",
|
||||
"MEZSUL", "Mezlocillin/ Sulbactam",
|
||||
"MICAFU", "Micafungin",
|
||||
"MICRON", "Micronomycin",
|
||||
"MIDEKA", "Midekamycin",
|
||||
"MINOCY", "Minocycline",
|
||||
"MONOBA", "Monobactam class",
|
||||
"MOTILI", "Motility",
|
||||
"MOXALA", "Moxalactam",
|
||||
"MOXIFL", "Moxifloxacin",
|
||||
"MUPIRO", "Mupirocin",
|
||||
"NAFCIL", "Nafcillin",
|
||||
"NALAC", "Nalidixic Acid",
|
||||
"NARASI", "Narasin",
|
||||
"NEGCTL", "Negative Growth Control",
|
||||
"NEOMYC", "Neomycin",
|
||||
"NETILM", "Netilmicin",
|
||||
"NFURAN", "Nitrofuran class",
|
||||
"NIMIDA", "Nitroimidazole class",
|
||||
"NIT16", "Nitrofurantoin 16ul",
|
||||
"NITFUR", "Nitrofurazone",
|
||||
"NITRAT", "Nitrate",
|
||||
"NITRO", "Nitrofurantoin",
|
||||
"NITSUL", "Nitrofurantoin/ Sulphadrazine",
|
||||
"NORFLO", "Norfloxacin",
|
||||
"NOVOBI", "Novobiocin",
|
||||
"NYSTAN", "Nystantin",
|
||||
"OFLOXA", "Ofloxacin",
|
||||
"OLAQUI", "Olaquindox",
|
||||
"OLEAND", "Oleandomycin",
|
||||
"OPTOCH", "Optochin Sensitivity",
|
||||
"ORBIFL", "Orbifloxacin",
|
||||
"ORITAV", "Oritavancin",
|
||||
"ORMSUL", "Ormetoprim/ Sulphadimethoxine",
|
||||
"ORNIST", "Ornithine Spot Test",
|
||||
"ORNITH", "Ornithine",
|
||||
"OXACIL", "Oxacillin + 2% NaCl",
|
||||
"OXAZOL", "Oxazolidinone class",
|
||||
"OXIDAS", "Oxidase",
|
||||
"OXOACI", "Oxolinic Acid",
|
||||
"OXTSCH", "Oxytet/Tylosin Tar/Sulphachlor",
|
||||
"OXTSDI", "Oxytet/Tylosin Tar/Sulphadimet",
|
||||
"OXYCEP", "Oxyimino Cephalosporin subclass",
|
||||
"OXYSCH", "Oxytetracycline/ Sulphachloropy",
|
||||
"OXYTET", "Oxytetracycline",
|
||||
"PASRAA", "Para-aminosalicylic acid",
|
||||
"PEN003", "Penicillin 0.03ug",
|
||||
"PENCIL", "Penicillin class",
|
||||
"PENIC8", "Penicillin 8 ug/ml",
|
||||
"PENICA", "Penicillin 1-2-8 ug/ml",
|
||||
"PENICI", "Penicillin",
|
||||
"PENMEN", "Penicillin(meningitis)",
|
||||
"PENNME", "Penicillin(nonmeningitis)",
|
||||
"PENNOV", "Penicillin/ Novobiocin",
|
||||
"PENORA", "Penicillin (Oral)",
|
||||
"PENSCH", "Penicillin/ Sulphachloropyridaz",
|
||||
"PENSTR", "Penicillin/ Streptomycin",
|
||||
"PERFLO", "Perfloxacin",
|
||||
"PHENIC", "Phenicol class",
|
||||
"PHEPEN", "Phenoxymethylpenicillin",
|
||||
"PIGMEN", "Pigment",
|
||||
"PIPACI", "Pipemidic Acid",
|
||||
"PIPERA", "Piperacillin",
|
||||
"PIPTAZ", "Piperacillin/ Tazobactam",
|
||||
"PIRLIM", "Pirlimycin",
|
||||
"PIVMEC", "Pivmecillinam",
|
||||
"PLUERO", "Plueromutilin class",
|
||||
"POD4", "Cefpodoxime 4 ug/ml",
|
||||
"PODCLA", "Cefpodoxime/ Clavulanic Acid",
|
||||
"POLION", "Polyether Ionophore class",
|
||||
"POLPEP", "Polypeptide class",
|
||||
"POLYB", "Polymyxin B",
|
||||
"POSACO", "Posaconazole",
|
||||
"POSCTL", "Positive Growth Control",
|
||||
"PREMAF", "Premafloxacin",
|
||||
"PRISTI", "Pristinamycin",
|
||||
"PSPEN", "Penicillinase-stable Penicillin class",
|
||||
"PYRUVA", "Pyruvate",
|
||||
"QUIN", "Quinolone class",
|
||||
"QUINOL", "Quinolones",
|
||||
"QUINS1", "Quinolones subclass 1",
|
||||
"QUINUP", "Quinupristin",
|
||||
"R28965", "RU 28965",
|
||||
"RAFFIN", "Raffinose",
|
||||
"RAMOPL", "Ramoplanin",
|
||||
"RAVUCO", "Ravuconazole",
|
||||
"RAZUPE", "Razupenem",
|
||||
"RHAMNO", "Rhamnose",
|
||||
"RIFAMP", "Rifampin",
|
||||
"RIFMYC", "Rifamycin class",
|
||||
"ROKITA", "Rokitamycin",
|
||||
"ROXITH", "Roxithromycin",
|
||||
"S21420", "Schering 21420",
|
||||
"S21561", "Schering 21561",
|
||||
"S21562", "Schering 21562",
|
||||
"S22591", "Schering 22591",
|
||||
"S29482", "Schering 29482",
|
||||
"S29486", "Schering 29486",
|
||||
"S34343", "Schering 34343",
|
||||
"S38609", "Schering 38609",
|
||||
"SALCTL", "Positive Control +2% NaCl",
|
||||
"SALINO", "Salinomycin",
|
||||
"SANFET", "Sanfetrinem",
|
||||
"SARAFL", "Sarafloxacin",
|
||||
"SB2LB2", "SB265805/ LB20304",
|
||||
"SBQLO", "SB265805",
|
||||
"SDIMET", "Sulphadimethoxine",
|
||||
"SIPRAM", "Sipramycin",
|
||||
"SISOMY", "Sisomycin",
|
||||
"SITAFL", "Sitafloxacin",
|
||||
"SORBIT", "Sorbitol",
|
||||
"SPARFL", "Sparfloxacin",
|
||||
"SPECT", "Spectinomycin",
|
||||
"SPIRAM", "Spiramycin",
|
||||
"ST1000", "Streptomycin 1000 ug/ml",
|
||||
"ST2000", "Streptomycin 2000 ug/ml",
|
||||
"STREPT", "Streptomycin",
|
||||
"STRGRA", "Streptogramin class",
|
||||
"SUCROS", "Sucrose",
|
||||
"SULAMI", "Sulfonamide subclass",
|
||||
"SULBAC", "Sulbactam",
|
||||
"SULBEN", "Sulbenicillin",
|
||||
"SULCHL", "Sulphachloropyridazine",
|
||||
"SULDIA", "Sulphadiazine",
|
||||
"SULDIM", "Sulphadimidine",
|
||||
"SULFAM", "Sulphamethoxazole",
|
||||
"SULFIZ", "Sulfisoxazole",
|
||||
"SULMET", "Sulphamethazine",
|
||||
"SULOPE", "Sulopenem",
|
||||
"SULTHI", "Sulphathiazole",
|
||||
"SULTOS", "Sultamicillin Tosilate",
|
||||
"SYNERC", "Quinupristin/dalfopristin",
|
||||
"TANNAL", "Tannalbit",
|
||||
"TAXCLA", "Cefotaxime/clavulanic acid",
|
||||
"TAXMEN", "Cefotaxime (meningitis)",
|
||||
"TAXNME", "Cefotaxime (nonmeningitis)",
|
||||
"TAZCLA", "Ceftazidime/clavulanic acid",
|
||||
"TAZOBA", "Tazobactam",
|
||||
"TDA", "TDA",
|
||||
"TEICOP", "Teicoplanin",
|
||||
"TELAVA", "Telavancin",
|
||||
"TELITH", "Telithromycin",
|
||||
"TEMAFL", "Temafloxacin",
|
||||
"TEMOCI", "Temocillin",
|
||||
"TETCYC", "Tetracycline class",
|
||||
"TETRA", "Tetracycline",
|
||||
"THIAPH", "Thiaphenicol",
|
||||
"TIAMUL", "Tiamulin",
|
||||
"TICARC", "Ticarcillin",
|
||||
"TICCLA", "Ticarcillin/ Clavulanic Acid",
|
||||
"TIGECY", "Tigecycline",
|
||||
"TILMIC", "Tilmicosin",
|
||||
"TOBRAM", "Tobramycin",
|
||||
"TOSUFL", "Tosufloxacin",
|
||||
"TREHAL", "Trehalose",
|
||||
"TRIBR", "Trimethoprim/ Sulphadiazine",
|
||||
"TRICLA", "Ceftriaxone/clavulanic acid",
|
||||
"TRIM", "Trimethoprim",
|
||||
"TRIMEN", "Ceftriaxone (meningitis)",
|
||||
"TRINME", "Ceftriaxone (nonmeningitis)",
|
||||
"TRISUL", "Trimethoprim/ Sulphamethoxazole",
|
||||
"TROSPE", "Trospectinomycin",
|
||||
"TROVAF", "Trovafloxacin",
|
||||
"TULATH", "Tulathromycin",
|
||||
"TYLO", "Tylosin (Tartrate/ Base)",
|
||||
"UNDECA", "Undecanoic Acid",
|
||||
"UREA", "Urea",
|
||||
"UREPEN", "Ureidopenicillin subclass",
|
||||
"UVAURS", "Uva Ursa",
|
||||
"VANCOM", "Vancomycin",
|
||||
"VIRGIN", "Virginiamycin",
|
||||
"VORICO", "Voriconazole",
|
||||
"W49373", "Win 49373-3",
|
||||
"W49548", "Win 49548-2A",
|
||||
"W51692", "Win 51692",
|
||||
"XYLOSE", "Xylose",
|
||||
"YELPIG", "Yellow Pigment"
|
||||
"ABT773", "Abbott 773",
|
||||
"AESCUL", "Aesculin",
|
||||
"AGMATI", "Agmatine",
|
||||
"AMDPEN", "Amidinopenicillin subclass",
|
||||
"AMICYC", "Aminocyclitol class",
|
||||
"AMIFLO", "Amifloxacin",
|
||||
"AMIGLY", "Aminoglycoside class",
|
||||
"AMIKAC", "Amikacin",
|
||||
"AMIPEN", "Aminopenicillin subclass",
|
||||
"AMOCL2", "Amoxicillin/ Clav.Acid */2",
|
||||
"AMOCL4", "Amoxicillin/ Clav. Acid 4:1",
|
||||
"AMOCLA", "Amoxicillin/ Clavulanic Acid",
|
||||
"AMOXIC", "Amoxicillin",
|
||||
"AMP100", "Ampicillin 100 ug/ml",
|
||||
"AMP200", "Ampicillin 200 ug/ml",
|
||||
"AMPHOT", "Amphotericin B",
|
||||
"AMPICI", "Ampicillin",
|
||||
"AMPSUL", "Ampicillin/ Sulbactam",
|
||||
"ANIDUL", "Anidulafungin",
|
||||
"ANSAMY", "Rifabutin",
|
||||
"ANSMYC", "Ansamycin class",
|
||||
"APALCI", "Apalcillin",
|
||||
"APOXIC", "Apoxicillin",
|
||||
"APRAMY", "Apramycin",
|
||||
"ARABIN", "Arabinose",
|
||||
"ARABIT", "Arabitol",
|
||||
"ARBEKA", "Arbekacin",
|
||||
"ARGINI", "Arginine",
|
||||
"ASPOXI", "Aspoxicillin",
|
||||
"ASTROM", "Astromycin",
|
||||
"AVILAM", "Avilamycin",
|
||||
"AZD256", "AZD2563",
|
||||
"AZITHR", "Azithromycin",
|
||||
"AZLOCI", "Azlocillin",
|
||||
"AZT1", "Aztreonam 1 ug/ml",
|
||||
"AZTREO", "Aztreonam",
|
||||
"BACAMP", "Bacampicillin",
|
||||
"BACITR", "Bacitracin",
|
||||
"BAMMYC", "Bambermycin class",
|
||||
"BAY12", "BAY12-8039",
|
||||
"BERBER", "Berberine",
|
||||
"BESIFL", "Besifloxacin",
|
||||
"BETA", "Beta-lactamase",
|
||||
"B", "HAEM Beta-haemolysis",
|
||||
"BIAPEN", "Biapenem (L-627)",
|
||||
"BLACT", "Beta-lactam class",
|
||||
"BLINHB", "Beta-lactam Inhibitor class",
|
||||
"B", "MGLU B-Methyl Glucoside",
|
||||
"CAPREO", "Capreomycin",
|
||||
"CAPRYL", "Caprylic Acid",
|
||||
"CARBAD", "Carbadox",
|
||||
"CARBAP", "Carbapenem class",
|
||||
"CARBEN", "Carbenicillin",
|
||||
"CARPEN", "Carboxypenicillin subclass",
|
||||
"CASPOF", "Caspofungin",
|
||||
"CATALA", "Catalase",
|
||||
"CCARB", "Carbacephem subclass",
|
||||
"CEFACL", "Cefaclor",
|
||||
"CEFADR", "Cefadroxil",
|
||||
"CEFAMA", "Cefamandole",
|
||||
"CEFATR", "Cefatrizine",
|
||||
"CEFAXE", "Cefuroxime (axetil)",
|
||||
"CEFAZE", "Cefazedon",
|
||||
"CEFAZO", "Cefazolin",
|
||||
"CEFBUP", "Cefbuperazone",
|
||||
"CEFCAP", "Cefcapene",
|
||||
"CEFCLA", "Cefepime/ Clavulanic Acid",
|
||||
"CEFCLI", "Cefclidin",
|
||||
"CEFDIN", "Cefdinir",
|
||||
"CEFDIT", "Cefditoren",
|
||||
"CEFEP4", "Cefepime 4 ug/ml",
|
||||
"CEFEPI", "Cefepime",
|
||||
"CEFETA", "Cefetamet",
|
||||
"CEFIXI", "Cefixime",
|
||||
"CEFMEN", "Cefmenoxime",
|
||||
"CEFMET", "Cefmetazole",
|
||||
"CEFMIN", "Cefminox",
|
||||
"CEFMTM", "Cefmetamet",
|
||||
"CEFO32", "Cefotaxime 32 ug/ml",
|
||||
"CEFONI", "Cefonicid",
|
||||
"CEFOPE", "Cefoperazone",
|
||||
"CEFORA", "Ceforanide",
|
||||
"CEFOSE", "Cefoselis",
|
||||
"CEFOTA", "Cefotaxime",
|
||||
"CEFOTE", "Cefotetan",
|
||||
"CEFOTI", "Cefotiam",
|
||||
"CEFOVE", "Cefovecin",
|
||||
"CEFOXI", "Cefoxitin",
|
||||
"CEFOZO", "Cefozopran",
|
||||
"CEFPAM", "Cefpiramide",
|
||||
"CEFPIM", "Cefpimizole",
|
||||
"CEFPOD", "Cefpodoxime",
|
||||
"CEFPOM", "Cefpirome",
|
||||
"CEFPRO", "Cefprozil",
|
||||
"CEFQUI", "Cefquinome",
|
||||
"CEFROX", "Cefroxidime",
|
||||
"CEFSUL", "Cefsulodin",
|
||||
"CEFTAR", "Ceftaroline",
|
||||
"CEFTAZ", "Ceftazidime",
|
||||
"CEFTER", "Cefteram",
|
||||
"CEFTEZ", "Ceftezole",
|
||||
"CEFTIB", "Ceftibuten",
|
||||
"CEFTIF", "Ceftiofur",
|
||||
"CEFTIX", "Ceftioxadine",
|
||||
"CEFTIZ", "Ceftizoxime",
|
||||
"CEFTOB", "Ceftobiprole",
|
||||
"CEFTRI", "Ceftriaxone",
|
||||
"CEFURO", "Cefuroxime (sodium)",
|
||||
"CEFUZO", "Cefuzonam",
|
||||
"CELLOB", "Cellobiose",
|
||||
"CEPALE", "Cefalexin",
|
||||
"CEPHAC", "Cephacetril",
|
||||
"CEPHAL", "Cephalothin",
|
||||
"CEPHAP", "Cephapirin",
|
||||
"CEPHEM", "Cephem class",
|
||||
"CEPHOR", "Cephem (oral) class",
|
||||
"CEPHPA", "Cephem (parenteral) class",
|
||||
"CEPHRA", "Cephradine",
|
||||
"CEPLOR", "Cephaloridine",
|
||||
"CHLORA", "Chloramphenicol",
|
||||
"CHLTET", "Chlortetracycline",
|
||||
"CI983", "CI-983",
|
||||
"CINOXA", "Cinoxacin",
|
||||
"CIPROF", "Ciprofloxacin",
|
||||
"CIPROP", "CIPROP",
|
||||
"CITRAT", "Citrate",
|
||||
"CLARYT", "Clarithromycin",
|
||||
"CLIN32", "Clindamycin 32 ug/ml",
|
||||
"CLINAF", "Clinafloxacin",
|
||||
"CLINDA", "Clindamycin",
|
||||
"CLISPE", "Clindamycin/ Spectinomycin",
|
||||
"CLOFAM", "Clofazimine",
|
||||
"CLOXAC", "Cloxacillin",
|
||||
"CMYC", "Cephamycin subclass",
|
||||
"COAGUL", "Coagulase",
|
||||
"COLFAZ", "Colfazamine",
|
||||
"COLIST", "Colistin",
|
||||
"COLMET", "Colistimethate",
|
||||
"COMBO", "Combination class",
|
||||
"CORAL", "Cephem (oral) class",
|
||||
"COUMER", "Coumermycin",
|
||||
"COXA", "Oxacephem subclass",
|
||||
"CPAREN", "Cephem (parenteral) class",
|
||||
"CPCA", "Cond. Pyridone Carboxylic Acid class",
|
||||
"CSPOR", "Cephalosporin class",
|
||||
"CSPOR1", "Cephalosporin I-Generation subclass",
|
||||
"CSPOR2", "Cephalosporin II-Generation subclass",
|
||||
"CSPOR3", "Cephalosporin III-Generation subclass",
|
||||
"CSPOR4", "Cephalosporin IV-Generation subclass",
|
||||
"CSPOR5", "Cephalosporin V-Generation subclass",
|
||||
"CYCLAC", "Cyclacillin",
|
||||
"CYCLOS", "Cycloserine",
|
||||
"DALBAV", "Dalbavancin",
|
||||
"DALFOP", "Dalfopristin",
|
||||
"DANOFL", "Danofloxacin",
|
||||
"DAPT25", "Daptomycin 25mg/L Ca",
|
||||
"DAPT50", "Daptomycin 50mg/L Ca",
|
||||
"DAPTOM", "Daptomycin",
|
||||
"DEMECY", "Demeclocycline",
|
||||
"DIBEKA", "Dibekacin",
|
||||
"DICLOX", "Dicloxacillin",
|
||||
"DIFLOX", "Difloxacin",
|
||||
"DIRITH", "Dirithromycin",
|
||||
"DORIPE", "Doripenem",
|
||||
"DOXYCY", "Doxycycline",
|
||||
"DTEST1", "DTest1",
|
||||
"DTEST2", "DTest2",
|
||||
"ENOXA", "Enoxacin",
|
||||
"ENROFL", "Enrofloxacin",
|
||||
"ERTAPE", "Ertapenem",
|
||||
"ERY32", "Erythromycin 32 ug/ml",
|
||||
"ERYSCH", "Erythromycin/ Sulphachloropyrid",
|
||||
"ERYSDI", "Erythromycin/ Sulphadimethoxine",
|
||||
"ERYSPE", "Erythromycin/ Spectinomycin",
|
||||
"ERYSUL", "Erythromycin/ Sulfizoxazole",
|
||||
"ERYTH", "Erythromycin",
|
||||
"ESBL", "Extended spectrum beta-lactamase",
|
||||
"ETHAMB", "Ethambutol",
|
||||
"ETHION", "Ethionamide",
|
||||
"FAROPE", "Faropenem",
|
||||
"FLAVOM", "Flavomycin",
|
||||
"FLEROX", "Fleroxacin",
|
||||
"FLOMOX", "Flomoxef",
|
||||
"FLORFE", "Florfenicol",
|
||||
"FLQUIN", "Fluoroquinolone class",
|
||||
"FLUCLO", "Flucloxacillin",
|
||||
"FLUCON", "Fluconazole",
|
||||
"FLUCYT", "5-Flucytosine",
|
||||
"FLUMEQ", "Flumequine",
|
||||
"FOPSUL", "Cefoperazone/ Sulbactam",
|
||||
"FOSFOM", "Fosfomycin",
|
||||
"FOSG6P", "Fosfomycin + Glucose6Phosphate",
|
||||
"FOSMYC", "Fosfomycin class",
|
||||
"FOSTRO", "Fosfomycin-trometamol",
|
||||
"FOT1", "Cefotaxime 1 ug/ml",
|
||||
"FOXSCR", "Cefoxitin Screen Test",
|
||||
"FPINHB", "Folate Pathway Inhibitor class",
|
||||
"FR1", "FR1",
|
||||
"FR10", "FR10",
|
||||
"FR12", "FR12",
|
||||
"FR13", "FR13",
|
||||
"FR14", "FR14",
|
||||
"FR15", "FR15",
|
||||
"FR16", "FR16",
|
||||
"FR17", "FR17",
|
||||
"FR18", "FR18",
|
||||
"FR19", "FR19",
|
||||
"FR20", "FR20",
|
||||
"FR21", "FR21",
|
||||
"FR22", "FR22",
|
||||
"FR23", "FR23",
|
||||
"FR24", "FR24",
|
||||
"FR25", "FR25",
|
||||
"FR26", "FR26",
|
||||
"FR27", "FR27",
|
||||
"FR28", "FR28",
|
||||
"FR29", "FR29",
|
||||
"FR3", "FR3",
|
||||
"FR30", "FR30",
|
||||
"FR31", "FR31",
|
||||
"FR32", "FR32",
|
||||
"FR5", "FR5",
|
||||
"FR6", "FR6",
|
||||
"FR7", "FR7",
|
||||
"FR8", "FR8",
|
||||
"FR9", "FR9",
|
||||
"FRAMYC", "Framycetin",
|
||||
"FRUCTO", "Fructose",
|
||||
"FURALT", "Furaltadone",
|
||||
"FURAZO", "Furazolidone",
|
||||
"FUSACI", "Fusidic Acid",
|
||||
"FUSIDA", "Fusidate",
|
||||
"GARENO", "Garenoxacin",
|
||||
"GARLIC", "Garlic",
|
||||
"GATIFL", "Gatifloxacin",
|
||||
"GE1000", "Gentamicin 1000 ug/ml",
|
||||
"GE2000", "Gentamicin 2000 ug/ml",
|
||||
"GEMIFL", "Gemifloxacin",
|
||||
"GEN128", "Gentamicin 128 ug/ml",
|
||||
"GEN500", "Gentamicin 500 ug/ml",
|
||||
"GENTA1", "Gentamicin 1024 ug/ml",
|
||||
"GENTAM", "Gentamicin",
|
||||
"GLUCOS", "Glucose",
|
||||
"GLYCER", "Glycerol",
|
||||
"GLYCO", "Glycopeptide class",
|
||||
"GREPAF", "Grepafloxacin",
|
||||
"HETACI", "Hetacillin",
|
||||
"HIPPUR", "Hippurate hydrolysis",
|
||||
"HODGE", "Hodge Test",
|
||||
"IB367", "IB-367",
|
||||
"IBAFLO", "Ibafloxacin",
|
||||
"ICLAPR", "Iclaprim",
|
||||
"IMIDAZ", "Imidazole class",
|
||||
"IMIP32", "Imipenem 32 ug/ml",
|
||||
"IMIPEN", "Imipenem",
|
||||
"INDOLE", "Indole",
|
||||
"INOSIT", "Inositol",
|
||||
"ISEPAM", "Isepamycin",
|
||||
"ISONIA", "Isoniazid",
|
||||
"ISOPEN", "Isoxazolyl Penicillin subclass",
|
||||
"ITRACO", "Itraconazole",
|
||||
"JOSAMY", "Josamycin",
|
||||
"KANAMY", "Kanamycin",
|
||||
"KETOCO", "Ketoconazole",
|
||||
"KETOLI", "Ketolide class",
|
||||
"LEVOFL", "Levofloxacin",
|
||||
"LINCOM", "Lincomycin",
|
||||
"LINCOS", "Lincosamide class",
|
||||
"LINEZO", "Linezolid",
|
||||
"LINFLO", "Linopristin-Flopristin",
|
||||
"LINNEO", "Lincomycin/ Neomycin 2:1 ratio",
|
||||
"LINSPE", "Lincomycin/ Spectinomycin",
|
||||
"LIPGLY", "Lipoglycopeptide subclass",
|
||||
"LIPOPE", "Lipopeptide class",
|
||||
"LOMEFL", "Lomefloxacin",
|
||||
"LORACA", "Loracarbef",
|
||||
"LYSINE", "Lysine",
|
||||
"MACCON", "Growth on MacConkey",
|
||||
"MACRO", "Macrolide class",
|
||||
"MALONA", "Malonate",
|
||||
"MALTOS", "Maltose",
|
||||
"MANNIT", "Mannitol",
|
||||
"MARBOF", "Marbofloxacin",
|
||||
"MECILL", "Mecillinam",
|
||||
"MEROPE", "Meropenem",
|
||||
"METHCY", "Methacycline",
|
||||
"METHIC", "Methicillin",
|
||||
"METRON", "Metronidazole",
|
||||
"MEZLO", "Mezlocillin",
|
||||
"MEZSUL", "Mezlocillin/ Sulbactam",
|
||||
"MICAFU", "Micafungin",
|
||||
"MICRON", "Micronomycin",
|
||||
"MIDEKA", "Midekamycin",
|
||||
"MINOCY", "Minocycline",
|
||||
"MONOBA", "Monobactam class",
|
||||
"MOTILI", "Motility",
|
||||
"MOXALA", "Moxalactam",
|
||||
"MOXIFL", "Moxifloxacin",
|
||||
"MUPIRO", "Mupirocin",
|
||||
"NAFCIL", "Nafcillin",
|
||||
"NALAC", "Nalidixic Acid",
|
||||
"NARASI", "Narasin",
|
||||
"NEGCTL", "Negative Growth Control",
|
||||
"NEOMYC", "Neomycin",
|
||||
"NETILM", "Netilmicin",
|
||||
"NFURAN", "Nitrofuran class",
|
||||
"NIMIDA", "Nitroimidazole class",
|
||||
"NIT16", "Nitrofurantoin 16ul",
|
||||
"NITFUR", "Nitrofurazone",
|
||||
"NITRAT", "Nitrate",
|
||||
"NITRO", "Nitrofurantoin",
|
||||
"NITSUL", "Nitrofurantoin/ Sulphadrazine",
|
||||
"NORFLO", "Norfloxacin",
|
||||
"NOVOBI", "Novobiocin",
|
||||
"NYSTAN", "Nystantin",
|
||||
"OFLOXA", "Ofloxacin",
|
||||
"OLAQUI", "Olaquindox",
|
||||
"OLEAND", "Oleandomycin",
|
||||
"OPTOCH", "Optochin Sensitivity",
|
||||
"ORBIFL", "Orbifloxacin",
|
||||
"ORITAV", "Oritavancin",
|
||||
"ORMSUL", "Ormetoprim/ Sulphadimethoxine",
|
||||
"ORNIST", "Ornithine Spot Test",
|
||||
"ORNITH", "Ornithine",
|
||||
"OXACIL", "Oxacillin + 2% NaCl",
|
||||
"OXAZOL", "Oxazolidinone class",
|
||||
"OXIDAS", "Oxidase",
|
||||
"OXOACI", "Oxolinic Acid",
|
||||
"OXTSCH", "Oxytet/Tylosin Tar/Sulphachlor",
|
||||
"OXTSDI", "Oxytet/Tylosin Tar/Sulphadimet",
|
||||
"OXYCEP", "Oxyimino Cephalosporin subclass",
|
||||
"OXYSCH", "Oxytetracycline/ Sulphachloropy",
|
||||
"OXYTET", "Oxytetracycline",
|
||||
"PASRAA", "Para-aminosalicylic acid",
|
||||
"PEN003", "Penicillin 0.03ug",
|
||||
"PENCIL", "Penicillin class",
|
||||
"PENIC8", "Penicillin 8 ug/ml",
|
||||
"PENICA", "Penicillin 1-2-8 ug/ml",
|
||||
"PENICI", "Penicillin",
|
||||
"PENMEN", "Penicillin(meningitis)",
|
||||
"PENNME", "Penicillin(nonmeningitis)",
|
||||
"PENNOV", "Penicillin/ Novobiocin",
|
||||
"PENORA", "Penicillin (Oral)",
|
||||
"PENSCH", "Penicillin/ Sulphachloropyridaz",
|
||||
"PENSTR", "Penicillin/ Streptomycin",
|
||||
"PERFLO", "Perfloxacin",
|
||||
"PHENIC", "Phenicol class",
|
||||
"PHEPEN", "Phenoxymethylpenicillin",
|
||||
"PIGMEN", "Pigment",
|
||||
"PIPACI", "Pipemidic Acid",
|
||||
"PIPERA", "Piperacillin",
|
||||
"PIPTAZ", "Piperacillin/ Tazobactam",
|
||||
"PIRLIM", "Pirlimycin",
|
||||
"PIVMEC", "Pivmecillinam",
|
||||
"PLUERO", "Plueromutilin class",
|
||||
"POD4", "Cefpodoxime 4 ug/ml",
|
||||
"PODCLA", "Cefpodoxime/ Clavulanic Acid",
|
||||
"POLION", "Polyether Ionophore class",
|
||||
"POLPEP", "Polypeptide class",
|
||||
"POLYB", "Polymyxin B",
|
||||
"POSACO", "Posaconazole",
|
||||
"POSCTL", "Positive Growth Control",
|
||||
"PREMAF", "Premafloxacin",
|
||||
"PRISTI", "Pristinamycin",
|
||||
"PSPEN", "Penicillinase-stable Penicillin class",
|
||||
"PYRUVA", "Pyruvate",
|
||||
"QUIN", "Quinolone class",
|
||||
"QUINOL", "Quinolones",
|
||||
"QUINS1", "Quinolones subclass 1",
|
||||
"QUINUP", "Quinupristin",
|
||||
"R28965", "RU 28965",
|
||||
"RAFFIN", "Raffinose",
|
||||
"RAMOPL", "Ramoplanin",
|
||||
"RAVUCO", "Ravuconazole",
|
||||
"RAZUPE", "Razupenem",
|
||||
"RHAMNO", "Rhamnose",
|
||||
"RIFAMP", "Rifampin",
|
||||
"RIFMYC", "Rifamycin class",
|
||||
"ROKITA", "Rokitamycin",
|
||||
"ROXITH", "Roxithromycin",
|
||||
"S21420", "Schering 21420",
|
||||
"S21561", "Schering 21561",
|
||||
"S21562", "Schering 21562",
|
||||
"S22591", "Schering 22591",
|
||||
"S29482", "Schering 29482",
|
||||
"S29486", "Schering 29486",
|
||||
"S34343", "Schering 34343",
|
||||
"S38609", "Schering 38609",
|
||||
"SALCTL", "Positive Control +2% NaCl",
|
||||
"SALINO", "Salinomycin",
|
||||
"SANFET", "Sanfetrinem",
|
||||
"SARAFL", "Sarafloxacin",
|
||||
"SB2LB2", "SB265805/ LB20304",
|
||||
"SBQLO", "SB265805",
|
||||
"SDIMET", "Sulphadimethoxine",
|
||||
"SIPRAM", "Sipramycin",
|
||||
"SISOMY", "Sisomycin",
|
||||
"SITAFL", "Sitafloxacin",
|
||||
"SORBIT", "Sorbitol",
|
||||
"SPARFL", "Sparfloxacin",
|
||||
"SPECT", "Spectinomycin",
|
||||
"SPIRAM", "Spiramycin",
|
||||
"ST1000", "Streptomycin 1000 ug/ml",
|
||||
"ST2000", "Streptomycin 2000 ug/ml",
|
||||
"STREPT", "Streptomycin",
|
||||
"STRGRA", "Streptogramin class",
|
||||
"SUCROS", "Sucrose",
|
||||
"SULAMI", "Sulfonamide subclass",
|
||||
"SULBAC", "Sulbactam",
|
||||
"SULBEN", "Sulbenicillin",
|
||||
"SULCHL", "Sulphachloropyridazine",
|
||||
"SULDIA", "Sulphadiazine",
|
||||
"SULDIM", "Sulphadimidine",
|
||||
"SULFAM", "Sulphamethoxazole",
|
||||
"SULFIZ", "Sulfisoxazole",
|
||||
"SULMET", "Sulphamethazine",
|
||||
"SULOPE", "Sulopenem",
|
||||
"SULTHI", "Sulphathiazole",
|
||||
"SULTOS", "Sultamicillin Tosilate",
|
||||
"SYNERC", "Quinupristin/dalfopristin",
|
||||
"TANNAL", "Tannalbit",
|
||||
"TAXCLA", "Cefotaxime/clavulanic acid",
|
||||
"TAXMEN", "Cefotaxime (meningitis)",
|
||||
"TAXNME", "Cefotaxime (nonmeningitis)",
|
||||
"TAZCLA", "Ceftazidime/clavulanic acid",
|
||||
"TAZOBA", "Tazobactam",
|
||||
"TDA", "TDA",
|
||||
"TEICOP", "Teicoplanin",
|
||||
"TELAVA", "Telavancin",
|
||||
"TELITH", "Telithromycin",
|
||||
"TEMAFL", "Temafloxacin",
|
||||
"TEMOCI", "Temocillin",
|
||||
"TETCYC", "Tetracycline class",
|
||||
"TETRA", "Tetracycline",
|
||||
"THIAPH", "Thiaphenicol",
|
||||
"TIAMUL", "Tiamulin",
|
||||
"TICARC", "Ticarcillin",
|
||||
"TICCLA", "Ticarcillin/ Clavulanic Acid",
|
||||
"TIGECY", "Tigecycline",
|
||||
"TILMIC", "Tilmicosin",
|
||||
"TOBRAM", "Tobramycin",
|
||||
"TOSUFL", "Tosufloxacin",
|
||||
"TREHAL", "Trehalose",
|
||||
"TRIBR", "Trimethoprim/ Sulphadiazine",
|
||||
"TRICLA", "Ceftriaxone/clavulanic acid",
|
||||
"TRIM", "Trimethoprim",
|
||||
"TRIMEN", "Ceftriaxone (meningitis)",
|
||||
"TRINME", "Ceftriaxone (nonmeningitis)",
|
||||
"TRISUL", "Trimethoprim/ Sulphamethoxazole",
|
||||
"TROSPE", "Trospectinomycin",
|
||||
"TROVAF", "Trovafloxacin",
|
||||
"TULATH", "Tulathromycin",
|
||||
"TYLO", "Tylosin (Tartrate/ Base)",
|
||||
"UNDECA", "Undecanoic Acid",
|
||||
"UREA", "Urea",
|
||||
"UREPEN", "Ureidopenicillin subclass",
|
||||
"UVAURS", "Uva Ursa",
|
||||
"VANCOM", "Vancomycin",
|
||||
"VIRGIN", "Virginiamycin",
|
||||
"VORICO", "Voriconazole",
|
||||
"W49373", "Win 49373-3",
|
||||
"W49548", "Win 49548-2A",
|
||||
"W51692", "Win 51692",
|
||||
"XYLOSE", "Xylose",
|
||||
"YELPIG", "Yellow Pigment"
|
||||
)
|
||||
|
||||
codes$name <- gsub("Apoxi", "Aspoxi", codes$name)
|
||||
@@ -476,10 +476,10 @@ codes$ab_name <- ab_name(codes$name_gen)
|
||||
|
||||
codes$lev <- unlist(Map(f = function(a, b) {
|
||||
as.double(utils::adist(a, b,
|
||||
ignore.case = FALSE,
|
||||
fixed = TRUE,
|
||||
costs = c(insertions = 5, deletions = 1, substitutions = 10),
|
||||
counts = FALSE
|
||||
ignore.case = FALSE,
|
||||
fixed = TRUE,
|
||||
costs = c(insertions = 5, deletions = 1, substitutions = 10),
|
||||
counts = FALSE
|
||||
))
|
||||
}, codes$name_gen, generalise_antibiotic_name(codes$ab_name), USE.NAMES = FALSE))
|
||||
|
||||
@@ -487,10 +487,7 @@ codes$lev_pct <- codes$lev / nchar(codes$name)
|
||||
|
||||
View(codes)
|
||||
|
||||
import <- codes |>
|
||||
filter(lev <= 10 | name_gen == "PENICILLIN") |>
|
||||
as_tibble() |>
|
||||
mutate(ab = as.ab(ab_name, fast_mode = TRUE))
|
||||
import <- codes |> filter(lev <= 10 | name_gen == "PENICILLIN") |> as_tibble() |> mutate(ab = as.ab(ab_name, fast_mode = TRUE))
|
||||
|
||||
for (i in seq_len(NROW(import))) {
|
||||
# put them in the abbreviations
|
||||
|
||||
@@ -1056,10 +1056,8 @@ import$mo <- as.mo(import$mo_name)
|
||||
|
||||
microorganisms.codes <- microorganisms.codes |>
|
||||
bind_rows(
|
||||
tibble(
|
||||
code = toupper(import$code),
|
||||
mo = import$mo
|
||||
) |>
|
||||
tibble(code = toupper(import$code),
|
||||
mo = import$mo) |>
|
||||
distinct()
|
||||
) |>
|
||||
arrange(code)
|
||||
@@ -1067,3 +1065,4 @@ class(microorganisms.codes$mo) <- c("mo", "character")
|
||||
usethis::use_data(microorganisms.codes, overwrite = TRUE, compress = "xz", version = 2)
|
||||
rm(microorganisms.codes)
|
||||
devtools::load_all()
|
||||
|
||||
|
||||
@@ -3,15 +3,13 @@ df <- example_isolates |>
|
||||
mutate(mo = ifelse(mo_genus(mo) == "Klebsiella", as.mo("Klebsiella"), mo)) |>
|
||||
top_n_microorganisms(10)
|
||||
|
||||
out_new <- df |> antibiogram(c("TZP", "TZP+GEN", "TZP+TOB"), wisca = TRUE, syndromic_group = "ward")
|
||||
out_nonwisca <- df |>
|
||||
antibiogram(c("TZP", "TZP+GEN", "TZP+TOB"),
|
||||
syndromic_group = "ward",
|
||||
mo_transform = function(x) "",
|
||||
digits = 1,
|
||||
minimum = 10,
|
||||
formatting_type = 14
|
||||
) |>
|
||||
out_new <- df |> antibiogram(c("TZP","TZP+GEN","TZP+TOB"), wisca = TRUE, syndromic_group = "ward")
|
||||
out_nonwisca <- df |> antibiogram(c("TZP","TZP+GEN","TZP+TOB"),
|
||||
syndromic_group = "ward",
|
||||
mo_transform = function(x) "",
|
||||
digits = 1,
|
||||
minimum = 10,
|
||||
formatting_type = 14) |>
|
||||
as_tibble() |>
|
||||
select(-Pathogen)
|
||||
|
||||
@@ -19,3 +17,7 @@ out_nonwisca <- df |>
|
||||
# parameters_amr.R: number of first isolates are determined on the whole data set, while Klebsiella is aggregated afterwards (=duplicates on genus level)
|
||||
|
||||
source("~/Downloads/estimate_definition_amr.R")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
118
index.md
118
index.md
@@ -26,9 +26,12 @@
|
||||
<div style="display: flex; font-size: 0.8em;">
|
||||
|
||||
<p style="text-align:left; width: 50%;">
|
||||
|
||||
<small><a href="https://amr-for-r.org/">amr-for-r.org</a></small>
|
||||
</p>
|
||||
|
||||
<p style="text-align:right; width: 50%;">
|
||||
|
||||
<small><a href="https://doi.org/10.18637/jss.v104.i03" target="_blank">doi.org/10.18637/jss.v104.i03</a></small>
|
||||
</p>
|
||||
|
||||
@@ -171,26 +174,24 @@ example_isolates %>%
|
||||
#> ℹ Using column mo as input for `mo_fullname()`
|
||||
#> ℹ Using column mo as input for `mo_is_gram_negative()`
|
||||
#> ℹ Using column mo as input for `mo_is_intrinsic_resistant()`
|
||||
#> ℹ Determining intrinsic resistance based on 'EUCAST Expected
|
||||
#> Resistant Phenotypes' v1.2 (2023). This note will be shown
|
||||
#> once per session.
|
||||
#> ℹ For `aminoglycosides()` using columns GEN (gentamicin), TOB
|
||||
#> (tobramycin), AMK (amikacin), and KAN (kanamycin)
|
||||
#> ℹ For `carbapenems()` using columns IPM (imipenem) and MEM
|
||||
#> (meropenem)
|
||||
#> ℹ Determining intrinsic resistance based on 'EUCAST Expected Resistant
|
||||
#> Phenotypes' v1.2 (2023). This note will be shown once per session.
|
||||
#> ℹ For `aminoglycosides()` using columns GEN (gentamicin), TOB (tobramycin), AMK
|
||||
#> (amikacin), and KAN (kanamycin)
|
||||
#> ℹ For `carbapenems()` using columns IPM (imipenem) and MEM (meropenem)
|
||||
#> # A tibble: 35 × 7
|
||||
#> bacteria GEN TOB AMK KAN IPM MEM
|
||||
#> <chr> <sir> <sir> <sir> <sir> <sir> <sir>
|
||||
#> 1 Pseudomonas aer… I S NA R S NA
|
||||
#> 2 Pseudomonas aer… I S NA R S NA
|
||||
#> 3 Pseudomonas aer… I S NA R S NA
|
||||
#> 4 Pseudomonas aer… S S S R NA S
|
||||
#> 5 Pseudomonas aer… S S S R S S
|
||||
#> 6 Pseudomonas aer… S S S R S S
|
||||
#> 7 Stenotrophomona… R R R R R R
|
||||
#> 8 Pseudomonas aer… S S S R NA S
|
||||
#> 9 Pseudomonas aer… S S S R NA S
|
||||
#> 10 Pseudomonas aer… S S S R S S
|
||||
#> bacteria GEN TOB AMK KAN IPM MEM
|
||||
#> <chr> <sir> <sir> <sir> <sir> <sir> <sir>
|
||||
#> 1 Pseudomonas aeruginosa I S NA R S NA
|
||||
#> 2 Pseudomonas aeruginosa I S NA R S NA
|
||||
#> 3 Pseudomonas aeruginosa I S NA R S NA
|
||||
#> 4 Pseudomonas aeruginosa S S S R NA S
|
||||
#> 5 Pseudomonas aeruginosa S S S R S S
|
||||
#> 6 Pseudomonas aeruginosa S S S R S S
|
||||
#> 7 Stenotrophomonas maltophilia R R R R R R
|
||||
#> 8 Pseudomonas aeruginosa S S S R NA S
|
||||
#> 9 Pseudomonas aeruginosa S S S R NA S
|
||||
#> 10 Pseudomonas aeruginosa S S S R S S
|
||||
#> # ℹ 25 more rows
|
||||
```
|
||||
|
||||
@@ -214,24 +215,23 @@ output format automatically (such as markdown, LaTeX, HTML, etc.).
|
||||
``` r
|
||||
antibiogram(example_isolates,
|
||||
antimicrobials = c(aminoglycosides(), carbapenems()))
|
||||
#> ℹ For `aminoglycosides()` using columns GEN (gentamicin), TOB
|
||||
#> (tobramycin), AMK (amikacin), and KAN (kanamycin)
|
||||
#> ℹ For `carbapenems()` using columns IPM (imipenem) and MEM
|
||||
#> (meropenem)
|
||||
#> ℹ For `aminoglycosides()` using columns GEN (gentamicin), TOB (tobramycin), AMK
|
||||
#> (amikacin), and KAN (kanamycin)
|
||||
#> ℹ For `carbapenems()` using columns IPM (imipenem) and MEM (meropenem)
|
||||
```
|
||||
|
||||
| Pathogen | Amikacin | Gentamicin | Imipenem | Kanamycin | Meropenem | Tobramycin |
|
||||
|:-----------------|:---------------------|:--------------------|:---------------------|:----------------|:---------------------|:--------------------|
|
||||
| CoNS | 0% (0-8%,N=43) | 86% (82-90%,N=309) | 52% (37-67%,N=48) | 0% (0-8%,N=43) | 52% (37-67%,N=48) | 22% (12-35%,N=55) |
|
||||
| *E. coli* | 100% (98-100%,N=171) | 98% (96-99%,N=460) | 100% (99-100%,N=422) | NA | 100% (99-100%,N=418) | 97% (96-99%,N=462) |
|
||||
| *E. faecalis* | 0% (0-9%,N=39) | 0% (0-9%,N=39) | 100% (91-100%,N=38) | 0% (0-9%,N=39) | NA | 0% (0-9%,N=39) |
|
||||
| *K. pneumoniae* | NA | 90% (79-96%,N=58) | 100% (93-100%,N=51) | NA | 100% (93-100%,N=53) | 90% (79-96%,N=58) |
|
||||
| *P. aeruginosa* | NA | 100% (88-100%,N=30) | NA | 0% (0-12%,N=30) | NA | 100% (88-100%,N=30) |
|
||||
| *P. mirabilis* | NA | 94% (80-99%,N=34) | 94% (79-99%,N=32) | NA | NA | 94% (80-99%,N=34) |
|
||||
| *S. aureus* | NA | 99% (97-100%,N=233) | NA | NA | NA | 98% (92-100%,N=86) |
|
||||
| *S. epidermidis* | 0% (0-8%,N=44) | 79% (71-85%,N=163) | NA | 0% (0-8%,N=44) | NA | 51% (40-61%,N=89) |
|
||||
| *S. hominis* | NA | 92% (84-97%,N=80) | NA | NA | NA | 85% (74-93%,N=62) |
|
||||
| *S. pneumoniae* | 0% (0-3%,N=117) | 0% (0-3%,N=117) | NA | 0% (0-3%,N=117) | NA | 0% (0-3%,N=117) |
|
||||
| Pathogen | Amikacin | Gentamicin | Imipenem | Kanamycin | Meropenem | Tobramycin |
|
||||
|:---|:---|:---|:---|:---|:---|:---|
|
||||
| CoNS | 0% (0-8%,N=43) | 86% (82-90%,N=309) | 52% (37-67%,N=48) | 0% (0-8%,N=43) | 52% (37-67%,N=48) | 22% (12-35%,N=55) |
|
||||
| *E. coli* | 100% (98-100%,N=171) | 98% (96-99%,N=460) | 100% (99-100%,N=422) | NA | 100% (99-100%,N=418) | 97% (96-99%,N=462) |
|
||||
| *E. faecalis* | 0% (0-9%,N=39) | 0% (0-9%,N=39) | 100% (91-100%,N=38) | 0% (0-9%,N=39) | NA | 0% (0-9%,N=39) |
|
||||
| *K. pneumoniae* | NA | 90% (79-96%,N=58) | 100% (93-100%,N=51) | NA | 100% (93-100%,N=53) | 90% (79-96%,N=58) |
|
||||
| *P. aeruginosa* | NA | 100% (88-100%,N=30) | NA | 0% (0-12%,N=30) | NA | 100% (88-100%,N=30) |
|
||||
| *P. mirabilis* | NA | 94% (80-99%,N=34) | 94% (79-99%,N=32) | NA | NA | 94% (80-99%,N=34) |
|
||||
| *S. aureus* | NA | 99% (97-100%,N=233) | NA | NA | NA | 98% (92-100%,N=86) |
|
||||
| *S. epidermidis* | 0% (0-8%,N=44) | 79% (71-85%,N=163) | NA | 0% (0-8%,N=44) | NA | 51% (40-61%,N=89) |
|
||||
| *S. hominis* | NA | 92% (84-97%,N=80) | NA | NA | NA | 85% (74-93%,N=62) |
|
||||
| *S. pneumoniae* | 0% (0-3%,N=117) | 0% (0-3%,N=117) | NA | 0% (0-3%,N=117) | NA | 0% (0-3%,N=117) |
|
||||
|
||||
In combination antibiograms, it is clear that combined antimicrobials
|
||||
yield higher empiric coverage:
|
||||
@@ -242,10 +242,10 @@ antibiogram(example_isolates,
|
||||
mo_transform = "gramstain")
|
||||
```
|
||||
|
||||
| Pathogen | Piperacillin/tazobactam | Piperacillin/tazobactam + Gentamicin | Piperacillin/tazobactam + Tobramycin |
|
||||
|:--------------|:------------------------|:-------------------------------------|:-------------------------------------|
|
||||
| Gram-negative | 88% (85-91%,N=641) | 99% (97-99%,N=691) | 98% (97-99%,N=693) |
|
||||
| Gram-positive | 86% (82-89%,N=345) | 98% (96-98%,N=1044) | 95% (93-97%,N=550) |
|
||||
| Pathogen | Piperacillin/tazobactam | Piperacillin/tazobactam + Gentamicin | Piperacillin/tazobactam + Tobramycin |
|
||||
|:---|:---|:---|:---|
|
||||
| Gram-negative | 88% (85-91%,N=641) | 99% (97-99%,N=691) | 98% (97-99%,N=693) |
|
||||
| Gram-positive | 86% (82-89%,N=345) | 98% (96-98%,N=1044) | 95% (93-97%,N=550) |
|
||||
|
||||
Like many other functions in this package, `antibiogram()` comes with
|
||||
support for 28 languages that are often detected automatically based on
|
||||
@@ -318,18 +318,16 @@ example_isolates %>%
|
||||
summarise(across(c(GEN, TOB),
|
||||
list(total_R = resistance,
|
||||
conf_int = function(x) sir_confidence_interval(x, collapse = "-"))))
|
||||
#> ℹ `resistance()` assumes the EUCAST guideline and thus
|
||||
#> considers the 'I' category susceptible. Set the `guideline`
|
||||
#> argument or the `AMR_guideline` option to either "CLSI" or
|
||||
#> "EUCAST", see `?AMR-options`.
|
||||
#> ℹ `resistance()` assumes the EUCAST guideline and thus considers the 'I'
|
||||
#> category susceptible. Set the `guideline` argument or the `AMR_guideline`
|
||||
#> option to either "CLSI" or "EUCAST", see `?AMR-options`.
|
||||
#> ℹ This message will be shown once per session.
|
||||
#> # A tibble: 3 × 5
|
||||
#> ward GEN_total_R GEN_conf_int TOB_total_R
|
||||
#> <chr> <dbl> <chr> <dbl>
|
||||
#> 1 Clinical 0.229 0.205-0.254 0.315
|
||||
#> 2 ICU 0.290 0.253-0.33 0.400
|
||||
#> 3 Outpatient 0.2 0.131-0.285 0.368
|
||||
#> # ℹ 1 more variable: TOB_conf_int <chr>
|
||||
#> ward GEN_total_R GEN_conf_int TOB_total_R TOB_conf_int
|
||||
#> <chr> <dbl> <chr> <dbl> <chr>
|
||||
#> 1 Clinical 0.229 0.205-0.254 0.315 0.284-0.347
|
||||
#> 2 ICU 0.290 0.253-0.33 0.400 0.353-0.449
|
||||
#> 3 Outpatient 0.2 0.131-0.285 0.368 0.254-0.493
|
||||
```
|
||||
|
||||
Or use [antimicrobial
|
||||
@@ -346,16 +344,15 @@ out <- example_isolates %>%
|
||||
# calculate AMR using resistance(), over all aminoglycosides and polymyxins:
|
||||
summarise(across(c(aminoglycosides(), polymyxins()),
|
||||
resistance))
|
||||
#> ℹ For `aminoglycosides()` using columns GEN (gentamicin), TOB
|
||||
#> (tobramycin), AMK (amikacin), and KAN (kanamycin)
|
||||
#> ℹ For `aminoglycosides()` using columns GEN (gentamicin), TOB (tobramycin), AMK
|
||||
#> (amikacin), and KAN (kanamycin)
|
||||
#> ℹ For `polymyxins()` using column COL (colistin)
|
||||
#> Warning: There was 1 warning in `summarise()`.
|
||||
#> ℹ In argument: `across(c(aminoglycosides(), polymyxins()),
|
||||
#> resistance)`.
|
||||
#> ℹ In argument: `across(c(aminoglycosides(), polymyxins()), resistance)`.
|
||||
#> ℹ In group 3: `ward = "Outpatient"`.
|
||||
#> Caused by warning:
|
||||
#> ! Introducing NA: only 23 results available for KAN in group:
|
||||
#> ward = "Outpatient" (whilst `minimum = 30`).
|
||||
#> ! Introducing NA: only 23 results available for KAN in group: ward = "Outpatient"
|
||||
#> (whilst `minimum = 30`).
|
||||
out
|
||||
#> # A tibble: 3 × 6
|
||||
#> ward GEN TOB AMK KAN COL
|
||||
@@ -369,12 +366,11 @@ out
|
||||
# transform the antibiotic columns to names:
|
||||
out %>% set_ab_names()
|
||||
#> # A tibble: 3 × 6
|
||||
#> ward gentamicin tobramycin amikacin kanamycin
|
||||
#> <chr> <dbl> <dbl> <dbl> <dbl>
|
||||
#> 1 Clinical 0.229 0.315 0.626 1
|
||||
#> 2 ICU 0.290 0.400 0.662 1
|
||||
#> 3 Outpatient 0.2 0.368 0.605 NA
|
||||
#> # ℹ 1 more variable: colistin <dbl>
|
||||
#> ward gentamicin tobramycin amikacin kanamycin colistin
|
||||
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
|
||||
#> 1 Clinical 0.229 0.315 0.626 1 0.780
|
||||
#> 2 ICU 0.290 0.400 0.662 1 0.857
|
||||
#> 3 Outpatient 0.2 0.368 0.605 NA 0.889
|
||||
```
|
||||
|
||||
``` r
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
% Please edit documentation in R/zz_deprecated.R
|
||||
\name{AMR-deprecated}
|
||||
\alias{AMR-deprecated}
|
||||
\alias{custom_eucast_rules}
|
||||
\alias{ab_class}
|
||||
\alias{ab_selector}
|
||||
\title{Deprecated Functions, Arguments, or Datasets}
|
||||
\usage{
|
||||
custom_eucast_rules(...)
|
||||
|
||||
ab_class(...)
|
||||
|
||||
ab_selector(...)
|
||||
|
||||
@@ -12,7 +12,7 @@ This is an overview of all the package-specific options you can set in the \code
|
||||
|
||||
\itemize{
|
||||
\item \code{AMR_antibiogram_formatting_type} \cr A \link{numeric} (1-22) to use in \code{\link[=antibiogram]{antibiogram()}}, to indicate which formatting type to use.
|
||||
\item \code{AMR_breakpoint_type} \cr A \link{character} to use in \code{\link[=as.sir]{as.sir()}}, to indicate which breakpoint type to use. This must be either \code{"ECOFF"}, \code{"animal"}, or \code{"human"}.
|
||||
\item \code{AMR_breakpoint_type} \cr A \link{character} to use in \code{\link[=as.sir]{as.sir()}}, to indicate which breakpoint type to use. This must be either {.val ECOFF}, {.val animal}, or {.val human}.
|
||||
\item \code{AMR_capped_mic_handling} \cr A \link{character} to use in \code{\link[=as.sir]{as.sir()}}, to indicate how capped MIC values (\code{<}, \code{<=}, \code{>}, \code{>=}) should be interpreted. Must be one of \code{"none"}, \code{"conservative"}, \code{"standard"}, or \code{"lenient"} - the default is \code{"conservative"}.
|
||||
\item \code{AMR_cleaning_regex} \cr A \link[base:regex]{regular expression} (case-insensitive) to use in \code{\link[=as.mo]{as.mo()}} and all \code{\link[=mo_property]{mo_*}} functions, to clean the user input. The default is the outcome of \code{\link[=mo_cleaning_regex]{mo_cleaning_regex()}}, which removes texts between brackets and texts such as "species" and "serovar".
|
||||
\item \code{AMR_custom_ab} \cr A file location to an RDS file, to use custom antimicrobial drugs with this package. This is explained in \code{\link[=add_custom_antimicrobials]{add_custom_antimicrobials()}}.
|
||||
|
||||
@@ -67,7 +67,7 @@ set_ab_names(data, ..., property = "name", language = get_AMR_locale(),
|
||||
|
||||
\item{open}{Browse the URL using \code{\link[utils:browseURL]{utils::browseURL()}}.}
|
||||
|
||||
\item{property}{One of the column names of one of the \link{antimicrobials} data set: \code{"ab"}, \code{"cid"}, \code{"name"}, \code{"group"}, \code{"atc"}, \code{"atc_group1"}, \code{"atc_group2"}, \code{"abbreviations"}, \code{"synonyms"}, \code{"oral_ddd"}, \code{"oral_units"}, \code{"iv_ddd"}, \code{"iv_units"}, or \code{"loinc"}.}
|
||||
\item{property}{One of the column names of one of the \link{antimicrobials} data set: \code{vector_or(colnames(antimicrobials), sort = FALSE)}.}
|
||||
|
||||
\item{data}{A \link{data.frame} of which the columns need to be renamed, or a \link{character} vector of column names.}
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ These steps integrate with \code{recipes::recipe()} and work like standard prepr
|
||||
}
|
||||
\examples{
|
||||
if (require("tidymodels")) {
|
||||
|
||||
# The below approach formed the basis for this paper: DOI 10.3389/fmicb.2025.1582703
|
||||
# Presence of ESBL genes was predicted based on raw MIC values.
|
||||
|
||||
@@ -91,10 +92,13 @@ if (require("tidymodels")) {
|
||||
|
||||
# Create and prep a recipe with MIC log2 transformation
|
||||
mic_recipe <- recipe(esbl ~ ., data = training_data) \%>\%
|
||||
|
||||
# Optionally remove non-predictive variables
|
||||
remove_role(genus, old_role = "predictor") \%>\%
|
||||
|
||||
# Apply the log2 transformation to all MIC predictors
|
||||
step_mic_log2(all_mic_predictors()) \%>\%
|
||||
|
||||
# And apply the preparation steps
|
||||
prep()
|
||||
|
||||
@@ -115,15 +119,13 @@ if (require("tidymodels")) {
|
||||
bind_cols(out_testing)
|
||||
|
||||
# Evaluate predictions using standard classification metrics
|
||||
our_metrics <- metric_set(
|
||||
accuracy,
|
||||
recall,
|
||||
precision,
|
||||
sensitivity,
|
||||
specificity,
|
||||
ppv,
|
||||
npv
|
||||
)
|
||||
our_metrics <- metric_set(accuracy,
|
||||
recall,
|
||||
precision,
|
||||
sensitivity,
|
||||
specificity,
|
||||
ppv,
|
||||
npv)
|
||||
metrics <- our_metrics(predictions, truth = esbl, estimate = .pred_class)
|
||||
|
||||
# Show performance
|
||||
|
||||
@@ -25,8 +25,7 @@ antibiogram(x, antimicrobials = where(is.sir), mo_transform = "shortname",
|
||||
ifelse(wisca, 14, 18)), col_mo = NULL, language = get_AMR_locale(),
|
||||
minimum = 30, combine_SI = TRUE, sep = " + ", sort_columns = TRUE,
|
||||
wisca = FALSE, simulations = 1000, conf_interval = 0.95,
|
||||
interval_side = "two-tailed", info = interactive(), parallel = FALSE,
|
||||
...)
|
||||
interval_side = "two-tailed", info = interactive(), ...)
|
||||
|
||||
wisca(x, antimicrobials = where(is.sir), ab_transform = "name",
|
||||
syndromic_group = NULL, only_all_tested = FALSE, digits = 1,
|
||||
@@ -34,7 +33,7 @@ wisca(x, antimicrobials = where(is.sir), ab_transform = "name",
|
||||
col_mo = NULL, language = get_AMR_locale(), combine_SI = TRUE,
|
||||
sep = " + ", sort_columns = TRUE, simulations = 1000,
|
||||
conf_interval = 0.95, interval_side = "two-tailed",
|
||||
info = interactive(), parallel = FALSE, ...)
|
||||
info = interactive(), ...)
|
||||
|
||||
retrieve_wisca_parameters(wisca_model, ...)
|
||||
|
||||
@@ -69,9 +68,9 @@ retrieve_wisca_parameters(wisca_model, ...)
|
||||
}
|
||||
}}
|
||||
|
||||
\item{mo_transform}{A character to transform microorganism input - must be \code{"name"}, \code{"shortname"} (default), \code{"gramstain"}, or one of the column names of the \link{microorganisms} data set: \code{"mo"}, \code{"fullname"}, \code{"status"}, \code{"kingdom"}, \code{"phylum"}, \code{"class"}, \code{"order"}, \code{"family"}, \code{"genus"}, \code{"species"}, \code{"subspecies"}, \code{"rank"}, \code{"ref"}, \code{"oxygen_tolerance"}, \code{"source"}, \code{"lpsn"}, \code{"lpsn_parent"}, \code{"lpsn_renamed_to"}, \code{"mycobank"}, \code{"mycobank_parent"}, \code{"mycobank_renamed_to"}, \code{"gbif"}, \code{"gbif_parent"}, \code{"gbif_renamed_to"}, \code{"prevalence"}, or \code{"snomed"}. Can also be \code{NULL} to not transform the input or \code{NA} to consider all microorganisms 'unknown'.}
|
||||
\item{mo_transform}{A character to transform microorganism input - must be \code{"name"}, \code{"shortname"} (default), \code{"gramstain"}, or one of the column names of the \link{microorganisms} data set: {.val mo}, {.val fullname}, {.val status}, {.val kingdom}, {.val phylum}, {.val class}, {.val order}, {.val family}, {.val genus}, {.val species}, {.val subspecies}, {.val rank}, {.val ref}, {.val oxygen_tolerance}, {.val source}, {.val lpsn}, {.val lpsn_parent}, {.val lpsn_renamed_to}, {.val mycobank}, {.val mycobank_parent}, {.val mycobank_renamed_to}, {.val gbif}, {.val gbif_parent}, {.val gbif_renamed_to}, {.val prevalence}, or {.val snomed}. Can also be \code{NULL} to not transform the input or \code{NA} to consider all microorganisms 'unknown'.}
|
||||
|
||||
\item{ab_transform}{A character to transform antimicrobial input - must be one of the column names of the \link{antimicrobials} data set (defaults to \code{"name"}): \code{"ab"}, \code{"cid"}, \code{"name"}, \code{"group"}, \code{"atc"}, \code{"atc_group1"}, \code{"atc_group2"}, \code{"abbreviations"}, \code{"synonyms"}, \code{"oral_ddd"}, \code{"oral_units"}, \code{"iv_ddd"}, \code{"iv_units"}, or \code{"loinc"}. Can also be \code{NULL} to not transform the input.}
|
||||
\item{ab_transform}{A character to transform antimicrobial input - must be one of the column names of the \link{antimicrobials} data set (defaults to \code{"name"}): {.val ab}, {.val cid}, {.val name}, {.val group}, {.val atc}, {.val atc_group1}, {.val atc_group2}, {.val abbreviations}, {.val synonyms}, {.val oral_ddd}, {.val oral_units}, {.val iv_ddd}, {.val iv_units}, or {.val loinc}. Can also be \code{NULL} to not transform the input.}
|
||||
|
||||
\item{syndromic_group}{A column name of \code{x}, or values calculated to split rows of \code{x}, e.g. by using \code{\link[=ifelse]{ifelse()}} or \code{\link[dplyr:case-and-replace-when]{case_when()}}. See \emph{Examples}.}
|
||||
|
||||
@@ -81,7 +80,7 @@ retrieve_wisca_parameters(wisca_model, ...)
|
||||
|
||||
\item{digits}{Number of digits to use for rounding the antimicrobial coverage, defaults to 1 for WISCA and 0 otherwise.}
|
||||
|
||||
\item{formatting_type}{Numeric value (1-22 for WISCA, 1-12 for non-WISCA) indicating how the 'cells' of the antibiogram table should be formatted. See \emph{Details} > \emph{Formatting Type} for a list of options.}
|
||||
\item{formatting_type}{Numeric value (1–22 for WISCA, 1-12 for non-WISCA) indicating how the 'cells' of the antibiogram table should be formatted. See \emph{Details} > \emph{Formatting Type} for a list of options.}
|
||||
|
||||
\item{col_mo}{Column name of the names or codes of the microorganisms (see \code{\link[=as.mo]{as.mo()}}) - the default is the first column of class \code{\link{mo}}. Values will be coerced using \code{\link[=as.mo]{as.mo()}}.}
|
||||
|
||||
@@ -105,8 +104,6 @@ retrieve_wisca_parameters(wisca_model, ...)
|
||||
|
||||
\item{info}{A \link{logical} to indicate info should be printed - the default is \code{TRUE} only in interactive mode.}
|
||||
|
||||
\item{parallel}{A \link{logical} to indicate if parallel computing must be used, defaults to \code{FALSE}. Requires the \code{\link[future.apply:future_lapply]{future.apply}} package. For WISCA, Monte Carlo simulations are distributed across workers; for grouped antibiograms, each group is processed by a separate worker. \strong{A non-sequential \code{\link[future:plan]{future::plan()}} must already be active before setting \code{parallel = TRUE}} -- for example, \code{future::plan(future::multisession)}. An error is thrown if \code{parallel = TRUE} is used without a plan set by the user.}
|
||||
|
||||
\item{...}{When used in \link[knitr:kable]{R Markdown or Quarto}: arguments passed on to \code{\link[knitr:kable]{knitr::kable()}} (otherwise, has no use).}
|
||||
|
||||
\item{wisca_model}{The outcome of \code{\link[=wisca]{wisca()}} or \code{\link[=antibiogram]{antibiogram(..., wisca = TRUE)}}.}
|
||||
|
||||
@@ -157,7 +157,7 @@ not_intrinsic_resistant(only_sir_columns = FALSE, col_mo = NULL,
|
||||
|
||||
\item{col_mo}{Column name of the names or codes of the microorganisms (see \code{\link[=as.mo]{as.mo()}}) - the default is the first column of class \code{\link{mo}}. Values will be coerced using \code{\link[=as.mo]{as.mo()}}.}
|
||||
|
||||
\item{version_expected_phenotypes}{The version number to use for the EUCAST Expected Phenotypes. Can be \code{"1.2"}.}
|
||||
\item{version_expected_phenotypes}{The version number to use for the EUCAST Expected Phenotypes. Can be {.val 1.2}.}
|
||||
}
|
||||
\value{
|
||||
When used inside selecting or filtering, this returns a \link{character} vector of column names, with additional class \code{"amr_selector"}. When used individually, this returns an \link[=as.ab]{'ab' vector} with all possible antimicrobials that the function would be able to select or filter.
|
||||
|
||||
@@ -73,7 +73,7 @@ is_sir_eligible(x, threshold = 0.05)
|
||||
include_PKPD = getOption("AMR_include_PKPD", TRUE),
|
||||
breakpoint_type = getOption("AMR_breakpoint_type", "human"), host = NULL,
|
||||
language = get_AMR_locale(), verbose = FALSE, info = interactive(),
|
||||
parallel = FALSE, conserve_capped_values = NULL)
|
||||
parallel = FALSE, max_cores = -1, conserve_capped_values = NULL)
|
||||
|
||||
sir_interpretation_history(clean = FALSE)
|
||||
}
|
||||
@@ -130,7 +130,7 @@ The default \code{"conservative"} setting ensures cautious handling of uncertain
|
||||
|
||||
\item{add_intrinsic_resistance}{\emph{(only useful when using a EUCAST guideline)} a \link{logical} to indicate whether intrinsic antibiotic resistance must also be considered for applicable bug-drug combinations, meaning that e.g. ampicillin will always return "R" in \emph{Klebsiella} species. Determination is based on the \link{intrinsic_resistant} data set, that itself is based on \href{https://www.eucast.org/bacteria/important-additional-information/expert-rules/}{'EUCAST Expert Rules' and 'EUCAST Intrinsic Resistance and Unusual Phenotypes' v3.3} (2021).}
|
||||
|
||||
\item{reference_data}{A \link{data.frame} to be used for interpretation, which defaults to the \link{clinical_breakpoints} data set. Changing this argument allows for using own interpretation guidelines. This argument must have the same column names as the \link{clinical_breakpoints} data set. Column types are coerced automatically where possible: the \code{mo} column is passed through \code{\link[=as.mo]{as.mo()}}, the \code{ab} column through \code{\link[=as.ab]{as.ab()}}, and plain character, numeric, or logical columns are cast to the expected type. When \code{reference_data} is manually set, the \code{guideline} argument is optional: if omitted (or if its value does not match any row in the custom data), all rows in \code{reference_data} are considered. If \code{guideline} is set to a value that exists in the \code{guideline} column of the custom data, only matching rows are used — useful when a single custom table contains multiple guidelines. For the R classification, the EUCAST convention is used by default: MIC values \verb{> breakpoint_R} and disk diffusion values \verb{< breakpoint_R} are classified as R, with values between \code{breakpoint_S} and \code{breakpoint_R} classified as I (or SDD). Only when using the standard \link{clinical_breakpoints} with a CLSI guideline are the closed-interval rules (\verb{>= breakpoint_R} for MIC, \verb{<= breakpoint_R} for disk) applied; custom \code{reference_data} always uses the open-interval (EUCAST) convention regardless of the guideline name.}
|
||||
\item{reference_data}{A \link{data.frame} to be used for interpretation, which defaults to the \link{clinical_breakpoints} 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{clinical_breakpoints} 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{substitute_missing_r_breakpoint}{A \link{logical} to indicate that a missing clinical breakpoints for R (resistant) must be substituted with R - the default is \code{FALSE}. Some (especially CLSI) breakpoints only have a breakpoint for S, meaning that the outcome can only be \code{"S"} or \code{NA}. Setting this to \code{TRUE} will convert the \code{NA}s in these cases to \code{"R"}. Can also be set with the package option \code{\link[=AMR-options]{AMR_substitute_missing_r_breakpoint}}.}
|
||||
|
||||
@@ -138,7 +138,7 @@ The default \code{"conservative"} setting ensures cautious handling of uncertain
|
||||
|
||||
\item{include_PKPD}{A \link{logical} to indicate that PK/PD clinical breakpoints must be applied as a last resort - the default is \code{TRUE}. Can also be set with the package option \code{\link[=AMR-options]{AMR_include_PKPD}}.}
|
||||
|
||||
\item{breakpoint_type}{The type of breakpoints to use, either \code{"ECOFF"}, \code{"animal"}, or \code{"human"}. ECOFF stands for Epidemiological Cut-Off values. The default is \code{"human"}, which can also be set with the package option \code{\link[=AMR-options]{AMR_breakpoint_type}}. If \code{host} is set to values of veterinary species, this will automatically be set to \code{"animal"}.}
|
||||
\item{breakpoint_type}{The type of breakpoints to use, either {.val ECOFF}, {.val animal}, or {.val human}. ECOFF stands for Epidemiological Cut-Off values. The default is \code{"human"}, which can also be set with the package option \code{\link[=AMR-options]{AMR_breakpoint_type}}. If \code{host} is set to values of veterinary species, this will automatically be set to \code{"animal"}.}
|
||||
|
||||
\item{host}{A vector (or column name) with \link{character}s to indicate the host. Only useful for veterinary breakpoints, as it requires \code{breakpoint_type = "animal"}. The values can be any text resembling the animal species, even in any of the 28 supported languages of this package. For foreign languages, be sure to set the language with \code{\link[=set_AMR_locale]{set_AMR_locale()}} (though it will be automatically guessed based on the system language).}
|
||||
|
||||
@@ -150,7 +150,9 @@ The default \code{"conservative"} setting ensures cautious handling of uncertain
|
||||
|
||||
\item{col_mo}{Column name of the names or codes of the microorganisms (see \code{\link[=as.mo]{as.mo()}}) - the default is the first column of class \code{\link{mo}}. Values will be coerced using \code{\link[=as.mo]{as.mo()}}.}
|
||||
|
||||
\item{parallel}{A \link{logical} to indicate if parallel computing must be used, defaults to \code{FALSE}. Requires the \code{\link[future.apply:future_lapply]{future.apply}} package. \strong{A non-sequential \code{\link[future:plan]{future::plan()}} must already be active before setting \code{parallel = TRUE}} — for example, \code{future::plan(future::multisession)}. An error is thrown if \code{parallel = TRUE} is used without a plan set by the user. Parallelism distributes columns (and optionally row batches) across workers; it is most beneficial when there are many antibiotic columns and a large number of rows.}
|
||||
\item{parallel}{A \link{logical} to indicate if parallel computing must be used, defaults to \code{FALSE}. This requires no additional packages, as the used \code{parallel} package is part of base \R. On Windows and on \R < 4.0.0 \code{\link[parallel:clusterApply]{parallel::parLapply()}} will be used, in all other cases the more efficient \code{\link[parallel:mclapply]{parallel::mclapply()}} will be used.}
|
||||
|
||||
\item{max_cores}{Maximum number of cores to use if \code{parallel = TRUE}. Use a negative value to subtract that number from the available number of cores, e.g. a value of \code{-2} on an 8-core machine means that at most 6 cores will be used. Defaults to \code{-1}. There will never be used more cores than variables to analyse. The available number of cores are detected using \code{\link[parallelly:availableCores]{parallelly::availableCores()}} if that package is installed, and base \R's \code{\link[parallel:detectCores]{parallel::detectCores()}} otherwise.}
|
||||
|
||||
\item{clean}{A \link{logical} to indicate whether previously stored results should be forgotten after returning the 'logbook' with results.}
|
||||
}
|
||||
@@ -181,7 +183,7 @@ your_data \%>\% mutate_if(is.mic, as.sir, ab = c("cipro", "ampicillin", ...), mo
|
||||
# for veterinary breakpoints, also set `host`:
|
||||
your_data \%>\% mutate_if(is.mic, as.sir, host = "column_with_animal_species", guideline = "CLSI")
|
||||
|
||||
# fast processing with parallel computing (requires future.apply):
|
||||
# fast processing with parallel computing:
|
||||
as.sir(your_data, ..., parallel = TRUE)
|
||||
}\if{html}{\out{</div>}}
|
||||
\item Operators like "<=" will be considered according to the \code{capped_mic_handling} setting. At default, an MIC value of e.g. ">2" will return "NI" (non-interpretable) if the breakpoint is 4-8; the \emph{true} MIC could be at either side of the breakpoint. This is to prevent that capped values from raw laboratory data would not be treated conservatively.
|
||||
@@ -199,7 +201,7 @@ your_data \%>\% mutate_if(is.disk, as.sir, ab = c("cipro", "ampicillin", ...), m
|
||||
# for veterinary breakpoints, also set `host`:
|
||||
your_data \%>\% mutate_if(is.disk, as.sir, host = "column_with_animal_species", guideline = "CLSI")
|
||||
|
||||
# fast processing with parallel computing (requires future.apply):
|
||||
# fast processing with parallel computing:
|
||||
as.sir(your_data, ..., parallel = TRUE)
|
||||
}\if{html}{\out{</div>}}
|
||||
}
|
||||
@@ -311,6 +313,9 @@ as.sir(df_wide)
|
||||
sir_interpretation_history()
|
||||
|
||||
\donttest{
|
||||
# using parallel computing, which is available in base R:
|
||||
as.sir(df_wide, parallel = TRUE, info = TRUE)
|
||||
|
||||
|
||||
## Using dplyr -------------------------------------------------
|
||||
if (require("dplyr")) {
|
||||
|
||||
@@ -52,7 +52,7 @@ av_property(x, property = "name", language = get_AMR_locale(), ...)
|
||||
|
||||
\item{open}{Browse the URL using \code{\link[utils:browseURL]{utils::browseURL()}}.}
|
||||
|
||||
\item{property}{One of the column names of one of the \link{antivirals} data set: \code{"av"}, \code{"name"}, \code{"atc"}, \code{"cid"}, \code{"atc_group"}, \code{"synonyms"}, \code{"oral_ddd"}, \code{"oral_units"}, \code{"iv_ddd"}, \code{"iv_units"}, or \code{"loinc"}.}
|
||||
\item{property}{One of the column names of one of the \link{antivirals} data set: \code{vector_or(colnames(antivirals), sort = FALSE)}.}
|
||||
}
|
||||
\value{
|
||||
\itemize{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/custom_interpretive_rules.R
|
||||
\name{custom_interpretive_rules}
|
||||
\alias{custom_interpretive_rules}
|
||||
\title{Define Custom Interpretive Rules}
|
||||
% Please edit documentation in R/custom_eucast_rules.R
|
||||
\name{custom_eucast_rules}
|
||||
\alias{custom_eucast_rules}
|
||||
\title{Define Custom EUCAST Rules}
|
||||
\usage{
|
||||
custom_interpretive_rules(...)
|
||||
custom_eucast_rules(...)
|
||||
}
|
||||
\arguments{
|
||||
\item{...}{Rules in \link[base:tilde]{formula} notation, see below for instructions, and in \emph{Examples}.}
|
||||
@@ -13,22 +13,22 @@ custom_interpretive_rules(...)
|
||||
A \link{list} containing the custom rules
|
||||
}
|
||||
\description{
|
||||
Define custom interpretive rules for your organisation or specific analysis and use the output of this function in \code{\link[=interpretive_rules]{interpretive_rules()}}.
|
||||
Define custom EUCAST rules for your organisation or specific analysis and use the output of this function in \code{\link[=eucast_rules]{eucast_rules()}}.
|
||||
}
|
||||
\details{
|
||||
Some organisations have their own adoption of interpretive rules. This function can be used to define custom rules to be used in the \code{\link[=interpretive_rules]{interpretive_rules()}} function.
|
||||
Some organisations have their own adoption of EUCAST rules. This function can be used to define custom EUCAST rules to be used in the \code{\link[=eucast_rules]{eucast_rules()}} function.
|
||||
\subsection{Basics}{
|
||||
|
||||
If you are familiar with the \code{\link[dplyr:case-and-replace-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_interpretive_rules(TZP == "S" ~ aminopenicillins == "S",
|
||||
TZP == "R" ~ aminopenicillins == "R")
|
||||
\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 interpretive 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:
|
||||
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 interpretive rules:
|
||||
#> A set of custom EUCAST rules:
|
||||
#>
|
||||
#> 1. If TZP is "S" then set to S :
|
||||
#> amoxicillin (AMX), ampicillin (AMP)
|
||||
@@ -48,11 +48,11 @@ df
|
||||
#> 1 Escherichia coli R S S
|
||||
#> 2 Klebsiella pneumoniae R S S
|
||||
|
||||
interpretive_rules(df,
|
||||
rules = "custom",
|
||||
custom_rules = x,
|
||||
info = FALSE,
|
||||
overwrite = TRUE)
|
||||
eucast_rules(df,
|
||||
rules = "custom",
|
||||
custom_rules = x,
|
||||
info = FALSE,
|
||||
overwrite = TRUE)
|
||||
#> mo TZP ampi cipro
|
||||
#> 1 Escherichia coli R R S
|
||||
#> 2 Klebsiella pneumoniae R R S
|
||||
@@ -63,16 +63,16 @@ interpretive_rules(df,
|
||||
|
||||
There is one exception in columns 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: \code{"mo"}, \code{"fullname"}, \code{"status"}, \code{"kingdom"}, \code{"phylum"}, \code{"class"}, \code{"order"}, \code{"family"}, \code{"genus"}, \code{"species"}, \code{"subspecies"}, \code{"rank"}, \code{"ref"}, \code{"oxygen_tolerance"}, \code{"source"}, \code{"lpsn"}, \code{"lpsn_parent"}, \code{"lpsn_renamed_to"}, \code{"mycobank"}, \code{"mycobank_parent"}, \code{"mycobank_renamed_to"}, \code{"gbif"}, \code{"gbif_parent"}, \code{"gbif_renamed_to"}, \code{"prevalence"}, and \code{"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}:
|
||||
|
||||
\if{html}{\out{<div class="sourceCode r">}}\preformatted{y <- custom_interpretive_rules(
|
||||
\if{html}{\out{<div class="sourceCode r">}}\preformatted{y <- custom_eucast_rules(
|
||||
TZP == "S" & genus == "Klebsiella" ~ aminopenicillins == "S",
|
||||
TZP == "R" & genus == "Klebsiella" ~ aminopenicillins == "R"
|
||||
)
|
||||
|
||||
interpretive_rules(df,
|
||||
rules = "custom",
|
||||
custom_rules = y,
|
||||
info = FALSE,
|
||||
overwrite = TRUE)
|
||||
eucast_rules(df,
|
||||
rules = "custom",
|
||||
custom_rules = y,
|
||||
info = FALSE,
|
||||
overwrite = TRUE)
|
||||
#> mo TZP ampi cipro
|
||||
#> 1 Escherichia coli R S S
|
||||
#> 2 Klebsiella pneumoniae R R S
|
||||
@@ -90,9 +90,9 @@ You can define antimicrobial groups instead of single antimicrobials for the rul
|
||||
|
||||
Rules can also be applied to multiple antimicrobials and antimicrobial groups simultaneously. Use the \code{c()} function to combine multiple antimicrobials. For instance, the following example sets all aminopenicillins and ureidopenicillins to "R" if column TZP (piperacillin/tazobactam) is "R":
|
||||
|
||||
\if{html}{\out{<div class="sourceCode r">}}\preformatted{x <- custom_interpretive_rules(TZP == "R" ~ c(aminopenicillins, ureidopenicillins) == "R")
|
||||
\if{html}{\out{<div class="sourceCode r">}}\preformatted{x <- custom_eucast_rules(TZP == "R" ~ c(aminopenicillins, ureidopenicillins) == "R")
|
||||
x
|
||||
#> A set of custom interpretive rules:
|
||||
#> A set of custom EUCAST rules:
|
||||
#>
|
||||
#> 1. If TZP is "R" then set to "R":
|
||||
#> amoxicillin (AMX), ampicillin (AMP), azlocillin (AZL), mezlocillin (MEZ), piperacillin (PIP), piperacillin/tazobactam (TZP)
|
||||
@@ -147,7 +147,7 @@ These 43 antimicrobial groups are allowed in the rules (case-insensitive) and ca
|
||||
}
|
||||
}
|
||||
\examples{
|
||||
x <- custom_interpretive_rules(
|
||||
x <- custom_eucast_rules(
|
||||
AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
|
||||
AMC == "I" & genus == "Klebsiella" ~ aminopenicillins == "I"
|
||||
)
|
||||
@@ -165,7 +165,7 @@ eucast_rules(example_isolates,
|
||||
# combine rule sets
|
||||
x2 <- c(
|
||||
x,
|
||||
custom_interpretive_rules(TZP == "R" ~ carbapenems == "R")
|
||||
custom_eucast_rules(TZP == "R" ~ carbapenems == "R")
|
||||
)
|
||||
x2
|
||||
}
|
||||
@@ -46,7 +46,7 @@ A list with class \code{"htest"} containing the following
|
||||
\code{(observed - expected) / sqrt(expected)}.}
|
||||
\item{stdres}{standardized residuals,
|
||||
\code{(observed - expected) / sqrt(V)}, where \code{V} is the
|
||||
residual cell variance {(\if{html}{\out{<a href="#reference+chisq.test.Rd+R+3AAgresti+3A2007" class="citation">}}Agresti 2007\if{html}{\out{</a>}}, section 2.4.5)}
|
||||
residual cell variance (Agresti, 2007, section 2.4.5
|
||||
for the case where \code{x} is a matrix, \code{n * p * (1 - p)} otherwise).}
|
||||
}
|
||||
\description{
|
||||
|
||||
@@ -42,9 +42,8 @@ ggplot_pca(x, choices = 1:2, scale = 1, pc.biplot = TRUE,
|
||||
}
|
||||
|
||||
\item{pc.biplot}{
|
||||
If true, use what {\if{html}{\cite{}\out{<a href="#reference+biplot.princomp.Rd+R+3AGabriel+3A1971" class="citation">}}Gabriel (1971)\if{html}{\out{</a>}}} refers to as a
|
||||
\dQuote{principal component biplot},
|
||||
with \code{lambda = 1} and observations scaled up by sqrt(n) and
|
||||
If true, use what Gabriel (1971) refers to as a "principal component
|
||||
biplot", with \code{lambda = 1} and observations scaled up by sqrt(n) and
|
||||
variables scaled down by sqrt(n). Then inner products between
|
||||
variables approximate covariances and distances between observations
|
||||
approximate Mahalanobis distance.
|
||||
|
||||
@@ -46,7 +46,7 @@ eucast_dosage(ab, administration = "iv", version_breakpoints = 15)
|
||||
|
||||
\item{info}{A \link{logical} to indicate whether progress should be printed to the console - the default is only print while in interactive sessions.}
|
||||
|
||||
\item{rules}{A \link{character} vector that specifies which rules should be applied. Must be one or more of \code{"breakpoints"}, \code{"expected_phenotypes"}, \code{"expert"}, \code{"other"}, \code{"custom"}, \code{"all"}, and defaults to \code{c("breakpoints", "expected_phenotypes")}. The default value can be set to another value using the package option \code{\link[=AMR-options]{AMR_interpretive_rules}}: \code{options(AMR_interpretive_rules = "all")}. If using \code{"custom"}, be sure to fill in argument \code{custom_rules} too. Custom rules can be created with \code{\link[=custom_interpretive_rules]{custom_interpretive_rules()}}.}
|
||||
\item{rules}{A \link{character} vector that specifies which rules should be applied. Must be one or more of \code{"breakpoints"}, \code{"expected_phenotypes"}, \code{"expert"}, \code{"other"}, \code{"custom"}, \code{"all"}, and defaults to \code{c("breakpoints", "expected_phenotypes")}. The default value can be set to another value using the package option \code{\link[=AMR-options]{AMR_interpretive_rules}}: \code{options(AMR_interpretive_rules = "all")}. If using \code{"custom"}, be sure to fill in argument \code{custom_rules} too. Custom rules can be created with \code{\link[=custom_eucast_rules]{custom_eucast_rules()}}.}
|
||||
|
||||
\item{guideline}{A guideline name, either "EUCAST" (default) or "CLSI". This can be set with the package option \code{\link[=AMR-options]{AMR_guideline}}.}
|
||||
|
||||
@@ -54,15 +54,15 @@ eucast_dosage(ab, administration = "iv", version_breakpoints = 15)
|
||||
|
||||
\item{version_breakpoints}{The version number to use for the EUCAST Clinical Breakpoints guideline. Can be \code{"16.0"}, \code{"15.0"}, \code{"14.0"}, \code{"13.1"}, \code{"12.0"}, \code{"11.0"}, or \code{"10.0"}.}
|
||||
|
||||
\item{version_expected_phenotypes}{The version number to use for the EUCAST Expected Phenotypes. Can be \code{"1.2"}.}
|
||||
\item{version_expected_phenotypes}{The version number to use for the EUCAST Expected Phenotypes. Can be {.val 1.2}.}
|
||||
|
||||
\item{version_expertrules}{The version number to use for the EUCAST Expert Rules and Intrinsic Resistance guideline. Can be \code{"3.3"}, \code{"3.2"}, or \code{"3.1"}.}
|
||||
\item{version_expertrules}{The version number to use for the EUCAST Expert Rules and Intrinsic Resistance guideline. Can be {.val 3.3}, {.val 3.2}, or {.val 3.1}.}
|
||||
|
||||
\item{ampc_cephalosporin_resistance}{(only applies when \code{rules} contains \code{"expert"} or \code{"all"}) a \link{character} value that should be applied to cefotaxime, ceftriaxone and ceftazidime for AmpC de-repressed cephalosporin-resistant mutants - the default is \code{NA}. Currently only works when \code{version_expertrules} is \code{3.2} and higher; these versions of '\emph{EUCAST Expert Rules on Enterobacterales}' state that results of cefotaxime, ceftriaxone and ceftazidime should be reported with a note, or results should be suppressed (emptied) for these three drugs. A value of \code{NA} (the default) for this argument will remove results for these three drugs, while e.g. a value of \code{"R"} will make the results for these drugs resistant. Use \code{NULL} or \code{FALSE} to not alter results for these three drugs of AmpC de-repressed cephalosporin-resistant mutants. Using \code{TRUE} is equal to using \code{"R"}. \cr For \emph{EUCAST Expert Rules} v3.2, this rule applies to: \emph{Citrobacter braakii}, \emph{Citrobacter freundii}, \emph{Citrobacter gillenii}, \emph{Citrobacter murliniae}, \emph{Citrobacter rodenticum}, \emph{Citrobacter sedlakii}, \emph{Citrobacter werkmanii}, \emph{Citrobacter youngae}, \emph{Enterobacter}, \emph{Hafnia alvei}, \emph{Klebsiella aerogenes}, \emph{Morganella morganii}, \emph{Providencia}, and \emph{Serratia}.}
|
||||
|
||||
\item{only_sir_columns}{A \link{logical} to indicate whether only antimicrobial columns must be included that were transformed to class \link[=as.sir]{sir} on beforehand. Defaults to \code{FALSE} if no columns of \code{x} have a class \link[=as.sir]{sir}.}
|
||||
|
||||
\item{custom_rules}{Custom rules to apply, created with \code{\link[=custom_interpretive_rules]{custom_interpretive_rules()}}.}
|
||||
\item{custom_rules}{Custom rules to apply, created with \code{\link[=custom_eucast_rules]{custom_eucast_rules()}}.}
|
||||
|
||||
\item{overwrite}{A \link{logical} indicating whether to overwrite existing SIR values (default: \code{FALSE}). When \code{FALSE}, only non-SIR values are modified (i.e., any value that is not already S, I or R). To ensure compliance with EUCAST guidelines, \strong{this should remain} \code{FALSE}, as EUCAST notes often state that an organism "should be tested for susceptibility to individual agents or be reported resistant".}
|
||||
|
||||
@@ -72,7 +72,7 @@ eucast_dosage(ab, administration = "iv", version_breakpoints = 15)
|
||||
|
||||
\item{ab}{Any (vector of) text that can be coerced to a valid antimicrobial drug code with \code{\link[=as.ab]{as.ab()}}.}
|
||||
|
||||
\item{administration}{Route of administration, either \code{""}, \code{"im"}, \code{"iv"}, \code{"oral"}, or NA.}
|
||||
\item{administration}{Route of administration, either {.val }, {.val im}, {.val iv}, {.val oral}, or NA.}
|
||||
}
|
||||
\value{
|
||||
The input of \code{x}, possibly with edited values of antimicrobials. Or, if \code{verbose = TRUE}, a \link{data.frame} with all original and new values of the affected bug-drug combinations.
|
||||
@@ -86,15 +86,15 @@ To improve the interpretation of the antibiogram before CLSI/EUCAST interpretive
|
||||
\strong{Note:} This function does not translate MIC or disk values to SIR values. Use \code{\link[=as.sir]{as.sir()}} 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 interpretive rules is located here: \url{https://github.com/msberends/AMR/blob/main/data-raw/interpretive_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 \code{AMR} package contains the full microbial taxonomy updated until June 24th, 2024, see \link{microorganisms}.
|
||||
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 \code{AMR} package contains the full microbial taxonomy updated until June 24th, 2024, see \link{microorganisms}.
|
||||
\subsection{Custom Rules}{
|
||||
|
||||
Custom rules can be created using \code{\link[=custom_interpretive_rules]{custom_interpretive_rules()}}, e.g.:
|
||||
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_interpretive_rules(AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
|
||||
AMC == "I" & genus == "Klebsiella" ~ aminopenicillins == "I")
|
||||
\if{html}{\out{<div class="sourceCode r">}}\preformatted{x <- custom_eucast_rules(AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
|
||||
AMC == "I" & genus == "Klebsiella" ~ aminopenicillins == "I")
|
||||
|
||||
interpretive_rules(example_isolates, rules = "custom", custom_rules = x)
|
||||
eucast_rules(example_isolates, rules = "custom", custom_rules = x)
|
||||
}\if{html}{\out{</div>}}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ Before further processing, two non-EUCAST rules about drug combinations can be a
|
||||
|
||||
Important examples include amoxicillin and amoxicillin/clavulanic acid, and trimethoprim and trimethoprim/sulfamethoxazole. Needless to say, for these rules to work, both drugs must be available in the data set.
|
||||
|
||||
Since these rules are not officially approved by EUCAST, they are not applied at default. To use these rules, include \code{"other"} to the \code{rules} argument, or use \code{interpretive_rules(..., rules = "all")}. You can also set the package option \code{\link[=AMR-options]{AMR_interpretive_rules}}, i.e. run \code{options(AMR_interpretive_rules = "all")}.
|
||||
Since these rules are not officially approved by EUCAST, they are not applied at default. To use these rules, include \code{"other"} to the \code{rules} argument, or use \code{eucast_rules(..., rules = "all")}. You can also set the package option \code{\link[=AMR-options]{AMR_interpretive_rules}}, i.e. run \code{options(AMR_interpretive_rules = "all")}.
|
||||
}
|
||||
}
|
||||
\section{Download Our Reference Data}{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
\alias{intrinsic_resistant}
|
||||
\title{Data Set Denoting Bacterial Intrinsic Resistance}
|
||||
\format{
|
||||
A \link[tibble:tibble]{tibble} with 285 928 observations and 2 variables:
|
||||
A \link[tibble:tibble]{tibble} with 271 905 observations and 2 variables:
|
||||
\itemize{
|
||||
\item \code{mo}\cr Microorganism ID which occurs in \code{\link[=microorganisms]{microorganisms$mo}}. Names can be retrieved using \code{\link[=mo_name]{mo_name()}}.
|
||||
\item \code{ab}\cr Antimicrobial ID which occurs in \code{\link[=antimicrobials]{antimicrobials$ab}}. Names can be retrieved using \code{\link[=ab_name]{ab_name()}}.
|
||||
|
||||
@@ -119,7 +119,7 @@ The international guideline for multi-drug resistant tuberculosis - World Health
|
||||
The German national guideline - Mueller et al. (2015) Antimicrobial Resistance and Infection Control 4:7; \doi{10.1186/s13756-015-0047-6}
|
||||
\item \code{guideline = "BRMO 2024"} (or simply \code{guideline = "BRMO"})
|
||||
|
||||
The Dutch national guideline - Samenwerkingverband Richtlijnen Infectiepreventie (SRI) (2024) "Bijzonder Resistente Micro-Organismen (BRMO)" (\href{https://richtlijnendatabase.nl/richtlijn/bijzonder_resistente_micro-organismen_brmo}{link})
|
||||
The Dutch national guideline - Samenwerkingverband Richtlijnen Infectiepreventie (SRI) (2024) "Bijzonder Resistente Micro-Organismen (BRMO)" (\href{https://www.sri-richtlijnen.nl/brmo}{link})
|
||||
|
||||
Also:
|
||||
\itemize{
|
||||
|
||||
@@ -12,9 +12,8 @@ A \link[tibble:tibble]{tibble} with 78 679 observations and 26 variables:
|
||||
\item \code{status} \cr Status of the taxon, either \code{"accepted"}, \code{"not validly published"}, \code{"synonym"}, or \code{"unknown"}
|
||||
\item \code{kingdom}, \code{phylum}, \code{class}, \code{order}, \code{family}, \code{genus}, \code{species}, \code{subspecies}\cr Taxonomic rank of the microorganism. Note that for fungi, \emph{phylum} is equal to their taxonomic \emph{division}. Also, for fungi, \emph{subkingdom} and \emph{subdivision} were left out since they do not occur in the bacterial taxonomy.
|
||||
\item \code{rank}\cr Text of the taxonomic rank of the microorganism, such as \code{"species"} or \code{"genus"}
|
||||
\item \code{ref}\cr Abbreviated authority citation for the nomenclatural act that established the current name combination, following ICNP conventions. For species described in their current genus (\emph{sp. nov.}), this is the original description author(s) and year. For species transferred to a different genus (\emph{comb. nov.}), this is the reclassification author(s) and year. Emendations are excluded. For synonyms, this is the authority under which the synonym was originally published. This field is directly retrieved from the source specified in the column \code{source}. Diacritics were removed to comply with CRAN, that only allows ASCII characters.
|
||||
\item \code{ref}\cr Author(s) and year of related scientific publication. This contains only the \emph{first surname} and year of the \emph{latest} authors, e.g. "Wallis \emph{et al.} 2006 \emph{emend.} Smith and Jones 2018" becomes "Smith \emph{et al.}, 2018". This field is directly retrieved from the source specified in the column \code{source}. Moreover, accents were removed to comply with CRAN that only allows ASCII characters.
|
||||
\item \code{oxygen_tolerance} \cr Oxygen tolerance, either \code{"aerobe"}, \code{"anaerobe"}, \code{"anaerobe/microaerophile"}, \code{"facultative anaerobe"}, \code{"likely facultative anaerobe"}, \code{"microaerophile"}, or NA. These data were retrieved from BacDive (see \emph{Source}). Items that contain "likely" are missing from BacDive and were extrapolated from other species within the same genus to guess the oxygen tolerance. Currently 68.3\% of all ~39 000 bacteria in the data set contain an oxygen tolerance.
|
||||
\item \code{morphology} \cr Morphology (cell shape), either \code{""}. These data were retrieved from BacDive (see \emph{Source}). Genera that are clinically established as coccobacilli (the HACEK group and beyond, such as \emph{Haemophilus} and \emph{Acinetobacter}) are classified as such regardless of BacDive majority vote. Items that contain "likely" are missing from BacDive and were extrapolated from other species within the same genus. Currently 0\% of all ~39 000 bacteria in the data set contain a morphology.
|
||||
\item \code{source}\cr Either \code{"GBIF"}, \code{"LPSN"}, \code{"Manually added"}, \code{"MycoBank"}, or \code{"manually added"} (see \emph{Source})
|
||||
\item \code{lpsn}\cr Identifier ('Record number') of List of Prokaryotic names with Standing in Nomenclature (LPSN). This will be the first/highest LPSN identifier to keep one identifier per row. For example, \emph{Acetobacter ascendens} has LPSN Record number 7864 and 11011. Only the first is available in the \code{microorganisms} data set. \emph{\strong{This is a unique identifier}}, though available for only ~33 000 records.
|
||||
\item \code{lpsn_parent}\cr LPSN identifier of the parent taxon
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
\alias{mo_is_intrinsic_resistant}
|
||||
\alias{mo_oxygen_tolerance}
|
||||
\alias{mo_is_anaerobic}
|
||||
\alias{mo_morphology}
|
||||
\alias{mo_snomed}
|
||||
\alias{mo_ref}
|
||||
\alias{mo_authors}
|
||||
@@ -87,8 +86,7 @@ mo_pathogenicity(x, language = get_AMR_locale(),
|
||||
keep_synonyms = getOption("AMR_keep_synonyms", FALSE), ...)
|
||||
|
||||
mo_gramstain(x, language = get_AMR_locale(),
|
||||
keep_synonyms = getOption("AMR_keep_synonyms", FALSE),
|
||||
add_morphology = FALSE, ...)
|
||||
keep_synonyms = getOption("AMR_keep_synonyms", FALSE), ...)
|
||||
|
||||
mo_is_gram_negative(x, language = get_AMR_locale(),
|
||||
keep_synonyms = getOption("AMR_keep_synonyms", FALSE), ...)
|
||||
@@ -108,9 +106,6 @@ mo_oxygen_tolerance(x, language = get_AMR_locale(),
|
||||
mo_is_anaerobic(x, language = get_AMR_locale(),
|
||||
keep_synonyms = getOption("AMR_keep_synonyms", FALSE), ...)
|
||||
|
||||
mo_morphology(x, language = get_AMR_locale(),
|
||||
keep_synonyms = getOption("AMR_keep_synonyms", FALSE), ...)
|
||||
|
||||
mo_snomed(x, language = get_AMR_locale(),
|
||||
keep_synonyms = getOption("AMR_keep_synonyms", FALSE), ...)
|
||||
|
||||
@@ -166,13 +161,11 @@ The default is \code{FALSE}, which will return a note if outdated taxonomic name
|
||||
|
||||
\item{...}{Other arguments passed on to \code{\link[=as.mo]{as.mo()}}, such as 'minimum_matching_score', 'ignore_pattern', and 'remove_from_input'.}
|
||||
|
||||
\item{add_morphology}{a \link{logical} to indicate whether the morphology (from \code{\link[=mo_morphology]{mo_morphology()}}) should be added to the Gram stain result, e.g. \code{"Gram-negative rods"} instead of \code{"Gram-negative"}. The default is \code{FALSE}.}
|
||||
|
||||
\item{ab}{Any (vector of) text that can be coerced to a valid antibiotic drug code with \code{\link[=as.ab]{as.ab()}}.}
|
||||
|
||||
\item{open}{Browse the URL using \code{\link[utils:browseURL]{browseURL()}}.}
|
||||
|
||||
\item{property}{One of the column names of the \link{microorganisms} data set: \code{"mo"}, \code{"fullname"}, \code{"status"}, \code{"kingdom"}, \code{"phylum"}, \code{"class"}, \code{"order"}, \code{"family"}, \code{"genus"}, \code{"species"}, \code{"subspecies"}, \code{"rank"}, \code{"ref"}, \code{"oxygen_tolerance"}, \code{"source"}, \code{"lpsn"}, \code{"lpsn_parent"}, \code{"lpsn_renamed_to"}, \code{"mycobank"}, \code{"mycobank_parent"}, \code{"mycobank_renamed_to"}, \code{"gbif"}, \code{"gbif_parent"}, \code{"gbif_renamed_to"}, \code{"prevalence"}, or \code{"snomed"}, or must be \code{"shortname"}.}
|
||||
\item{property}{One of the column names of the \link{microorganisms} data set: {.val mo}, {.val fullname}, {.val status}, {.val kingdom}, {.val phylum}, {.val class}, {.val order}, {.val family}, {.val genus}, {.val species}, {.val subspecies}, {.val rank}, {.val ref}, {.val oxygen_tolerance}, {.val source}, {.val lpsn}, {.val lpsn_parent}, {.val lpsn_renamed_to}, {.val mycobank}, {.val mycobank_parent}, {.val mycobank_renamed_to}, {.val gbif}, {.val gbif_parent}, {.val gbif_renamed_to}, {.val prevalence}, or {.val snomed}, or must be \code{"shortname"}.}
|
||||
}
|
||||
\value{
|
||||
\itemize{
|
||||
@@ -196,23 +189,21 @@ All functions will, at default, \strong{not} keep old taxonomic properties, as s
|
||||
\item \code{mo_ref("Enterobacter aerogenes", keep_synonyms = TRUE)} will return \code{"Hormaeche et al., 1960"} (with a once-per-session warning that the name is outdated)
|
||||
}
|
||||
|
||||
\code{\link[=mo_ref]{mo_ref()}} returns the abbreviated authority of the nomenclatural act that created the queried name combination. When \code{keep_synonyms = FALSE} (default), this is the authority of the currently accepted name. When \code{keep_synonyms = TRUE}, this is the authority under which the queried (possibly outdated) name was published. Emendations (changes to the species description without a name change) are not reflected; only the combination or original description authority is returned.
|
||||
|
||||
The short name (\code{\link[=mo_shortname]{mo_shortname()}}) returns the first character of the genus and the full species, such as \code{"E. coli"}, for species and subspecies. Exceptions are abbreviations of staphylococci (such as \emph{"CoNS"}, Coagulase-Negative Staphylococci) and beta-haemolytic streptococci (such as \emph{"GBS"}, Group B Streptococci). Please bear in mind that e.g. \emph{E. coli} could mean \emph{Escherichia coli} (kingdom of Bacteria) as well as \emph{Entamoeba coli} (kingdom of Protozoa). Returning to the full name will be done using \code{\link[=as.mo]{as.mo()}} internally, giving priority to bacteria and human pathogens, i.e. \code{"E. coli"} will always be considered \emph{Escherichia coli}. As a result, \code{mo_fullname(mo_shortname("Entamoeba coli"))} returns \code{"Escherichia coli"}.
|
||||
The short name (\code{\link[=mo_shortname]{mo_shortname()}}) returns the first character of the genus and the full species, such as \code{"E. coli"}, for species and subspecies. Exceptions are abbreviations of staphylococci (such as \emph{"CoNS"}, Coagulase-Negative Staphylococci) and beta-haemolytic streptococci (such as \emph{"GBS"}, Group B Streptococci). Please bear in mind that e.g. \emph{E. coli} could mean \emph{Escherichia coli} (kingdom of Bacteria) as well as \emph{Entamoeba coli} (kingdom of Protozoa). Returning to the full name will be done using \code{\link[=as.mo]{as.mo()}} internally, giving priority to bacteria and human pathogens, i.e. \code{"E. coli"} will be considered \emph{Escherichia coli}. As a result, \code{mo_fullname(mo_shortname("Entamoeba coli"))} returns \code{"Escherichia coli"}.
|
||||
|
||||
Since the top-level of the taxonomy is sometimes referred to as 'kingdom' and sometimes as 'domain', the functions \code{\link[=mo_kingdom]{mo_kingdom()}} and \code{\link[=mo_domain]{mo_domain()}} return the exact same results.
|
||||
|
||||
Determination of human pathogenicity (\code{\link[=mo_pathogenicity]{mo_pathogenicity()}}) is strongly based on Bartlett \emph{et al.} (2022, \doi{10.1099/mic.0.001269}). This function returns a \link{factor} with the levels \emph{Pathogenic}, \emph{Potentially pathogenic}, \emph{Non-pathogenic}, and \emph{Unknown}.
|
||||
|
||||
Determination of the Gram stain (\code{\link[=mo_gramstain]{mo_gramstain()}} is based on the taxonomic kingdom and phylum. Originally, Cavalier-Smith defined the so-called subkingdoms Negibacteria and Posibacteria (2002, \href{https://pubmed.ncbi.nlm.nih.gov/11837318/}{PMID 11837318}), and only considered these phyla as Posibacteria: Actinobacteria, Chloroflexi, Firmicutes, and Tenericutes. These phyla were later renamed to Actinomycetota, Chloroflexota, Bacillota, and Mycoplasmatota (2021, \href{https://pubmed.ncbi.nlm.nih.gov/34694987/}{PMID 34694987}). Bacteria in these phyla are considered Gram-positive in this \code{AMR} package, except for members of the class Negativicutes (within phylum Bacillota) which are Gram-negative. All other bacteria are considered Gram-negative. Species outside the kingdom of Bacteria will return a value \code{NA}. Functions \code{\link[=mo_is_gram_negative]{mo_is_gram_negative()}} and \code{\link[=mo_is_gram_positive]{mo_is_gram_positive()}} always return \code{TRUE} or \code{FALSE} (or \code{NA} when the input is \code{NA} or the MO code is \code{UNKNOWN}), thus always return \code{FALSE} for species outside the taxonomic kingdom of Bacteria.
|
||||
Determination of the Gram stain (\code{\link[=mo_gramstain]{mo_gramstain()}}) will be based on the taxonomic kingdom and phylum. Originally, Cavalier-Smith defined the so-called subkingdoms Negibacteria and Posibacteria (2002, \href{https://pubmed.ncbi.nlm.nih.gov/11837318/}{PMID 11837318}), and only considered these phyla as Posibacteria: Actinobacteria, Chloroflexi, Firmicutes, and Tenericutes. These phyla were later renamed to Actinomycetota, Chloroflexota, Bacillota, and Mycoplasmatota (2021, \href{https://pubmed.ncbi.nlm.nih.gov/34694987/}{PMID 34694987}). Bacteria in these phyla are considered Gram-positive in this \code{AMR} package, except for members of the class Negativicutes (within phylum Bacillota) which are Gram-negative. All other bacteria are considered Gram-negative. Species outside the kingdom of Bacteria will return a value \code{NA}. Functions \code{\link[=mo_is_gram_negative]{mo_is_gram_negative()}} and \code{\link[=mo_is_gram_positive]{mo_is_gram_positive()}} always return \code{TRUE} or \code{FALSE} (or \code{NA} when the input is \code{NA} or the MO code is \code{UNKNOWN}), thus always return \code{FALSE} for species outside the taxonomic kingdom of Bacteria.
|
||||
|
||||
Determination of yeasts (\code{\link[=mo_is_yeast]{mo_is_yeast()}}) is based on the taxonomic kingdom and class. \emph{Budding yeasts} are yeasts that reproduce asexually through a process called budding, where a new cell develops from a small protrusion on the parent cell. Taxonomically, these are members of the phylum Ascomycota, class Saccharomycetes (also called Hemiascomycetes) or Pichiomycetes. \emph{True yeasts} quite specifically refers to yeasts in the underlying order Saccharomycetales (such as \emph{Saccharomyces cerevisiae}). Thus, for all microorganisms that are member of the taxonomic class Saccharomycetes or Pichiomycetes, the function will return \code{TRUE}. It returns \code{FALSE} otherwise (or \code{NA} when the input is \code{NA} or the MO code is \code{UNKNOWN}).
|
||||
Determination of yeasts (\code{\link[=mo_is_yeast]{mo_is_yeast()}}) will be based on the taxonomic kingdom and class. \emph{Budding yeasts} are yeasts that reproduce asexually through a process called budding, where a new cell develops from a small protrusion on the parent cell. Taxonomically, these are members of the phylum Ascomycota, class Saccharomycetes (also called Hemiascomycetes) or Pichiomycetes. \emph{True yeasts} quite specifically refers to yeasts in the underlying order Saccharomycetales (such as \emph{Saccharomyces cerevisiae}). Thus, for all microorganisms that are member of the taxonomic class Saccharomycetes or Pichiomycetes, the function will return \code{TRUE}. It returns \code{FALSE} otherwise (or \code{NA} when the input is \code{NA} or the MO code is \code{UNKNOWN}).
|
||||
|
||||
Determination of intrinsic resistance (\code{\link[=mo_is_intrinsic_resistant]{mo_is_intrinsic_resistant()}}) is based on the \link{intrinsic_resistant} data set, which is based on \href{https://www.eucast.org/bacteria/important-additional-information/expert-rules/}{'EUCAST Expected Resistant Phenotypes' v1.2} (2023). The \code{\link[=mo_is_intrinsic_resistant]{mo_is_intrinsic_resistant()}} function can be vectorised over both argument \code{x} (input for microorganisms) and \code{ab} (input for antimicrobials).
|
||||
Determination of intrinsic resistance (\code{\link[=mo_is_intrinsic_resistant]{mo_is_intrinsic_resistant()}}) will be based on the \link{intrinsic_resistant} data set, which is based on \href{https://www.eucast.org/bacteria/important-additional-information/expert-rules/}{'EUCAST Expected Resistant Phenotypes' v1.2} (2023). The \code{\link[=mo_is_intrinsic_resistant]{mo_is_intrinsic_resistant()}} function can be vectorised over both argument \code{x} (input for microorganisms) and \code{ab} (input for antimicrobials).
|
||||
|
||||
Determination of both bacterial oxygen tolerance (\code{\link[=mo_oxygen_tolerance]{mo_oxygen_tolerance()}}) and morphology (\code{\link[=mo_morphology]{mo_morphology()}}) are based on BacDive, see \emph{Source}. The function \code{\link[=mo_is_anaerobic]{mo_is_anaerobic()}} only returns \code{TRUE} if the oxygen tolerance is \code{"anaerobe"}, indicating an obligate anaerobic species or genus. It always returns \code{FALSE} for species outside the taxonomic kingdom of Bacteria.
|
||||
Determination of bacterial oxygen tolerance (\code{\link[=mo_oxygen_tolerance]{mo_oxygen_tolerance()}}) will be based on BacDive, see \emph{Source}. The function \code{\link[=mo_is_anaerobic]{mo_is_anaerobic()}} only returns \code{TRUE} if the oxygen tolerance is \code{"anaerobe"}, indicting an obligate anaerobic species or genus. It always returns \code{FALSE} for species outside the taxonomic kingdom of Bacteria.
|
||||
|
||||
The function \code{\link[=mo_url]{mo_url()}} will return the direct URL to the online database entry, which also shows the scientific reference of the concerned species. \href{https://www.mycobank.org}{This MycoBank URL} is used for fungi wherever available , \href{https://www.mycobank.org}{this LPSN URL} for bacteria wherever available, and \href{https://www.gbif.org}{this GBIF link} otherwise.
|
||||
The function \code{\link[=mo_url]{mo_url()}} will return the direct URL to the online database entry, which also shows the scientific reference of the concerned species. \href{https://www.mycobank.org}{This MycoBank URL} will be used for fungi wherever available , \href{https://www.mycobank.org}{this LPSN URL} for bacteria wherever available, and \href{https://www.gbif.org}{this GBIF link} otherwise.
|
||||
|
||||
SNOMED codes (\code{\link[=mo_snomed]{mo_snomed()}}) was last updated on July 16th, 2024. See \emph{Source} and the \link{microorganisms} data set for more info.
|
||||
|
||||
@@ -269,10 +260,8 @@ mo_shortname("Klebsiella pneumoniae")
|
||||
|
||||
# other properties ---------------------------------------------------------
|
||||
|
||||
mo_morphology("Klebsiella pneumoniae")
|
||||
mo_gramstain("Klebsiella pneumoniae")
|
||||
mo_gramstain("Klebsiella pneumoniae", add_morphology = TRUE)
|
||||
mo_pathogenicity("Klebsiella pneumoniae")
|
||||
mo_gramstain("Klebsiella pneumoniae")
|
||||
mo_snomed("Klebsiella pneumoniae")
|
||||
mo_type("Klebsiella pneumoniae")
|
||||
mo_rank("Klebsiella pneumoniae")
|
||||
|
||||
@@ -79,12 +79,12 @@ if (require("dplyr")) {
|
||||
|
||||
# new ggplot2 plotting method using this package:
|
||||
if (require("dplyr") && require("ggplot2")) {
|
||||
ggplot_pca(pca_result)
|
||||
ggplot_pca(pca_result)
|
||||
}
|
||||
if (require("dplyr") && require("ggplot2")) {
|
||||
ggplot_pca(pca_result) +
|
||||
scale_colour_viridis_d() +
|
||||
labs(title = "Title here")
|
||||
ggplot_pca(pca_result) +
|
||||
scale_colour_viridis_d() +
|
||||
labs(title = "Title here")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ labels_sir_count(position = NULL, x = "antibiotic",
|
||||
|
||||
\item{include_PKPD}{A \link{logical} to indicate that PK/PD clinical breakpoints must be applied as a last resort - the default is \code{TRUE}. Can also be set with the package option \code{\link[=AMR-options]{AMR_include_PKPD}}.}
|
||||
|
||||
\item{breakpoint_type}{The type of breakpoints to use, either \code{"ECOFF"}, \code{"animal"}, or \code{"human"}. ECOFF stands for Epidemiological Cut-Off values. The default is \code{"human"}, which can also be set with the package option \code{\link[=AMR-options]{AMR_breakpoint_type}}. If \code{host} is set to values of veterinary species, this will automatically be set to \code{"animal"}.}
|
||||
\item{breakpoint_type}{The type of breakpoints to use, either {.val ECOFF}, {.val animal}, or {.val human}. ECOFF stands for Epidemiological Cut-Off values. The default is \code{"human"}, which can also be set with the package option \code{\link[=AMR-options]{AMR_breakpoint_type}}. If \code{host} is set to values of veterinary species, this will automatically be set to \code{"animal"}.}
|
||||
|
||||
\item{facet}{Variable to split plots by, either \code{"interpretation"} (default) or \code{"antibiotic"} or a grouping variable.}
|
||||
|
||||
@@ -321,7 +321,7 @@ if (require("ggplot2")) {
|
||||
theme_minimal() +
|
||||
geom_boxplot(fill = NA, colour = "grey30") +
|
||||
geom_jitter(width = 0.25)
|
||||
labs(title = "scale_y_mic()/scale_colour_sir() automatically applied")
|
||||
labs(title = "scale_y_mic()/scale_colour_sir() automatically applied")
|
||||
|
||||
mic_sir_plot
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ top_n_microorganisms(x, n, property = "species", n_for_each = NULL,
|
||||
|
||||
\item{n}{An integer specifying the maximum number of unique values of the \code{property} to include in the output.}
|
||||
|
||||
\item{property}{A character string indicating the microorganism property to use for filtering. Must be one of the column names of the \link{microorganisms} data set: \code{"mo"}, \code{"fullname"}, \code{"status"}, \code{"kingdom"}, \code{"phylum"}, \code{"class"}, \code{"order"}, \code{"family"}, \code{"genus"}, \code{"species"}, \code{"subspecies"}, \code{"rank"}, \code{"ref"}, \code{"oxygen_tolerance"}, \code{"source"}, \code{"lpsn"}, \code{"lpsn_parent"}, \code{"lpsn_renamed_to"}, \code{"mycobank"}, \code{"mycobank_parent"}, \code{"mycobank_renamed_to"}, \code{"gbif"}, \code{"gbif_parent"}, \code{"gbif_renamed_to"}, \code{"prevalence"}, or \code{"snomed"}. If \code{NULL}, the raw values from \code{col_mo} will be used without transformation. When using \code{"species"} (default) or \code{"subpecies"}, the genus will be added to make sure each (sub)species still belongs to the right genus.}
|
||||
\item{property}{A character string indicating the microorganism property to use for filtering. Must be one of the column names of the \link{microorganisms} data set: {.val mo}, {.val fullname}, {.val status}, {.val kingdom}, {.val phylum}, {.val class}, {.val order}, {.val family}, {.val genus}, {.val species}, {.val subspecies}, {.val rank}, {.val ref}, {.val oxygen_tolerance}, {.val source}, {.val lpsn}, {.val lpsn_parent}, {.val lpsn_renamed_to}, {.val mycobank}, {.val mycobank_parent}, {.val mycobank_renamed_to}, {.val gbif}, {.val gbif_parent}, {.val gbif_renamed_to}, {.val prevalence}, or {.val snomed}. If \code{NULL}, the raw values from \code{col_mo} will be used without transformation. When using \code{"species"} (default) or \code{"subpecies"}, the genus will be added to make sure each (sub)species still belongs to the right genus.}
|
||||
|
||||
\item{n_for_each}{An optional integer specifying the maximum number of rows to retain for each value of the selected property. If \code{NULL}, all rows within the top \emph{n} groups will be included.}
|
||||
|
||||
|
||||
@@ -30,15 +30,6 @@
|
||||
test_that("test-_deprecated.R", {
|
||||
skip_on_cran()
|
||||
|
||||
if (getRversion() > "4.0.0") {
|
||||
expect_warning(example_isolates[, ab_class("mycobact")])
|
||||
expect_warning(example_isolates[, ab_selector(name %like% "trim")])
|
||||
|
||||
# deprecated custom_interpretive_rules() still works and emits a warning
|
||||
expect_warning(
|
||||
x_old <- custom_eucast_rules(AMC == "R" ~ aminopenicillins == "R"),
|
||||
regexp = "custom_eucast_rules"
|
||||
)
|
||||
expect_inherits(x_old, "custom_interpretive_rules")
|
||||
}
|
||||
expect_warning(example_isolates[, ab_class("mycobact")])
|
||||
expect_warning(example_isolates[, ab_selector(name %like% "trim")])
|
||||
})
|
||||
|
||||
@@ -130,77 +130,6 @@ test_that("test-antibiogram.R", {
|
||||
expect_equal(colnames(ab9), c("ward", "gender", "Piperacillin/tazobactam", "Piperacillin/tazobactam + Gentamicin", "Piperacillin/tazobactam + Tobramycin"))
|
||||
}
|
||||
|
||||
# Parallel computing ----------------------------------------------------
|
||||
# Tests must pass even when only 1 core is available; parallel = TRUE then
|
||||
# silently falls back to sequential, but results must still be correct.
|
||||
|
||||
if (AMR:::pkg_is_available("future.apply")) {
|
||||
set.seed(42)
|
||||
|
||||
# sequential reference for WISCA
|
||||
wisca_seq <- suppressWarnings(suppressMessages(
|
||||
wisca(example_isolates, antimicrobials = c("TZP", "TZP+TOB", "TZP+GEN"), simulations = 100, info = FALSE)
|
||||
))
|
||||
|
||||
future::plan(future::multicore)
|
||||
|
||||
# 1. parallel = TRUE produces the same antibiogram structure as sequential
|
||||
wisca_par <- suppressWarnings(suppressMessages(
|
||||
wisca(example_isolates, antimicrobials = c("TZP", "TZP+TOB", "TZP+GEN"), simulations = 100, parallel = TRUE, info = FALSE)
|
||||
))
|
||||
expect_inherits(wisca_par, "antibiogram")
|
||||
expect_equal(colnames(wisca_par), colnames(wisca_seq))
|
||||
expect_true(isTRUE(attributes(wisca_par)$wisca))
|
||||
|
||||
# 2. coverage values are non-NA and fall within [0, 1]
|
||||
ln <- attributes(wisca_par)$long_numeric
|
||||
expect_false(anyNA(ln$coverage))
|
||||
expect_false(anyNA(ln$lower_ci))
|
||||
expect_false(anyNA(ln$upper_ci))
|
||||
expect_true(all(ln$coverage >= 0 & ln$coverage <= 1))
|
||||
expect_true(all(ln$lower_ci <= ln$coverage))
|
||||
expect_true(all(ln$upper_ci >= ln$coverage))
|
||||
|
||||
# 3. a second parallel run gives the same column names
|
||||
wisca_par2 <- suppressWarnings(suppressMessages(
|
||||
wisca(example_isolates, antimicrobials = c("TZP", "TZP+TOB", "TZP+GEN"), simulations = 100, parallel = TRUE, info = FALSE)
|
||||
))
|
||||
expect_equal(colnames(wisca_par), colnames(wisca_par2))
|
||||
|
||||
# 4. parallel with workers = 1 gives same structure as sequential
|
||||
future::plan(future::multicore, workers = 1)
|
||||
wisca_par1 <- suppressWarnings(suppressMessages(
|
||||
wisca(example_isolates, antimicrobials = c("TZP", "TZP+TOB", "TZP+GEN"), simulations = 100, parallel = TRUE, info = FALSE)
|
||||
))
|
||||
expect_equal(colnames(wisca_seq), colnames(wisca_par1))
|
||||
|
||||
# 5. grouped antibiogram in parallel yields identical structure to sequential
|
||||
if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0", also_load = TRUE)) {
|
||||
future::plan(future::sequential)
|
||||
ab_grp_seq <- suppressWarnings(suppressMessages(
|
||||
example_isolates %>%
|
||||
group_by(ward) %>%
|
||||
wisca(antimicrobials = c("TZP", "TZP+TOB"), simulations = 50, info = FALSE)
|
||||
))
|
||||
future::plan(future::multicore)
|
||||
ab_grp_par <- suppressWarnings(suppressMessages(
|
||||
example_isolates %>%
|
||||
group_by(ward) %>%
|
||||
wisca(antimicrobials = c("TZP", "TZP+TOB"), simulations = 50, parallel = TRUE, info = FALSE)
|
||||
))
|
||||
expect_equal(colnames(ab_grp_seq), colnames(ab_grp_par))
|
||||
expect_equal(nrow(ab_grp_seq), nrow(ab_grp_par))
|
||||
}
|
||||
|
||||
# 6. parallel = TRUE without a plan raises an informative error
|
||||
future::plan(future::sequential)
|
||||
expect_error(
|
||||
suppressWarnings(wisca(example_isolates, antimicrobials = "TZP", parallel = TRUE, info = FALSE)),
|
||||
"non-sequential"
|
||||
)
|
||||
|
||||
future::plan(future::sequential)
|
||||
}
|
||||
|
||||
# Generate plots with ggplot2 or base R --------------------------------
|
||||
|
||||
|
||||
@@ -53,12 +53,12 @@ test_that("test-data.R", {
|
||||
expect_false(anyNA(microorganisms.codes$mo))
|
||||
expect_true(all(dosage$ab %in% AMR::antimicrobials$ab))
|
||||
expect_true(all(dosage$name %in% AMR::antimicrobials$name))
|
||||
interpretive_abx <- AMR:::INTERPRETIVE_RULES_DF$and_these_antibiotics
|
||||
interpretive_abx <- unique(unlist(strsplit(interpretive_abx[!is.na(interpretive_abx)], ", +")))
|
||||
expect_true(all(interpretive_abx %in% AMR::antimicrobials$ab),
|
||||
eucast_abx <- AMR:::EUCAST_RULES_DF$and_these_antibiotics
|
||||
eucast_abx <- unique(unlist(strsplit(eucast_abx[!is.na(eucast_abx)], ", +")))
|
||||
expect_true(all(eucast_abx %in% AMR::antimicrobials$ab),
|
||||
info = paste0(
|
||||
"Missing in `antimicrobials` data set: ",
|
||||
toString(interpretive_abx[which(!interpretive_abx %in% AMR::antimicrobials$ab)])
|
||||
toString(eucast_abx[which(!eucast_abx %in% AMR::antimicrobials$ab)])
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -27,14 +27,13 @@
|
||||
# how to conduct AMR data analysis: https://amr-for-r.org #
|
||||
# ==================================================================== #
|
||||
|
||||
test_that("test-interpretive_rules.R", {
|
||||
test_that("test-eucast_rules.R", {
|
||||
skip_on_cran()
|
||||
|
||||
# thoroughly check input table
|
||||
expect_equal(
|
||||
sort(colnames(AMR:::INTERPRETIVE_RULES_DF)),
|
||||
sort(colnames(AMR:::EUCAST_RULES_DF)),
|
||||
sort(c(
|
||||
"rule.provider",
|
||||
"if_mo_property", "like.is.one_of", "this_value",
|
||||
"and_these_antibiotics", "have_these_values",
|
||||
"then_change_these_antibiotics", "to_value",
|
||||
@@ -43,7 +42,7 @@ test_that("test-interpretive_rules.R", {
|
||||
"note"
|
||||
))
|
||||
)
|
||||
MOs_mentioned <- unique(AMR:::INTERPRETIVE_RULES_DF$this_value)
|
||||
MOs_mentioned <- unique(AMR:::EUCAST_RULES_DF$this_value)
|
||||
MOs_mentioned <- sort(trimws(unlist(strsplit(MOs_mentioned[!AMR:::is_valid_regex(MOs_mentioned)], ",", fixed = TRUE))))
|
||||
MOs_test <- suppressWarnings(
|
||||
trimws(paste(
|
||||
@@ -55,19 +54,19 @@ test_that("test-interpretive_rules.R", {
|
||||
MOs_test[MOs_test == ""] <- mo_fullname(MOs_mentioned[MOs_test == ""], keep_synonyms = TRUE, language = NULL)
|
||||
expect_equal(MOs_mentioned, MOs_test)
|
||||
|
||||
expect_error(suppressWarnings(interpretive_rules(example_isolates, col_mo = "Non-existing")))
|
||||
expect_error(interpretive_rules(x = "text"))
|
||||
expect_error(interpretive_rules(data.frame(a = "test")))
|
||||
expect_error(interpretive_rules(data.frame(mo = "test"), rules = "invalid rules set"))
|
||||
expect_error(suppressWarnings(eucast_rules(example_isolates, col_mo = "Non-existing")))
|
||||
expect_error(eucast_rules(x = "text"))
|
||||
expect_error(eucast_rules(data.frame(a = "test")))
|
||||
expect_error(eucast_rules(data.frame(mo = "test"), rules = "invalid rules set"))
|
||||
|
||||
# expect_warning(interpretive_rules(data.frame(mo = "Escherichia coli", vancomycin = "S", stringsAsFactors = TRUE)))
|
||||
# expect_warning(eucast_rules(data.frame(mo = "Escherichia coli", vancomycin = "S", stringsAsFactors = TRUE)))
|
||||
|
||||
expect_identical(
|
||||
colnames(example_isolates),
|
||||
colnames(suppressWarnings(interpretive_rules(example_isolates, info = FALSE)))
|
||||
colnames(suppressWarnings(eucast_rules(example_isolates, info = FALSE)))
|
||||
)
|
||||
|
||||
expect_output(suppressMessages(interpretive_rules(example_isolates, info = TRUE)))
|
||||
expect_output(suppressMessages(eucast_rules(example_isolates, info = TRUE)))
|
||||
|
||||
a <- data.frame(
|
||||
mo = c(
|
||||
@@ -87,8 +86,8 @@ test_that("test-interpretive_rules.R", {
|
||||
amox = "R", # Amoxicillin
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
expect_identical(suppressWarnings(interpretive_rules(a, "mo", info = FALSE)), b)
|
||||
expect_output(suppressMessages(suppressWarnings(interpretive_rules(a, "mo", info = TRUE))))
|
||||
expect_identical(suppressWarnings(eucast_rules(a, "mo", info = FALSE)), b)
|
||||
expect_output(suppressMessages(suppressWarnings(eucast_rules(a, "mo", info = TRUE))))
|
||||
|
||||
a <- data.frame(
|
||||
mo = c(
|
||||
@@ -106,7 +105,7 @@ test_that("test-interpretive_rules.R", {
|
||||
COL = "R", # Colistin
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
expect_equal(suppressWarnings(interpretive_rules(a, "mo", info = FALSE)), b)
|
||||
expect_equal(suppressWarnings(eucast_rules(a, "mo", info = FALSE)), b)
|
||||
|
||||
# piperacillin must be R in Enterobacteriaceae when tica is R
|
||||
if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0", also_load = TRUE)) {
|
||||
@@ -118,7 +117,7 @@ test_that("test-interpretive_rules.R", {
|
||||
TIC = as.sir("R"),
|
||||
PIP = as.sir("S")
|
||||
) %>%
|
||||
interpretive_rules(col_mo = "mo", version_expertrules = 3.1, rules = "expert", info = FALSE, overwrite = TRUE) %>%
|
||||
eucast_rules(col_mo = "mo", version_expertrules = 3.1, rules = "expert", info = FALSE, overwrite = TRUE) %>%
|
||||
pull(PIP) %>%
|
||||
unique() %>%
|
||||
as.character()
|
||||
@@ -128,7 +127,7 @@ test_that("test-interpretive_rules.R", {
|
||||
}
|
||||
|
||||
# azithromycin and clarythromycin must be equal to Erythromycin
|
||||
a <- suppressWarnings(as.sir(interpretive_rules(
|
||||
a <- suppressWarnings(as.sir(eucast_rules(
|
||||
data.frame(
|
||||
mo = example_isolates$mo,
|
||||
ERY = example_isolates$ERY,
|
||||
@@ -150,7 +149,7 @@ test_that("test-interpretive_rules.R", {
|
||||
# amox is inferred by benzylpenicillin in Kingella kingae
|
||||
expect_equal(
|
||||
suppressWarnings(
|
||||
as.list(interpretive_rules(
|
||||
as.list(eucast_rules(
|
||||
data.frame(
|
||||
mo = as.mo("Kingella kingae"),
|
||||
PEN = "S",
|
||||
@@ -165,16 +164,16 @@ test_that("test-interpretive_rules.R", {
|
||||
|
||||
# also test norf
|
||||
if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0", also_load = TRUE)) {
|
||||
expect_output(suppressWarnings(interpretive_rules(example_isolates %>% mutate(NOR = "S", NAL = "S"), info = TRUE)))
|
||||
expect_output(suppressWarnings(eucast_rules(example_isolates %>% mutate(NOR = "S", NAL = "S"), info = TRUE)))
|
||||
}
|
||||
|
||||
# check verbose output
|
||||
expect_output(suppressWarnings(interpretive_rules(example_isolates, verbose = TRUE, rules = "all", info = TRUE)))
|
||||
expect_output(suppressWarnings(eucast_rules(example_isolates, verbose = TRUE, rules = "all", info = TRUE)))
|
||||
|
||||
# AmpC de-repressed cephalo mutants
|
||||
|
||||
expect_identical(
|
||||
interpretive_rules(
|
||||
eucast_rules(
|
||||
data.frame(
|
||||
mo = c("Escherichia coli", "Enterobacter cloacae"),
|
||||
cefotax = as.sir(c("S", "S"))
|
||||
@@ -188,7 +187,7 @@ test_that("test-interpretive_rules.R", {
|
||||
)
|
||||
|
||||
expect_identical(
|
||||
interpretive_rules(
|
||||
eucast_rules(
|
||||
data.frame(
|
||||
mo = c("Escherichia coli", "Enterobacter cloacae"),
|
||||
cefotax = as.sir(c("S", "S"))
|
||||
@@ -202,7 +201,7 @@ test_that("test-interpretive_rules.R", {
|
||||
)
|
||||
|
||||
expect_identical(
|
||||
interpretive_rules(
|
||||
eucast_rules(
|
||||
data.frame(
|
||||
mo = c("Escherichia coli", "Enterobacter cloacae"),
|
||||
cefotax = as.sir(c("S", "S"))
|
||||
@@ -220,7 +219,7 @@ test_that("test-interpretive_rules.R", {
|
||||
expect_inherits(eucast_dosage(c("tobra", "genta", "cipro")), "data.frame")
|
||||
|
||||
|
||||
x <- custom_interpretive_rules(
|
||||
x <- custom_eucast_rules(
|
||||
AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
|
||||
AMC == "I" & genus == "Klebsiella" ~ aminopenicillins == "I",
|
||||
AMX == "S" ~ AMC == "S"
|
||||
@@ -231,7 +230,7 @@ test_that("test-interpretive_rules.R", {
|
||||
|
||||
# this custom rules makes 8 changes
|
||||
expect_equal(
|
||||
nrow(interpretive_rules(example_isolates,
|
||||
nrow(eucast_rules(example_isolates,
|
||||
rules = "custom",
|
||||
custom_rules = x,
|
||||
info = FALSE,
|
||||
@@ -241,10 +240,4 @@ test_that("test-interpretive_rules.R", {
|
||||
8,
|
||||
tolerance = 0.5
|
||||
)
|
||||
|
||||
# clsi_rules() no longer errors (returns data unchanged until CLSI rows are added)
|
||||
expect_identical(
|
||||
suppressWarnings(clsi_rules(example_isolates, info = FALSE)),
|
||||
example_isolates
|
||||
)
|
||||
})
|
||||
@@ -84,16 +84,6 @@ test_that("test-mo.R", {
|
||||
|
||||
# expect_warning(as.mo("Acinetobacter calcoaceticus/baumannii complex"))
|
||||
|
||||
# Issue #287: "X complex" fallback to "X" when complex is not a distinct taxon
|
||||
expect_identical(as.character(suppressWarnings(as.mo("Proteus vulgaris complex"))), as.character(suppressWarnings(as.mo("Proteus vulgaris"))))
|
||||
expect_identical(as.character(suppressWarnings(as.mo("Enterobacter cloacae complex"))), as.character(as.mo("Enterobacter cloacae complex")))
|
||||
|
||||
# Issue #288: abbreviated genus with exact species epithet match should win
|
||||
expect_identical(
|
||||
as.character(suppressWarnings(as.mo("S. apiospermum"))),
|
||||
as.character(suppressWarnings(as.mo("Scedosporium apiospermum")))
|
||||
)
|
||||
|
||||
# prevalent MO
|
||||
expect_identical(
|
||||
suppressWarnings(as.character(
|
||||
|
||||
@@ -406,199 +406,40 @@ test_that("test-sir.R", {
|
||||
expect_equal(out3, as.sir(c("NWT", "WT", "NWT")))
|
||||
expect_equal(out4, as.sir(c("NWT", "WT", "NWT")))
|
||||
|
||||
# Issue #278: re-running as.sir() on already-<sir> data must preserve columns
|
||||
df_already_sir <- data.frame(
|
||||
mo = "B_ESCHR_COLI",
|
||||
AMC = as.mic(c("1", "2", "4")),
|
||||
GEN = sample(c("S", "I", "R"), 3, replace = TRUE),
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
first_pass <- suppressMessages(as.sir(df_already_sir, col_mo = "mo", info = FALSE))
|
||||
second_pass <- suppressMessages(as.sir(first_pass, col_mo = "mo", info = FALSE))
|
||||
expect_equal(ncol(first_pass), ncol(second_pass))
|
||||
expect_true(is.sir(second_pass[["AMC"]]))
|
||||
expect_true(is.sir(second_pass[["GEN"]]))
|
||||
expect_identical(first_pass[["AMC"]], second_pass[["AMC"]])
|
||||
expect_identical(first_pass[["GEN"]], second_pass[["GEN"]])
|
||||
|
||||
# Issue #278: metadata columns whose names coincidentally match antibiotic
|
||||
# codes (e.g. 'patient' -> OXY, 'ward' -> PRU) must not be processed
|
||||
df_meta <- data.frame(
|
||||
mo = "B_ESCHR_COLI",
|
||||
patient = paste0("Pt_", 1:20),
|
||||
ward = rep(c("ICU", "Surgery", "Outpatient", "ED"), 5),
|
||||
AMC = as.mic(rep(c("1", "2", "4", "8"), 5)),
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
df_meta_sir <- suppressMessages(as.sir(df_meta, col_mo = "mo", info = FALSE))
|
||||
expect_true("patient" %in% colnames(df_meta_sir))
|
||||
expect_true("ward" %in% colnames(df_meta_sir))
|
||||
expect_false(is.sir(df_meta_sir[["patient"]]))
|
||||
expect_false(is.sir(df_meta_sir[["ward"]]))
|
||||
expect_true(is.sir(df_meta_sir[["AMC"]]))
|
||||
|
||||
# Parallel computing ----------------------------------------------------
|
||||
# Tests must pass even when only 1 core is available; parallel = TRUE then
|
||||
# silently falls back to sequential, but results must still be identical.
|
||||
|
||||
if (AMR:::pkg_is_available("future.apply")) {
|
||||
set.seed(42)
|
||||
n_par <- 200
|
||||
df_par <- data.frame(
|
||||
mo = "B_ESCHR_COLI",
|
||||
AMC = as.mic(sample(c("0.25", "0.5", "1", "2", "4", "8", "16", "32"), n_par, TRUE)),
|
||||
GEN = as.mic(sample(c("0.5", "1", "2", "4", "8", "16", "32", "64"), n_par, TRUE)),
|
||||
CIP = as.mic(sample(c("0.001", "0.002", "0.004", "0.008", "0.016", "0.032"), n_par, TRUE)),
|
||||
PEN = sample(c("S", "I", "R", NA_character_), n_par, TRUE),
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
# MB 29 Apr 2025: I have run the code of AVC, PEI, Canada (dataset of 2854x65), and compared it like this:
|
||||
|
||||
# clear any existing history before comparing
|
||||
sir_interpretation_history(clean = TRUE)
|
||||
sir_seq <- suppressMessages(as.sir(df_par, col_mo = "mo", info = FALSE))
|
||||
log_seq <- sir_interpretation_history(clean = TRUE)
|
||||
# system.time({
|
||||
# data_2022_2023_SIR_parallel <- data_2022_2023_clean |>
|
||||
# as.sir(amikacin:tiamulin,
|
||||
# col_mo = "mo",
|
||||
# guideline = "CLSI 2024",
|
||||
# host = "Species",
|
||||
# uti = "isUTI",
|
||||
# parallel = TRUE)
|
||||
# })
|
||||
# # user system elapsed
|
||||
# # 271.424 2.767 45.762
|
||||
#
|
||||
# history_parallel <- sir_interpretation_history(clean = TRUE)
|
||||
#
|
||||
# system.time({
|
||||
# data_2022_2023_SIR <- data_2022_2023_clean |>
|
||||
# as.sir(amikacin:tiamulin,
|
||||
# col_mo = "mo",
|
||||
# guideline = "CLSI 2024",
|
||||
# host = "Species",
|
||||
# uti = "isUTI")
|
||||
# })
|
||||
# # user system elapsed
|
||||
# # 120.637 5.406 128.835
|
||||
# history <- sir_interpretation_history()
|
||||
|
||||
future::plan(future::multicore)
|
||||
n_max_workers <- future::nbrOfWorkers()
|
||||
|
||||
sir_par <- suppressMessages(as.sir(df_par, col_mo = "mo", info = FALSE, parallel = TRUE))
|
||||
log_par <- sir_interpretation_history(clean = TRUE)
|
||||
# and then got this:
|
||||
# identical(history[, -1], history_parallel[, -1])
|
||||
#> [1] TRUE
|
||||
|
||||
# 1. parallel = TRUE gives identical SIR results to sequential
|
||||
expect_identical(sir_seq[["AMC"]], sir_par[["AMC"]])
|
||||
expect_identical(sir_seq[["GEN"]], sir_par[["GEN"]])
|
||||
expect_identical(sir_seq[["CIP"]], sir_par[["CIP"]])
|
||||
expect_identical(sir_seq[["PEN"]], sir_par[["PEN"]])
|
||||
|
||||
# 2. same number of log rows as sequential
|
||||
expect_equal(nrow(log_seq), nrow(log_par))
|
||||
|
||||
# 3. pre-existing log entries must not be duplicated
|
||||
# run sequential once to populate the history, then run parallel and
|
||||
# verify the new parallel run adds exactly as many rows as sequential
|
||||
sir_interpretation_history(clean = TRUE)
|
||||
future::plan(future::sequential)
|
||||
suppressMessages(as.sir(df_par, col_mo = "mo", info = FALSE)) # populate history
|
||||
pre_n <- nrow(sir_interpretation_history())
|
||||
future::plan(future::multicore)
|
||||
suppressMessages(as.sir(df_par, col_mo = "mo", info = FALSE, parallel = TRUE))
|
||||
post_n <- nrow(sir_interpretation_history())
|
||||
expect_equal(post_n - pre_n, nrow(log_seq)) # exactly one run's worth of new rows
|
||||
sir_interpretation_history(clean = TRUE)
|
||||
|
||||
# 4. two sequential runs and two parallel runs yield identical results
|
||||
sir_par2 <- suppressMessages(as.sir(df_par, col_mo = "mo", info = FALSE, parallel = TRUE))
|
||||
expect_identical(sir_par[["AMC"]], sir_par2[["AMC"]])
|
||||
expect_identical(sir_par[["GEN"]], sir_par2[["GEN"]])
|
||||
|
||||
# 5. used cores = 1 gives same results as default sequential
|
||||
future::plan(future::multicore, workers = 1)
|
||||
sir_mc1 <- suppressMessages(as.sir(df_par, col_mo = "mo", info = FALSE, parallel = TRUE))
|
||||
expect_identical(sir_seq[["AMC"]], sir_mc1[["AMC"]])
|
||||
expect_identical(sir_seq[["GEN"]], sir_mc1[["GEN"]])
|
||||
|
||||
# 6. used cores = 2 and used cores = 3 give same results as sequential
|
||||
if (n_max_workers >= 3) {
|
||||
future::plan(future::multicore, workers = 2)
|
||||
sir_mc2 <- suppressMessages(as.sir(df_par, col_mo = "mo", info = FALSE, parallel = TRUE))
|
||||
future::plan(future::multicore, workers = 3)
|
||||
sir_mc3 <- suppressMessages(as.sir(df_par, col_mo = "mo", info = FALSE, parallel = TRUE))
|
||||
expect_identical(sir_seq[["AMC"]], sir_mc2[["AMC"]])
|
||||
expect_identical(sir_seq[["GEN"]], sir_mc3[["GEN"]])
|
||||
}
|
||||
|
||||
# 7. single-column data frame falls back silently to sequential
|
||||
df_single <- df_par[, c("mo", "AMC")]
|
||||
future::plan(future::sequential)
|
||||
sir_single_seq <- suppressMessages(as.sir(df_single, col_mo = "mo", info = FALSE))
|
||||
future::plan(future::multicore)
|
||||
sir_single_par <- suppressMessages(as.sir(df_single, col_mo = "mo", info = FALSE, parallel = TRUE))
|
||||
expect_identical(sir_single_seq[["AMC"]], sir_single_par[["AMC"]])
|
||||
|
||||
# 8. row-batch mode (n_cols < n_cores): force row splitting via used cores and
|
||||
# verify identical output to sequential for a dataset with 2 AB columns so
|
||||
# pieces_per_col = ceiling(used cores / 2) >= 2 and row batching activates
|
||||
df_wide <- data.frame(
|
||||
mo = "B_ESCHR_COLI",
|
||||
AMC = as.mic(sample(c("1", "2", "4", "8"), n_par, TRUE)),
|
||||
GEN = as.mic(sample(c("1", "2", "4", "8"), n_par, TRUE)),
|
||||
stringsAsFactors = FALSE
|
||||
)
|
||||
future::plan(future::sequential)
|
||||
sir_wide_seq <- suppressMessages(as.sir(df_wide, col_mo = "mo", info = FALSE))
|
||||
future::plan(future::multicore)
|
||||
sir_wide_par <- suppressMessages(as.sir(df_wide,
|
||||
col_mo = "mo", info = FALSE,
|
||||
parallel = TRUE
|
||||
))
|
||||
expect_identical(sir_wide_seq[["AMC"]], sir_wide_par[["AMC"]])
|
||||
expect_identical(sir_wide_seq[["GEN"]], sir_wide_par[["GEN"]])
|
||||
|
||||
# 8. info = TRUE with parallel does not produce per-column worker messages
|
||||
# (messages should only appear in the main process, not duplicated from workers)
|
||||
msgs <- capture.output(
|
||||
suppressWarnings(as.sir(df_par, col_mo = "mo", info = TRUE, parallel = TRUE)),
|
||||
type = "message"
|
||||
)
|
||||
# each AB column name should appear at most once in all messages combined
|
||||
for (ab_nm in c("AMC", "GEN", "CIP", "PEN")) {
|
||||
n_mentions <- sum(grepl(ab_nm, msgs, fixed = TRUE))
|
||||
expect_lte(n_mentions, 1L)
|
||||
}
|
||||
future::plan(future::sequential)
|
||||
}
|
||||
})
|
||||
|
||||
# issue #239 — custom reference_data support
|
||||
test_that("custom reference_data: non-EUCAST/CLSI guideline produces R", {
|
||||
# Build a minimal one-row custom breakpoint table from a plain data.frame.
|
||||
# coerce_reference_data_columns() will coerce mo/ab to the right class.
|
||||
my_bp <- clinical_breakpoints[clinical_breakpoints$method == "MIC" &
|
||||
clinical_breakpoints$type == "human", ][1, ]
|
||||
my_bp$guideline <- "MyLab 2025"
|
||||
my_bp$mo <- "B_ACHRMB_XYLS" # plain character — coerced to <mo>
|
||||
my_bp$ab <- "MEM" # plain character — coerced to <ab>
|
||||
my_bp$breakpoint_S <- 8
|
||||
my_bp$breakpoint_R <- 32
|
||||
|
||||
# guideline omitted: all rows in reference_data are used; R via open interval (>)
|
||||
expect_equal(as.character(suppressMessages(
|
||||
as.sir(as.mic(64), mo = "B_ACHRMB_XYLS", ab = "MEM", reference_data = my_bp)
|
||||
)), "R")
|
||||
expect_equal(as.character(suppressMessages(
|
||||
as.sir(as.mic(16), mo = "B_ACHRMB_XYLS", ab = "MEM", reference_data = my_bp)
|
||||
)), "I")
|
||||
# at R breakpoint value must be I (open interval: > not >=)
|
||||
expect_equal(as.character(suppressMessages(
|
||||
as.sir(as.mic(32), mo = "B_ACHRMB_XYLS", ab = "MEM", reference_data = my_bp)
|
||||
)), "I")
|
||||
|
||||
# guideline explicitly set: same result when it matches the data
|
||||
expect_equal(as.character(suppressMessages(
|
||||
as.sir(as.mic(64),
|
||||
mo = "B_ACHRMB_XYLS", ab = "MEM",
|
||||
guideline = "MyLab 2025", reference_data = my_bp
|
||||
)
|
||||
)), "R")
|
||||
})
|
||||
|
||||
test_that("custom reference_data: host = NA acts as host-agnostic fallback", {
|
||||
my_bp <- clinical_breakpoints[clinical_breakpoints$method == "MIC" &
|
||||
clinical_breakpoints$type == "human", ][1, ]
|
||||
my_bp$guideline <- "MyLab 2025"
|
||||
my_bp$mo <- "B_ACHRMB_XYLS"
|
||||
my_bp$ab <- "MEM"
|
||||
my_bp$type <- "animal"
|
||||
my_bp$host <- NA # logical NA — coerced to character by coerce_reference_data_columns()
|
||||
my_bp$breakpoint_S <- 8
|
||||
my_bp$breakpoint_R <- 32
|
||||
|
||||
# NA host should match when no species-specific row exists
|
||||
result <- suppressMessages(
|
||||
as.sir(as.mic(64),
|
||||
mo = "B_ACHRMB_XYLS", ab = "MEM",
|
||||
host = "dogs", breakpoint_type = "animal", reference_data = my_bp
|
||||
)
|
||||
)
|
||||
expect_equal(as.character(result), "R")
|
||||
# so parallel on Apple M2 is 2.8x faster, with identical history -> GREAT!
|
||||
})
|
||||
|
||||
@@ -89,11 +89,6 @@ test_that("test-zzz.R", {
|
||||
"symbol" = "cli",
|
||||
# curl
|
||||
"has_internet" = "curl",
|
||||
# future
|
||||
"plan" = "future",
|
||||
"nbrOfWorkers" = "future",
|
||||
# future.apply
|
||||
"future_lapply" = "future.apply",
|
||||
# ggplot2
|
||||
"aes" = "ggplot2",
|
||||
"arrow" = "ggplot2",
|
||||
@@ -132,6 +127,8 @@ test_that("test-zzz.R", {
|
||||
"kable" = "knitr",
|
||||
"knit_print" = "knitr",
|
||||
"opts_chunk" = "knitr",
|
||||
# parallelly
|
||||
"availableCores" = "parallelly",
|
||||
# pillar
|
||||
"pillar_shaft" = "pillar",
|
||||
"style_na" = "pillar",
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
# Benchmark: sequential vs parallel as.sir() across data-set shapes
|
||||
#
|
||||
# Run from the repo root:
|
||||
# Rscript tools/benchmark_parallel.R
|
||||
# or inside an R session:
|
||||
# source("tools/benchmark_parallel.R")
|
||||
#
|
||||
# Two panels:
|
||||
# Left – fixed columns (n_ab_fixed), varying rows.
|
||||
# Parallel wins at small n; sequential catches up at large n due to
|
||||
# memory-bandwidth saturation (all workers compete for the same
|
||||
# clinical_breakpoints lookup table in L3 cache / RAM).
|
||||
# Right – fixed rows (n_rows_fixed), varying column count.
|
||||
# This is the shape that actually benefits: each additional column
|
||||
# keeps another core busy. The "real world" gain for a 2854×65
|
||||
# dataset lives here.
|
||||
#
|
||||
# Requires ggplot2; uses devtools::load_all() so the package need not be
|
||||
# installed.
|
||||
|
||||
devtools::load_all(".", quiet = TRUE)
|
||||
|
||||
# ── configuration ─────────────────────────────────────────────────────────────
|
||||
row_sizes <- c(200, 1000, 5000, 20000)
|
||||
col_sizes <- c(4, 8, 16, 32, 48)
|
||||
n_rows_fixed <- 1000
|
||||
n_ab_fixed <- 16
|
||||
n_cores_avail <- AMR:::get_n_cores(Inf)
|
||||
|
||||
all_abs <- c("AMC", "GEN", "CIP", "TZP", "IPM", "MEM",
|
||||
"AMP", "TMP", "SXT", "NIT", "FOX", "CRO",
|
||||
"FEP", "CAZ", "CTX", "TOB", "AMK", "ERY",
|
||||
"AZM", "CLI", "VAN", "TEC", "RIF", "MTR",
|
||||
"MFX", "LNZ", "TGC", "DOX", "FLC", "OXA",
|
||||
"PEN", "CXM", "CZO", "KAN", "COL", "FOS",
|
||||
"MUP", "TCY", "TEC", "IPM", "CHL", "FEP",
|
||||
"MEM", "TZP", "GEN", "AMC", "AMX", "AMP")
|
||||
all_abs <- unique(all_abs)
|
||||
|
||||
mic_vals <- c("0.25", "0.5", "1", "2", "4", "8", "16", "32")
|
||||
|
||||
make_df <- function(n_rows, n_ab) {
|
||||
set.seed(42)
|
||||
ab_sel <- all_abs[seq_len(min(n_ab, length(all_abs)))]
|
||||
mics <- lapply(ab_sel, function(a) as.mic(sample(mic_vals, n_rows, TRUE)))
|
||||
names(mics) <- ab_sel
|
||||
data.frame(mo = "B_ESCHR_COLI", mics, stringsAsFactors = FALSE)
|
||||
}
|
||||
|
||||
time_both <- function(n_rows, n_ab, label) {
|
||||
df <- make_df(n_rows, n_ab)
|
||||
t_seq <- system.time(
|
||||
suppressMessages(as.sir(df, col_mo = "mo", info = FALSE, parallel = FALSE))
|
||||
)[["elapsed"]]
|
||||
t_par <- system.time(
|
||||
suppressMessages(as.sir(df, col_mo = "mo", info = FALSE, parallel = TRUE))
|
||||
)[["elapsed"]]
|
||||
message(sprintf("%-28s seq=%5.2fs par=%5.2fs speedup=%.1fx",
|
||||
label, t_seq, t_par, t_seq / t_par))
|
||||
data.frame(group = label, mode = c("sequential", "parallel"),
|
||||
seconds = c(t_seq, t_par), stringsAsFactors = FALSE)
|
||||
}
|
||||
|
||||
# ── warm-up (avoid first-call overhead biasing results) ───────────────────────
|
||||
message("Warming up cache ...")
|
||||
invisible(suppressMessages(as.sir(make_df(100, 6), col_mo = "mo", info = FALSE)))
|
||||
invisible(suppressMessages(as.sir(make_df(100, 6), col_mo = "mo", info = FALSE, parallel = TRUE)))
|
||||
sir_interpretation_history(clean = TRUE)
|
||||
|
||||
# ── panel 1: vary rows, fixed columns ─────────────────────────────────────────
|
||||
message(sprintf("\nPanel 1 – varying rows, %d fixed columns:", n_ab_fixed))
|
||||
res_rows <- do.call(rbind, lapply(row_sizes, function(n) {
|
||||
time_both(n, n_ab_fixed, sprintf("rows=%d", n))
|
||||
}))
|
||||
res_rows$x <- rep(row_sizes, each = 2)
|
||||
res_rows$panel <- "Vary rows (16 fixed AB columns)"
|
||||
|
||||
# ── panel 2: vary columns, fixed rows ─────────────────────────────────────────
|
||||
message(sprintf("\nPanel 2 – varying columns, %d fixed rows:", n_rows_fixed))
|
||||
res_cols <- do.call(rbind, lapply(col_sizes, function(n_ab) {
|
||||
time_both(n_rows_fixed, n_ab, sprintf("cols=%d", n_ab))
|
||||
}))
|
||||
res_cols$x <- rep(col_sizes, each = 2)
|
||||
res_cols$panel <- sprintf("Vary columns (%d fixed rows)", n_rows_fixed)
|
||||
|
||||
results <- rbind(res_rows, res_cols)
|
||||
|
||||
if (requireNamespace("ggplot2", quietly = TRUE)) {
|
||||
p <- ggplot2::ggplot(
|
||||
results,
|
||||
ggplot2::aes(x = x, y = seconds, colour = mode, group = mode)
|
||||
) +
|
||||
ggplot2::geom_line(linewidth = 1) +
|
||||
ggplot2::geom_point(size = 2.5) +
|
||||
ggplot2::facet_wrap(~panel, scales = "free_x") +
|
||||
ggplot2::scale_colour_manual(
|
||||
values = c(sequential = "#E05C5C", parallel = "#2E86AB")
|
||||
) +
|
||||
ggplot2::labs(
|
||||
title = "as.sir() throughput: sequential vs parallel",
|
||||
subtitle = sprintf("E. coli, EUCAST 2026, %d cores available", n_cores_avail),
|
||||
x = "Dataset dimension (rows ·left· or columns ·right·)",
|
||||
y = "Wall-clock time (seconds)",
|
||||
colour = NULL
|
||||
) +
|
||||
ggplot2::theme_minimal(base_size = 12) +
|
||||
ggplot2::theme(legend.position = "top")
|
||||
|
||||
out_file <- "tools/benchmark_parallel.png"
|
||||
ggplot2::ggsave(out_file, p, width = 10, height = 5, dpi = 150)
|
||||
message("\nPlot saved to ", out_file)
|
||||
} else {
|
||||
message("Install ggplot2 to get a plot; raw results:")
|
||||
print(results[, c("panel", "group", "mode", "seconds")])
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB |
@@ -268,8 +268,7 @@ To create a traditional antibiogram, simply state which antibiotics should be us
|
||||
|
||||
```{r trad}
|
||||
antibiogram(example_isolates,
|
||||
antibiotics = c(aminoglycosides(), carbapenems())
|
||||
)
|
||||
antibiotics = c(aminoglycosides(), carbapenems()))
|
||||
```
|
||||
|
||||
Notice that the `antibiogram()` function automatically prints in the right format when using Quarto or R Markdown (such as this page), and even applies italics for taxonomic names (by using `italicise_taxonomy()` internally).
|
||||
@@ -278,11 +277,10 @@ It also uses the language of your OS if this is either `r AMR:::vector_or(vapply
|
||||
|
||||
```{r trad2}
|
||||
antibiogram(example_isolates,
|
||||
mo_transform = "gramstain",
|
||||
antibiotics = aminoglycosides(),
|
||||
ab_transform = "name",
|
||||
language = "es"
|
||||
)
|
||||
mo_transform = "gramstain",
|
||||
antibiotics = aminoglycosides(),
|
||||
ab_transform = "name",
|
||||
language = "es")
|
||||
```
|
||||
|
||||
### Combined Antibiogram
|
||||
@@ -291,9 +289,8 @@ To create a combined antibiogram, use antibiotic codes or names with a plus `+`
|
||||
|
||||
```{r comb}
|
||||
combined_ab <- antibiogram(example_isolates,
|
||||
antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"),
|
||||
ab_transform = NULL
|
||||
)
|
||||
antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"),
|
||||
ab_transform = NULL)
|
||||
combined_ab
|
||||
```
|
||||
|
||||
@@ -303,9 +300,8 @@ To create a syndromic antibiogram, the `syndromic_group` argument must be used.
|
||||
|
||||
```{r synd}
|
||||
antibiogram(example_isolates,
|
||||
antibiotics = c(aminoglycosides(), carbapenems()),
|
||||
syndromic_group = "ward"
|
||||
)
|
||||
antibiotics = c(aminoglycosides(), carbapenems()),
|
||||
syndromic_group = "ward")
|
||||
```
|
||||
|
||||
### Weighted-Incidence Syndromic Combination Antibiogram (WISCA)
|
||||
@@ -314,10 +310,8 @@ To create a **Weighted-Incidence Syndromic Combination Antibiogram (WISCA)**, si
|
||||
|
||||
```{r wisca}
|
||||
example_isolates %>%
|
||||
wisca(
|
||||
antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"),
|
||||
minimum = 10
|
||||
) # Recommended threshold: ≥30
|
||||
wisca(antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"),
|
||||
minimum = 10) # Recommended threshold: ≥30
|
||||
```
|
||||
|
||||
WISCA uses a **Bayesian decision model** to integrate data from multiple pathogens, improving empirical therapy guidance, especially for low-incidence infections. It is **pathogen-agnostic**, meaning results are syndrome-based rather than stratified by microorganism.
|
||||
@@ -329,10 +323,8 @@ For **patient- or syndrome-specific WISCA**, run the function on a grouped `tibb
|
||||
```{r wisca_grouped}
|
||||
example_isolates %>%
|
||||
top_n_microorganisms(n = 10) %>%
|
||||
group_by(
|
||||
age_group = age_groups(age, c(25, 50, 75)),
|
||||
gender
|
||||
) %>%
|
||||
group_by(age_group = age_groups(age, c(25, 50, 75)),
|
||||
gender) %>%
|
||||
wisca(antibiotics = c("TZP", "TZP+TOB", "TZP+GEN"))
|
||||
```
|
||||
|
||||
@@ -387,21 +379,17 @@ We can visualise MIC distributions and their SIR interpretations using `ggplot2`
|
||||
|
||||
```{r mic_plot}
|
||||
# add a group
|
||||
my_data$group <- rep(c("A", "B", "C", "D"), each = 25)
|
||||
my_data$group <- rep(c("A", "B", "C", "D"), each = 25)
|
||||
|
||||
ggplot(
|
||||
my_data,
|
||||
aes(x = group, y = MIC, colour = SIR)
|
||||
) +
|
||||
ggplot(my_data,
|
||||
aes(x = group, y = MIC, colour = SIR)) +
|
||||
geom_jitter(width = 0.2, size = 2) +
|
||||
geom_boxplot(fill = NA, colour = "grey40") +
|
||||
scale_y_mic() +
|
||||
scale_colour_sir() +
|
||||
labs(
|
||||
title = "MIC Distribution and SIR Interpretation",
|
||||
x = "Sample Groups",
|
||||
y = "MIC (mg/L)"
|
||||
)
|
||||
labs(title = "MIC Distribution and SIR Interpretation",
|
||||
x = "Sample Groups",
|
||||
y = "MIC (mg/L)")
|
||||
```
|
||||
|
||||
This plot provides an intuitive way to assess susceptibility patterns across different groups while incorporating clinical breakpoints.
|
||||
|
||||
@@ -53,8 +53,8 @@ We begin by loading the required libraries and preparing the `example_isolates`
|
||||
|
||||
```{r lib packages, message = FALSE, warning = FALSE, results = 'asis'}
|
||||
# Load required libraries
|
||||
library(AMR) # For AMR data analysis
|
||||
library(tidymodels) # For machine learning workflows, and data manipulation (dplyr, tidyr, ...)
|
||||
library(AMR) # For AMR data analysis
|
||||
library(tidymodels) # For machine learning workflows, and data manipulation (dplyr, tidyr, ...)
|
||||
```
|
||||
|
||||
Prepare the data:
|
||||
@@ -68,19 +68,13 @@ data <- example_isolates %>%
|
||||
# select AB results dynamically
|
||||
select(mo, aminoglycosides(), betalactams()) %>%
|
||||
# replace NAs with NI (not-interpretable)
|
||||
mutate(
|
||||
across(
|
||||
where(is.sir),
|
||||
~ replace_na(.x, "NI")
|
||||
),
|
||||
# make factors of SIR columns
|
||||
across(
|
||||
where(is.sir),
|
||||
as.integer
|
||||
),
|
||||
# get Gramstain of microorganisms
|
||||
mo = as.factor(mo_gramstain(mo))
|
||||
) %>%
|
||||
mutate(across(where(is.sir),
|
||||
~replace_na(.x, "NI")),
|
||||
# make factors of SIR columns
|
||||
across(where(is.sir),
|
||||
as.integer),
|
||||
# get Gramstain of microorganisms
|
||||
mo = as.factor(mo_gramstain(mo))) %>%
|
||||
# drop NAs - the ones without a Gramstain (fungi, etc.)
|
||||
drop_na()
|
||||
```
|
||||
@@ -155,7 +149,7 @@ To train the model, we split the data into training and testing sets. Then, we f
|
||||
set.seed(123) # For reproducibility
|
||||
data_split <- initial_split(data, prop = 0.8) # 80% training, 20% testing
|
||||
training_data <- training(data_split) # Training set
|
||||
testing_data <- testing(data_split) # Testing set
|
||||
testing_data <- testing(data_split) # Testing set
|
||||
|
||||
# Fit the workflow to the training data
|
||||
fitted_workflow <- resistance_workflow %>%
|
||||
@@ -174,7 +168,7 @@ Next, we evaluate the model on the testing data.
|
||||
```{r}
|
||||
# Make predictions on the testing set
|
||||
predictions <- fitted_workflow %>%
|
||||
predict(testing_data) # Generate predictions
|
||||
predict(testing_data) # Generate predictions
|
||||
probabilities <- fitted_workflow %>%
|
||||
predict(testing_data, type = "prob") # Generate probabilities
|
||||
|
||||
@@ -272,8 +266,8 @@ testing_data <- testing(split)
|
||||
|
||||
# Define the recipe
|
||||
mic_recipe <- recipe(esbl ~ ., data = training_data) %>%
|
||||
remove_role(genus, old_role = "predictor") %>% # Remove non-informative variable
|
||||
step_mic_log2(all_mic_predictors()) # Log2 transform all MIC predictors
|
||||
remove_role(genus, old_role = "predictor") %>% # Remove non-informative variable
|
||||
step_mic_log2(all_mic_predictors()) # Log2 transform all MIC predictors
|
||||
|
||||
prep(mic_recipe)
|
||||
```
|
||||
@@ -347,11 +341,9 @@ library(ggplot2)
|
||||
|
||||
ggplot(predictions, aes(x = esbl, fill = .pred_class)) +
|
||||
geom_bar(position = "stack") +
|
||||
labs(
|
||||
title = "Predicted vs Actual ESBL Status",
|
||||
x = "Actual ESBL",
|
||||
y = "Count"
|
||||
) +
|
||||
labs(title = "Predicted vs Actual ESBL Status",
|
||||
x = "Actual ESBL",
|
||||
y = "Count") +
|
||||
theme_minimal()
|
||||
```
|
||||
|
||||
@@ -359,27 +351,18 @@ And plot the certainties too - how certain were the actual predictions?
|
||||
|
||||
```{r}
|
||||
predictions %>%
|
||||
mutate(
|
||||
certainty = ifelse(.pred_class == "FALSE",
|
||||
.pred_FALSE,
|
||||
.pred_TRUE
|
||||
),
|
||||
correct = ifelse(esbl == .pred_class, "Right", "Wrong")
|
||||
) %>%
|
||||
ggplot(aes(
|
||||
x = seq_len(nrow(predictions)),
|
||||
y = certainty,
|
||||
colour = correct
|
||||
)) +
|
||||
scale_colour_manual(
|
||||
values = c(Right = "green3", Wrong = "red2"),
|
||||
name = "Correct?"
|
||||
) +
|
||||
mutate(certainty = ifelse(.pred_class == "FALSE",
|
||||
.pred_FALSE,
|
||||
.pred_TRUE),
|
||||
correct = ifelse(esbl == .pred_class, "Right", "Wrong")) %>%
|
||||
ggplot(aes(x = seq_len(nrow(predictions)),
|
||||
y = certainty,
|
||||
colour = correct)) +
|
||||
scale_colour_manual(values = c(Right = "green3", Wrong = "red2"),
|
||||
name = "Correct?") +
|
||||
geom_point() +
|
||||
scale_y_continuous(
|
||||
labels = function(x) paste0(x * 100, "%"),
|
||||
limits = c(0.5, 1)
|
||||
) +
|
||||
scale_y_continuous(labels = function(x) paste0(x * 100, "%"),
|
||||
limits = c(0.5, 1)) +
|
||||
theme_minimal()
|
||||
```
|
||||
|
||||
@@ -416,18 +399,13 @@ library(tidymodels)
|
||||
# Transform dataset
|
||||
data_time <- example_isolates %>%
|
||||
top_n_microorganisms(n = 10) %>% # Filter on the top #10 species
|
||||
mutate(
|
||||
year = as.integer(format(date, "%Y")), # Extract year from date
|
||||
gramstain = mo_gramstain(mo)
|
||||
) %>% # Get taxonomic names
|
||||
mutate(year = as.integer(format(date, "%Y")), # Extract year from date
|
||||
gramstain = mo_gramstain(mo)) %>% # Get taxonomic names
|
||||
group_by(year, gramstain) %>%
|
||||
summarise(
|
||||
across(c(AMX, AMC, CIP),
|
||||
function(x) resistance(x, minimum = 0),
|
||||
.names = "res_{.col}"
|
||||
),
|
||||
.groups = "drop"
|
||||
) %>%
|
||||
summarise(across(c(AMX, AMC, CIP),
|
||||
function(x) resistance(x, minimum = 0),
|
||||
.names = "res_{.col}"),
|
||||
.groups = "drop") %>%
|
||||
filter(!is.na(res_AMX) & !is.na(res_AMC) & !is.na(res_CIP)) # Drop missing values
|
||||
|
||||
data_time
|
||||
@@ -448,9 +426,9 @@ We now define the modelling workflow, which consists of a preprocessing step, a
|
||||
```{r}
|
||||
# Define the recipe
|
||||
resistance_recipe_time <- recipe(res_AMX ~ year + gramstain, data = data_time) %>%
|
||||
step_dummy(gramstain, one_hot = TRUE) %>% # Convert categorical to numerical
|
||||
step_normalize(year) %>% # Normalise year for better model performance
|
||||
step_nzv(all_predictors()) # Remove near-zero variance predictors
|
||||
step_dummy(gramstain, one_hot = TRUE) %>% # Convert categorical to numerical
|
||||
step_normalize(year) %>% # Normalise year for better model performance
|
||||
step_nzv(all_predictors()) # Remove near-zero variance predictors
|
||||
|
||||
resistance_recipe_time
|
||||
```
|
||||
@@ -536,11 +514,9 @@ library(ggplot2)
|
||||
ggplot(predictions_time, aes(x = year)) +
|
||||
geom_point(aes(y = res_AMX, color = "Actual")) +
|
||||
geom_line(aes(y = .pred, color = "Predicted")) +
|
||||
labs(
|
||||
title = "Predicted vs Actual AMX Resistance Over Time",
|
||||
x = "Year",
|
||||
y = "Resistance Proportion"
|
||||
) +
|
||||
labs(title = "Predicted vs Actual AMX Resistance Over Time",
|
||||
x = "Year",
|
||||
y = "Resistance Proportion") +
|
||||
theme_minimal()
|
||||
```
|
||||
|
||||
@@ -549,17 +525,13 @@ Additionally, we can visualise resistance trends in `ggplot2` and directly add l
|
||||
```{r}
|
||||
ggplot(data_time, aes(x = year, y = res_AMX, color = gramstain)) +
|
||||
geom_line() +
|
||||
labs(
|
||||
title = "AMX Resistance Trends",
|
||||
x = "Year",
|
||||
y = "Resistance Proportion"
|
||||
) +
|
||||
labs(title = "AMX Resistance Trends",
|
||||
x = "Year",
|
||||
y = "Resistance Proportion") +
|
||||
# add a linear model directly in ggplot2:
|
||||
geom_smooth(
|
||||
method = "lm",
|
||||
formula = y ~ x,
|
||||
alpha = 0.25
|
||||
) +
|
||||
geom_smooth(method = "lm",
|
||||
formula = y ~ x,
|
||||
alpha = 0.25) +
|
||||
theme_minimal()
|
||||
```
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ data <- tibble::tibble(
|
||||
CAZ = "-", # Ceftazidime
|
||||
CXM = "-", # Cefuroxime
|
||||
PEN = "S", # Benzylenicillin
|
||||
FOX = "S" # Cefoxitin
|
||||
FOX = "S" # Cefoxitin
|
||||
)
|
||||
```
|
||||
```{r, eval = FALSE}
|
||||
|
||||
@@ -147,35 +147,31 @@ data$syndrome <- ifelse(data$mo %like% "coli", "UTI", "No UTI")
|
||||
|
||||
```{r}
|
||||
wisca(data,
|
||||
antimicrobials = c("AMC", "CIP", "GEN")
|
||||
)
|
||||
antimicrobials = c("AMC", "CIP", "GEN"))
|
||||
```
|
||||
|
||||
### Use combination regimens
|
||||
|
||||
```{r}
|
||||
wisca(data,
|
||||
antimicrobials = c("AMC", "AMC + CIP", "AMC + GEN")
|
||||
)
|
||||
antimicrobials = c("AMC", "AMC + CIP", "AMC + GEN"))
|
||||
```
|
||||
|
||||
### Stratify by syndrome
|
||||
|
||||
```{r}
|
||||
wisca(data,
|
||||
antimicrobials = c("AMC", "AMC + CIP", "AMC + GEN"),
|
||||
syndromic_group = "syndrome"
|
||||
)
|
||||
antimicrobials = c("AMC", "AMC + CIP", "AMC + GEN"),
|
||||
syndromic_group = "syndrome")
|
||||
```
|
||||
|
||||
The `AMR` package is available in `r length(AMR:::LANGUAGES_SUPPORTED)` languages, which can all be used for the `wisca()` function too:
|
||||
|
||||
```{r}
|
||||
wisca(data,
|
||||
antimicrobials = c("AMC", "AMC + CIP", "AMC + GEN"),
|
||||
syndromic_group = gsub("UTI", "UCI", data$syndrome),
|
||||
language = "Spanish"
|
||||
)
|
||||
antimicrobials = c("AMC", "AMC + CIP", "AMC + GEN"),
|
||||
syndromic_group = gsub("UTI", "UCI", data$syndrome),
|
||||
language = "Spanish")
|
||||
```
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user