diff --git a/DESCRIPTION b/DESCRIPTION index 426797e1..cc76b85b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: AMR -Version: 1.8.2.9039 -Date: 2022-10-30 +Version: 1.8.2.9040 +Date: 2022-10-31 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 diff --git a/NEWS.md b/NEWS.md index fd5a6c71..a0e4a06f 100755 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -# AMR 1.8.2.9039 +# AMR 1.8.2.9040 This version will eventually become v2.0! We're happy to reach a new major milestone soon! @@ -15,32 +15,35 @@ This version will eventually become v2.0! We're happy to reach a new major miles ### New * EUCAST 2022 and CLSI 2022 guidelines have been added for `as.rsi()`. EUCAST 2022 is now the new default guideline for all MIC and disks diffusion interpretations. +* Support for the following languages: Chinese, Greek, Japanese, Polish, Turkish and Ukrainian. We are very grateful for the valuable input by our colleagues from other countries. The `AMR` package is now available in 16 languages. The automatic language determination will give a note at start-up on systems in supported languages. * All new algorithm for `as.mo()` (and thus all `mo_*()` functions) while still following our original set-up as described in our paper (DOI 10.18637/jss.v104.i03). * A new argument `keep_synonyms` allows to *not* correct for updated taxonomy, in favour of the now deleted argument `allow_uncertain` * It has increased tremendously in speed and returns generally more consequent results * Sequential coercion is now extremely fast as results are stored to the package environment, although coercion of unknown values must be run once per session. Previous results can be reset/removed with the new `mo_reset_session()` function. -* Support for microorganism codes of the ASIan Antimicrobial Resistance Surveillance Network (ASIARS-Net) -* Function `rsi_confidence_interval()` to add confidence intervals in AMR calculation. This is also included in `rsi_df()` and `proportion_df()` -* Function `mean_amr_distance()` to calculate the mean AMR distance. The mean AMR distance is a normalised numeric value to compare AMR test results and can help to identify similar isolates, without comparing antibiograms by hand. -* Function `rsi_interpretation_history()` to view the history of previous runs of `as.rsi()`. This returns a 'logbook' with the selected guideline, reference table and specific interpretation of each row in a data set on which `as.rsi()` was run. -* Function `mo_current()` to get the currently valid taxonomic name of a microorganism -* Function `add_custom_antimicrobials()` to add custom antimicrobial codes and names to the `AMR` package -* Support for `data.frame`-enhancing R packages, more specifically: `data.table::data.table`, `janitor::tabyl`, `tibble::tibble`, and `tsibble::tsibble`. AMR package functions that have a data set as output (such as `rsi_df()` and `bug_drug_combinations()`), will now return the same data type as the input. -* All data sets in this package are now exported as `tibble`, instead of base R `data.frame`s. Older R versions are still supported. -* Support for the following languages: Chinese, Greek, Japanese, Polish, Turkish and Ukrainian. We are very grateful for the valuable input by our colleagues from other countries. The `AMR` package is now available in 16 languages. The automatic language determination will give a note at start-up on systems in supported languages. -* Our data sets are now also continually exported to Apache Feather and Apache Parquet formats. You can find more info [in this article on our website](https://msberends.github.io/AMR/articles/datasets.html). -* Support for using antibiotic selectors in scoped `dplyr` verbs (with or without `vars()`), such as in: `... %>% summarise_at(aminoglycosides(), resistance)`, see `resistance()` -* Support for antimicrobial interpretation of anaerobic bacteria, by adding a 'placeholder' code `B_ANAER` to the `microorganisms` data set and add the breakpoints of anaerobics to the `rsi_interpretation` data set, which is used by `as.rsi()` when interpreting MIC and disk diffusion values + * Support for microorganism codes of the ASIan Antimicrobial Resistance Surveillance Network (ASIARS-Net) + +* New functions! + * Function `rsi_confidence_interval()` to add confidence intervals in AMR calculation. This is also included in `rsi_df()` and `proportion_df()` + * Function `mean_amr_distance()` to calculate the mean AMR distance. The mean AMR distance is a normalised numeric value to compare AMR test results and can help to identify similar isolates, without comparing antibiograms by hand. + * Function `rsi_interpretation_history()` to view the history of previous runs of `as.rsi()`. This returns a 'logbook' with the selected guideline, reference table and specific interpretation of each row in a data set on which `as.rsi()` was run. + * Function `mo_current()` to get the currently valid taxonomic name of a microorganism + * Function `add_custom_antimicrobials()` to add custom antimicrobial codes and names to the `AMR` package * New and updated entries for the `antibiotics` data set * The following 20 antibiotics have been added (also includes the [new J01RA ATC group](https://www.whocc.no/atc_ddd_index/?code=J01RA&showdescription=no)): azithromycin/fluconazole/secnidazole (AFC), cefepime/amikacin (CFA), cefixime/ornidazole (CEO), ceftriaxone/beta-lactamase inhibitor (CEB), ciprofloxacin/metronidazole (CIM), ciprofloxacin/ornidazole (CIO), ciprofloxacin/tinidazole (CIT), furazidin (FUR), isoniazid/sulfamethoxazole/trimethoprim/pyridoxine (IST), lascufloxacin (LSC), levofloxacin/ornidazole (LEO), nemonoxacin (NEM), norfloxacin/metronidazole (NME), norfloxacin/tinidazole (NTI), ofloxacin/ornidazole (OOR), oteseconazole (OTE), rifampicin/ethambutol/isoniazid (REI), sarecycline (SRC), tetracycline/oleandomycin (TOL), and thioacetazone (TAT) * Added some missing ATC codes * Updated DDDs and PubChem Compound IDs * Updated some antibiotic name spelling, now used by WHOCC (such as cephalexin -> cefalexin, and phenethicillin -> pheneticillin) + * Antibiotic code "CEI" for ceftolozane/tazobactam has been replaced with "CZT" to comply with EARS-Net and WHONET 2022. The old code will still work in all cases when using `as.ab()` or any of the `ab_*()` functions. + * Support for antimicrobial interpretation of anaerobic bacteria, by adding a 'placeholder' code `B_ANAER` to the `microorganisms` data set and add the breakpoints of anaerobics to the `rsi_interpretation` data set, which is used by `as.rsi()` when interpreting MIC and disk diffusion values +* Support for `data.frame`-enhancing R packages, more specifically: `data.table::data.table`, `janitor::tabyl`, `tibble::tibble`, and `tsibble::tsibble`. AMR package functions that have a data set as output (such as `rsi_df()` and `bug_drug_combinations()`), will now return the same data type as the input. +* All data sets in this package are now exported as `tibble`, instead of base R `data.frame`s. Older R versions are still supported. +* Our data sets are now also continually exported to Apache Feather and Apache Parquet formats. You can find more info [in this article on our website](https://msberends.github.io/AMR/articles/datasets.html). +* Support for using antibiotic selectors in scoped `dplyr` verbs (with or without `vars()`), such as in: `... %>% summarise_at(aminoglycosides(), resistance)`, see `resistance()` ### Changed * Fix for using `as.rsi()` on certain EUCAST breakpoints for MIC values * Fix for using `as.rsi()` on `NA` values (e.g. `as.rsi(as.disk(NA), ...)`) -* Fix for using `as.rsi()` on drug-drug combinations with multiple breakpoints for different body sites +* Fix for using `as.rsi()` on bug-drug combinations with multiple breakpoints for different body sites * Removed `as.integer()` for MIC values, since MIC are not integer values and running `table()` on MIC values consequently failed for not being able to retrieve the level position (as that's how normally `as.integer()` on `factor`s work) * `droplevels()` on MIC will now return a common `factor` at default and will lose the `mic` class. Use `droplevels(..., as.mic = TRUE)` to keep the `mic` class. * Small fix for using `ab_from_text()` @@ -48,7 +51,7 @@ This version will eventually become v2.0! We're happy to reach a new major miles * Using any `random_*()` function (such as `random_mic()`) is now possible by directly calling the package without loading it first: `AMR::random_mic(10)` * Added *Toxoplasma gondii* (`P_TXPL_GOND`) to the `microorganisms` data set, together with its genus, family, and order * Changed value in column `prevalence` of the `microorganisms` data set from 3 to 2 for these genera: *Acholeplasma*, *Alistipes*, *Alloprevotella*, *Bergeyella*, *Borrelia*, *Brachyspira*, *Butyricimonas*, *Cetobacterium*, *Chlamydia*, *Chlamydophila*, *Deinococcus*, *Dysgonomonas*, *Elizabethkingia*, *Empedobacter*, *Haloarcula*, *Halobacterium*, *Halococcus*, *Myroides*, *Odoribacter*, *Ornithobacterium*, *Parabacteroides*, *Pedobacter*, *Phocaeicola*, *Porphyromonas*, *Riemerella*, *Sphingobacterium*, *Streptobacillus*, *Tenacibaculum*, *Terrimonas*, *Victivallis*, *Wautersiella*, *Weeksella* -* Fix for using the form `df[carbapenems() == "R", ]` when using the latest `vctrs` package +* Extended support for the `vctrs` package, used internally by the tidyverse. This allows to change values of class `mic`, `disk`, `rsi`, `mo` and `ab` in tibbles, and to use antibiotic selectors for selecting/filtering, e.g. `df[carbapenems() == "R", ]` * Fix for using `info = FALSE` in `mdro()` * For all interpretation guidelines using `as.rsi()` on amoxicillin, the rules for ampicillin will be used if amoxicillin rules are not available * Fix for using `ab_atc()` on non-existing ATC codes diff --git a/R/vctrs.R b/R/vctrs.R index dcaf1108..19759820 100644 --- a/R/vctrs.R +++ b/R/vctrs.R @@ -64,7 +64,10 @@ vec_ptype2.ab.character <- function(x, y, ...) { y } vec_cast.character.ab <- function(x, to, ...) { - unclass(x) + as.character(x) +} +vec_cast.ab.character <- function(x, to, ...) { + return_after_integrity_check(x, "antimicrobial code", as.character(AMR_env$AB_lookup$ab)) } # S3: mo @@ -75,7 +78,10 @@ vec_ptype2.mo.character <- function(x, y, ...) { y } vec_cast.character.mo <- function(x, to, ...) { - unclass(x) + as.character(x) +} +vec_cast.mo.character <- function(x, to, ...) { + return_after_integrity_check(x, "microorganism code", as.character(AMR::microorganisms$mo)) } # S3: disk @@ -88,15 +94,49 @@ vec_ptype2.disk.integer <- function(x, y, ...) { vec_cast.integer.disk <- function(x, to, ...) { unclass(x) } +vec_cast.disk.integer <- function(x, to, ...) { + as.disk(x) +} +vec_cast.double.disk <- function(x, to, ...) { + unclass(x) +} +vec_cast.disk.double <- function(x, to, ...) { + as.disk(x) +} +vec_cast.character.disk <- function(x, to, ...) { + unclass(x) +} +vec_cast.disk.character <- function(x, to, ...) { + as.disk(x) +} # S3: mic vec_cast.character.mic <- function(x, to, ...) { as.character(x) } vec_cast.double.mic <- function(x, to, ...) { - # this calls as.double.mic() as.double(x) } +vec_cast.mic.double <- function(x, to, ...) { + as.mic(x) +} +vec_cast.mic.character <- function(x, to, ...) { + as.mic(x) +} vec_math.mic <- function(.fn, x, ...) { .fn(as.double(x), ...) } + +# S3: rsi +vec_ptype2.character.rsi <- function(x, y, ...) { + x +} +vec_ptype2.rsi.character <- function(x, y, ...) { + y +} +vec_cast.character.rsi <- function(x, to, ...) { + as.character(x) +} +vec_cast.rsi.character <- function(x, to, ...) { + as.rsi(x) +} diff --git a/R/zzz.R b/R/zzz.R index d09c6083..80294f15 100755 --- a/R/zzz.R +++ b/R/zzz.R @@ -116,24 +116,44 @@ if (utf8_supported && !is_latex) { s3_register("ggplot2::fortify", "mic") s3_register("ggplot2::fortify", "disk") # Support vctrs package for use in e.g. dplyr verbs - s3_register("vctrs::vec_ptype2", "ab.character") - s3_register("vctrs::vec_ptype2", "character.ab") - s3_register("vctrs::vec_cast", "character.ab") - s3_register("vctrs::vec_ptype2", "mo.character") - s3_register("vctrs::vec_ptype2", "character.mo") - s3_register("vctrs::vec_cast", "character.mo") - s3_register("vctrs::vec_ptype2", "ab_selector.character") + # S3: ab_selector s3_register("vctrs::vec_ptype2", "character.ab_selector") + s3_register("vctrs::vec_ptype2", "ab_selector.character") s3_register("vctrs::vec_cast", "character.ab_selector") - s3_register("vctrs::vec_ptype2", "ab_selector_any_all.logical") + # S3: ab_selector_any_all s3_register("vctrs::vec_ptype2", "logical.ab_selector_any_all") + s3_register("vctrs::vec_ptype2", "ab_selector_any_all.logical") s3_register("vctrs::vec_cast", "logical.ab_selector_any_all") - s3_register("vctrs::vec_ptype2", "disk.integer") + # S3: ab + s3_register("vctrs::vec_ptype2", "character.ab") + s3_register("vctrs::vec_ptype2", "ab.character") + s3_register("vctrs::vec_cast", "character.ab") + s3_register("vctrs::vec_cast", "ab.character") + # S3: mo + s3_register("vctrs::vec_ptype2", "character.mo") + s3_register("vctrs::vec_ptype2", "mo.character") + s3_register("vctrs::vec_cast", "character.mo") + s3_register("vctrs::vec_cast", "mo.character") + # S3: disk s3_register("vctrs::vec_ptype2", "integer.disk") + s3_register("vctrs::vec_ptype2", "disk.integer") s3_register("vctrs::vec_cast", "integer.disk") + s3_register("vctrs::vec_cast", "disk.integer") + s3_register("vctrs::vec_cast", "double.disk") + s3_register("vctrs::vec_cast", "disk.double") + s3_register("vctrs::vec_cast", "character.disk") + s3_register("vctrs::vec_cast", "disk.character") + # S3: mic s3_register("vctrs::vec_cast", "character.mic") s3_register("vctrs::vec_cast", "double.mic") + s3_register("vctrs::vec_cast", "mic.character") + s3_register("vctrs::vec_cast", "mic.double") s3_register("vctrs::vec_math", "mic") + # S3: rsi + s3_register("vctrs::vec_ptype2", "character.rsi") + s3_register("vctrs::vec_ptype2", "rsi.character") + s3_register("vctrs::vec_cast", "character.rsi") + s3_register("vctrs::vec_cast", "rsi.character") # if mo source exists, fire it up (see mo_source()) if (tryCatch(file.exists(getOption("AMR_mo_source", "~/mo_source.rds")), error = function(e) FALSE)) { diff --git a/data/intrinsic_resistant.rda b/data/intrinsic_resistant.rda index c5ec0c9c..87f7dc0b 100644 Binary files a/data/intrinsic_resistant.rda and b/data/intrinsic_resistant.rda differ diff --git a/inst/tinytest/test-vctrs.R b/inst/tinytest/test-vctrs.R new file mode 100755 index 00000000..d9e2dc80 --- /dev/null +++ b/inst/tinytest/test-vctrs.R @@ -0,0 +1,53 @@ +# ==================================================================== # +# TITLE # +# AMR: An R Package for Working with Antimicrobial Resistance Data # +# # +# SOURCE # +# https://github.com/msberends/AMR # +# # +# CITE AS # +# Berends MS, Luz CF, Friedrich AW, Sinha BNM, Albers CJ, Glasner C # +# (2022). AMR: An R Package for Working with Antimicrobial Resistance # +# Data. Journal of Statistical Software, 104(3), 1-31. # +# doi:10.18637/jss.v104.i03 # +# # +# Developed at the University of Groningen, the Netherlands, in # +# collaboration with non-profit organisations Certe Medical # +# Diagnostics & Advice, and University Medical Center Groningen. # +# # +# This R package is free software; you can freely use and distribute # +# it for both personal and commercial purposes under the terms of the # +# GNU General Public License version 2.0 (GNU GPL-2), as published by # +# the Free Software Foundation. # +# We created this package for both routine data analysis and academic # +# research and it was publicly released in the hope that it will be # +# useful, but it comes WITHOUT ANY WARRANTY OR LIABILITY. # +# # +# Visit our website for the full manual and a complete tutorial about # +# how to conduct AMR data analysis: https://msberends.github.io/AMR/ # +# ==================================================================== # + +# extra tests for {vctrs} pkg support +if (pkg_is_available("dplyr", also_load = FALSE)) { + test <- dplyr::tibble(ab = as.ab("CIP"), + mo = as.mo("Escherichia coli"), + mic = as.mic(2), + disk = as.disk(20), + rsi = as.rsi("S")) + check1 <- lapply(test, class) + test[1, "ab"] <- "GEN" + test[1, "mo"] <- "B_KLBSL_PNMN" + test[1, "mic"] <- ">=32" + test[1, "mic"] <- 32 + test[1, "disk"] <- "35" + test[1, "disk"] <- 25 + test[1, "disk"] <- 26L + test[1, "rsi"] <- "R" + check2 <- lapply(test, class) + expect_identical(check1, check2) + + test <- dplyr::tibble(cipro = as.rsi("S"), + variable = "test") + expect_equal(nrow(test[quinolones() == "S", ]), 1) + expect_equal(nrow(test[quinolones() == "R", ]), 0) +}