From fdffc2791ba7d74f8794868d96ae978d62b4e8ef Mon Sep 17 00:00:00 2001
From: "Matthijs S. Berends"
Date: Fri, 15 Mar 2019 13:57:25 +0100
Subject: [PATCH] memory for as.mo()
---
.gitlab-ci.yml | 6 +-
DESCRIPTION | 4 +-
NAMESPACE | 1 +
NEWS.md | 53 +-
R/misc.R | 32 +-
R/mo.R | 155 +++++-
R/mo_history.R | 74 +++
R/mo_source.R | 21 +-
README.md | 10 +-
_pkgdown.yml | 10 +-
appveyor.yml | 3 -
docs/LICENSE-text.html | 2 +-
docs/articles/AMR.html | 467 +++++++++---------
.../AMR_files/figure-html/plot 1-1.png | Bin 35640 -> 35429 bytes
.../AMR_files/figure-html/plot 3-1.png | Bin 21140 -> 21146 bytes
.../AMR_files/figure-html/plot 4-1.png | Bin 69626 -> 69625 bytes
.../AMR_files/figure-html/plot 5-1.png | Bin 51370 -> 51366 bytes
docs/articles/EUCAST.html | 4 +-
docs/articles/G_test.html | 4 +-
docs/articles/SPSS.html | 4 +-
docs/articles/WHONET.html | 38 +-
docs/articles/atc_property.html | 4 +-
docs/articles/benchmarks.html | 99 ++--
.../figure-html/unnamed-chunk-5-1.png | Bin 28781 -> 26274 bytes
.../figure-html/unnamed-chunk-6-1.png | Bin 0 -> 26928 bytes
docs/articles/freq.html | 4 +-
docs/articles/index.html | 2 +-
docs/articles/mo_property.html | 4 +-
docs/articles/resistance_predict.html | 4 +-
docs/authors.html | 2 +-
docs/index.html | 2 +-
docs/news/index.html | 22 +-
docs/reference/AMR-deprecated.html | 2 +-
docs/reference/AMR.html | 2 +-
docs/reference/WHOCC.html | 2 +-
docs/reference/WHONET.html | 2 +-
docs/reference/abname.html | 2 +-
docs/reference/age.html | 2 +-
docs/reference/age_groups.html | 2 +-
docs/reference/antibiotics.html | 2 +-
docs/reference/as.atc.html | 2 +-
docs/reference/as.mic.html | 2 +-
docs/reference/as.mo.html | 18 +-
docs/reference/as.rsi.html | 6 +-
docs/reference/atc_online.html | 2 +-
docs/reference/atc_property.html | 2 +-
docs/reference/availability.html | 2 +-
docs/reference/catalogue_of_life.html | 2 +-
docs/reference/catalogue_of_life_version.html | 2 +-
docs/reference/count.html | 2 +-
docs/reference/eucast_rules.html | 2 +-
docs/reference/filter_ab_class.html | 2 +-
docs/reference/first_isolate.html | 2 +-
docs/reference/freq.html | 2 +-
docs/reference/g.test.html | 2 +-
docs/reference/get_locale.html | 2 +-
docs/reference/ggplot_rsi.html | 2 +-
docs/reference/guess_ab_col.html | 2 +-
docs/reference/index.html | 19 +-
docs/reference/join.html | 2 +-
docs/reference/key_antibiotics.html | 2 +-
docs/reference/kurtosis.html | 2 +-
docs/reference/like.html | 2 +-
docs/reference/mdro.html | 2 +-
docs/reference/microorganisms.codes.html | 2 +-
docs/reference/microorganisms.html | 2 +-
docs/reference/microorganisms.old.html | 2 +-
docs/reference/mo_property.html | 2 +-
docs/reference/mo_source.html | 2 +-
docs/reference/p.symbol.html | 2 +-
docs/reference/portion.html | 2 +-
docs/reference/read.4D.html | 2 +-
docs/reference/resistance_predict.html | 2 +-
docs/reference/rsi.html | 2 +-
docs/reference/septic_patients.html | 2 +-
docs/reference/skewness.html | 2 +-
man/as.mo.Rd | 14 +-
man/figures/logo_certe.png | Bin 0 -> 17383 bytes
man/figures/logo_eh1h.png | Bin 0 -> 11658 bytes
man/figures/logo_interreg.png | Bin 0 -> 11470 bytes
man/figures/logo_rug.png | Bin 0 -> 9579 bytes
man/figures/logo_umcg.png | Bin 0 -> 10895 bytes
tests/testthat/test-mo_history.R | 34 ++
vignettes/benchmarks.Rmd | 40 +-
84 files changed, 767 insertions(+), 477 deletions(-)
create mode 100644 R/mo_history.R
create mode 100644 docs/articles/benchmarks_files/figure-html/unnamed-chunk-6-1.png
create mode 100755 man/figures/logo_certe.png
create mode 100755 man/figures/logo_eh1h.png
create mode 100755 man/figures/logo_interreg.png
create mode 100755 man/figures/logo_rug.png
create mode 100755 man/figures/logo_umcg.png
create mode 100644 tests/testthat/test-mo_history.R
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0c081e01..b0b9fb4d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -61,10 +61,7 @@ cache:
R:
stage: build
allow_failure: false
- variables:
- WARNINGS_ARE_ERRORS: 1
script:
- - export WARNINGS_ARE_ERRORS=1
# remove vignettes folder and get VignetteBuilder field out of DESCRIPTION file
- rm -rf vignettes
- Rscript -e 'd <- read.dcf("DESCRIPTION"); d[, colnames(d) == "VignetteBuilder"] <- NA; write.dcf(d, "DESCRIPTION")'
@@ -86,7 +83,8 @@ coverage:
- master
script:
- apt-get install --yes git
- - Rscript -e 'cc <- covr::package_coverage(); covr::codecov(coverage = cc, token = "50ffa0aa-fee0-4f8b-a11d-8c7edc6d32ca"); cat("Code coverage:", covr::percent_coverage(cc))'
+ # codecov token is set in https://gitlab.com/msberends/AMR/settings/ci_cd
+ - Rscript -e 'cc <- covr::package_coverage(); covr::codecov(coverage = cc, token = "${codecov_token}"); cat("Code coverage:", covr::percent_coverage(cc))'
coverage: '/Code coverage: \d+\.\d+/'
pages:
diff --git a/DESCRIPTION b/DESCRIPTION
index b7a7e584..9a9b9fa5 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,6 +1,6 @@
Package: AMR
-Version: 0.5.0.9022
-Date: 2019-03-12
+Version: 0.5.0.9023
+Date: 2019-03-15
Title: Antimicrobial Resistance Analysis
Authors@R: c(
person(
diff --git a/NAMESPACE b/NAMESPACE
index f55cd80c..5ef332cf 100755
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -71,6 +71,7 @@ export(atc_umcg)
export(availability)
export(brmo)
export(catalogue_of_life_version)
+export(clean_mo_history)
export(count_I)
export(count_IR)
export(count_R)
diff --git a/NEWS.md b/NEWS.md
index 77b96a89..2d7bed2b 100755
--- a/NEWS.md
+++ b/NEWS.md
@@ -101,34 +101,35 @@ We've got a new website: [https://msberends.gitlab.io/AMR](https://msberends.git
* Function `guess_mo()` is now deprecated in favour of `as.mo()` and will be removed in future versions
* Function `guess_atc()` is now deprecated in favour of `as.atc()` and will be removed in future versions
* Improvements for `as.mo()`:
- * Now handles incorrect spelling like `i` instead of `y` and `f` instead of `ph`:
- ```r
- # mo_fullname() uses as.mo() internally
-
- mo_fullname("Sthafilokockus aaureuz")
- #> [1] "Staphylococcus aureus"
-
- mo_fullname("S. klossi")
- #> [1] "Staphylococcus kloosii"
- ```
+ * Now handles incorrect spelling, like `i` instead of `y` and `f` instead of `ph`:
+ ```r
+ # mo_fullname() uses as.mo() internally
+
+ mo_fullname("Sthafilokockus aaureuz")
+ #> [1] "Staphylococcus aureus"
+
+ mo_fullname("S. klossi")
+ #> [1] "Staphylococcus kloosii"
+ ```
* Uncertainty of the algorithm is now divided into four levels, 0 to 3, where the default `allow_uncertain = TRUE` is equal to uncertainty level 2. Run `?as.mo` for more info about these levels.
- ```r
- # equal:
- as.mo(..., allow_uncertain = TRUE)
- as.mo(..., allow_uncertain = 2)
-
- # also equal:
- as.mo(..., allow_uncertain = FALSE)
- as.mo(..., allow_uncertain = 0)
- ```
- Using `as.mo(..., allow_uncertain = 3)` could lead to very unreliable results.
+ ```r
+ # equal:
+ as.mo(..., allow_uncertain = TRUE)
+ as.mo(..., allow_uncertain = 2)
+
+ # also equal:
+ as.mo(..., allow_uncertain = FALSE)
+ as.mo(..., allow_uncertain = 0)
+ ```
+ Using `as.mo(..., allow_uncertain = 3)` could lead to very unreliable results.
+ * All microbial IDs that are found with zero uncertainty are now saved to a local file `~/.Rhistory_mo`. Use the new function `clean_mo_history()` to delete this file, which resets the algorithms.
* Incoercible results will now be considered 'unknown', MO code `UNKNOWN`. On foreign systems, properties of these will be translated to all languages already previously supported: German, Dutch, French, Italian, Spanish and Portuguese:
- ```r
- mo_genus("qwerty", language = "es")
- # Warning:
- # one unique value (^= 100.0%) could not be coerced and is considered 'unknown': "qwerty". Use mo_failures() to review it.
- #> [1] "(género desconocido)"
- ```
+ ```r
+ mo_genus("qwerty", language = "es")
+ # Warning:
+ # one unique value (^= 100.0%) could not be coerced and is considered 'unknown': "qwerty". Use mo_failures() to review it.
+ #> [1] "(género desconocido)"
+ ```
* Fix for vector containing only empty values
* Finds better results when input is in other languages
* Better handling for subspecies
diff --git a/R/misc.R b/R/misc.R
index ec634752..b153c951 100755
--- a/R/misc.R
+++ b/R/misc.R
@@ -75,7 +75,9 @@ check_available_columns <- function(tbl, col.list, info = TRUE) {
col.list.bak <- col.list
# are they available as upper case or lower case then?
for (i in 1:length(col.list)) {
- if (toupper(col.list[i]) %in% colnames(tbl)) {
+ if (is.null(col.list[i]) | isTRUE(is.na(col.list[i]))) {
+ col.list[i] <- NULL
+ } else if (toupper(col.list[i]) %in% colnames(tbl)) {
col.list[i] <- toupper(col.list[i])
} else if (tolower(col.list[i]) %in% colnames(tbl)) {
col.list[i] <- tolower(col.list[i])
@@ -124,7 +126,7 @@ size_humanreadable <- function(bytes, decimals = 1) {
out
}
-#' @importFrom crayon blue bold
+#' @importFrom crayon blue bold red
#' @importFrom dplyr %>% pull
search_type_in_df <- function(tbl, type) {
# try to find columns based on type
@@ -151,16 +153,22 @@ search_type_in_df <- function(tbl, type) {
}
# -- date
if (type == "date") {
- for (i in 1:ncol(tbl)) {
- if (any(colnames(tbl) %like% "^(Specimen date)")) {
- # WHONET support
- found <- colnames(tbl)[colnames(tbl) %like% "^(Specimen date)"][1]
- } else if ("Date" %in% class(tbl %>% pull(i)) | "POSIXct" %in% class(tbl %>% pull(i))) {
- found <- colnames(tbl)[i]
- break
+ if (any(colnames(tbl) %like% "^(specimen date|specimen_date|spec_date)")) {
+ # WHONET support
+ found <- colnames(tbl)[colnames(tbl) %like% "^(specimen date|specimen_date|spec_date)"][1]
+ if (!any(class(tbl %>% pull(found)) %in% c("Date", "POSIXct"))) {
+ stop(red(paste0("ERROR: Found column `", bold(found), "` to be used as input for `col_", type,
+ "`, but this column contains no valid dates. Transform its values to valid dates first.")),
+ call. = FALSE)
+ }
+ } else {
+ for (i in 1:ncol(tbl)) {
+ if (any(class(tbl %>% pull(i)) %in% c("Date", "POSIXct"))) {
+ found <- colnames(tbl)[i]
+ break
+ }
}
}
-
}
# -- patient id
if (type == "patient_id") {
@@ -170,8 +178,8 @@ search_type_in_df <- function(tbl, type) {
}
# -- specimen
if (type == "specimen") {
- if (any(colnames(tbl) %like% "(specimen type)")) {
- found <- colnames(tbl)[colnames(tbl) %like% "(specimen type)"][1]
+ if (any(colnames(tbl) %like% "(specimen type|spec_type)")) {
+ found <- colnames(tbl)[colnames(tbl) %like% "(specimen type|spec_type)"][1]
} else if (any(colnames(tbl) %like% "^(specimen)")) {
found <- colnames(tbl)[colnames(tbl) %like% "^(specimen)"][1]
}
diff --git a/R/mo.R b/R/mo.R
index 953b6aac..6379d3cf 100755
--- a/R/mo.R
+++ b/R/mo.R
@@ -31,10 +31,12 @@
#' This excludes \emph{Enterococci} at default (who are in group D), use \code{Lancefield = "all"} to also categorise all \emph{Enterococci} as group D.
#' @param allow_uncertain a logical (\code{TRUE} or \code{FALSE}) or a value between 0 and 3 to indicate whether the input should be checked for less possible results, see Details
#' @param reference_df a \code{data.frame} to use for extra reference when translating \code{x} to a valid \code{mo}. See \code{\link{set_mo_source}} and \code{\link{get_mo_source}} to automate the usage of your own codes (e.g. used in your analysis or organisation).
+#' @param ... other parameters passed on to functions
#' @rdname as.mo
#' @aliases mo
#' @keywords mo Becker becker Lancefield lancefield guess
#' @details
+#' \strong{General info} \cr
#' A microbial ID from this package (class: \code{mo}) typically looks like these examples:\cr
#' \preformatted{
#' Code Full name
@@ -53,7 +55,9 @@
#'
#' Values that cannot be coered will be considered 'unknown' and have an MO code \code{UNKNOWN}.
#'
-#' Use the \code{\link{mo_property}} functions to get properties based on the returned code, see Examples.
+#' Use the \code{\link{mo_property}_*} functions to get properties based on the returned code, see Examples.
+#'
+#' All IDs that are found with zero uncertainty are saved to a local file (\code{"~/.Rhistory_mo"}) to improve speed for every next time. Use \code{clean_mo_history()} to delete this file, which resets the algorithms. Only previous results will be used from this version of the \code{AMR} package, since the taxonomic tree may change in the future for any organism.
#'
#' \strong{Intelligent rules} \cr
#' This function uses intelligent rules to help getting fast and logical results. It tries to find matches in this order:
@@ -174,12 +178,14 @@
#' df <- df %>%
#' mutate(mo = as.mo(paste(genus, species)))
#' }
-as.mo <- function(x, Becker = FALSE, Lancefield = FALSE, allow_uncertain = TRUE, reference_df = get_mo_source()) {
+as.mo <- function(x, Becker = FALSE, Lancefield = FALSE, allow_uncertain = TRUE, reference_df = get_mo_source(), ...) {
if (!"AMR" %in% base::.packages()) {
library("AMR")
# check onLoad() in R/zzz.R: data tables are created there.
}
+ mo_hist <- get_mo_history(x, force = isTRUE(list(...)$force_mo_history))
+
if (mo_source_isvalid(reference_df)
& isFALSE(Becker)
& isFALSE(Lancefield)
@@ -211,6 +217,13 @@ as.mo <- function(x, Becker = FALSE, Lancefield = FALSE, allow_uncertain = TRUE,
& isFALSE(Lancefield)) {
y <- x
+
+ } else if (sum(is.na(mo_hist)) == 0
+ & isFALSE(Becker)
+ & isFALSE(Lancefield)) {
+ # check previously found results
+ y <- mo_hist
+
} else if (all(tolower(x) %in% microorganismsDT$fullname_lower)
& isFALSE(Becker)
& isFALSE(Lancefield)) {
@@ -229,13 +242,22 @@ as.mo <- function(x, Becker = FALSE, Lancefield = FALSE, allow_uncertain = TRUE,
on = "fullname_lower",
"mo"][[1]]
}
+ # save them too
+ mo_hist <- read_mo_history(force = isTRUE(list(...)$force_mo_history))
+ if (any(!x %in% mo_hist$x)) {
+ for (i in 1:length(y)) {
+ set_mo_history(x[i], y[i], force = isTRUE(list(...)$force_mo_history))
+ }
+ }
+
+ } else {
+ # will be checked for mo class in validation and uses exec_as.mo internally if necessary
+ y <- mo_validate(x = x, property = "mo",
+ Becker = Becker, Lancefield = Lancefield,
+ allow_uncertain = allow_uncertain, reference_df = reference_df,
+ force_mo_history = isTRUE(list(...)$force_mo_history))
+ }
- } else {
- # will be checked for mo class in validation and uses exec_as.mo internally if necessary
- y <- mo_validate(x = x, property = "mo",
- Becker = Becker, Lancefield = Lancefield,
- allow_uncertain = allow_uncertain, reference_df = reference_df)
- }
structure(.Data = y, class = "mo")
}
@@ -249,9 +271,14 @@ is.mo <- function(x) {
#' @importFrom dplyr %>% pull left_join n_distinct progress_estimated filter distinct
#' @importFrom data.table data.table as.data.table setkey
#' @importFrom crayon magenta red blue silver italic has_color
-exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
- allow_uncertain = TRUE, reference_df = get_mo_source(),
- property = "mo", clear_options = TRUE) {
+exec_as.mo <- function(x,
+ Becker = FALSE,
+ Lancefield = FALSE,
+ allow_uncertain = TRUE,
+ reference_df = get_mo_source(),
+ property = "mo",
+ clear_options = TRUE,
+ force_mo_history = FALSE) {
if (!"AMR" %in% base::.packages()) {
library("AMR")
@@ -412,7 +439,7 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
# replace hemolytic by haemolytic
x <- gsub("ha?emoly", "haemoly", x)
# place minus back in streptococci
- x <- gsub("(alpha|beta|gamma) ha?emoly", "\\1-haemoly", x)
+ x <- gsub("(alpha|beta|gamma).?ha?emoly", "\\1-haemoly", x)
# remove genus as first word
x <- gsub("^Genus ", "", x)
# allow characters that resemble others
@@ -458,6 +485,13 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
progress$tick()$print()
+ found <- microorganismsDT[mo == get_mo_history(x_backup[i], force = force_mo_history), ..property][[1]]
+ # previously found result
+ if (length(found) > 0) {
+ x[i] <- found[1L]
+ next
+ }
+
found <- microorganismsDT[mo == toupper(x_backup[i]), ..property][[1]]
# is a valid MO code
if (length(found) > 0) {
@@ -469,6 +503,9 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
# most probable: is exact match in fullname
if (length(found) > 0) {
x[i] <- found[1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
@@ -494,6 +531,9 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
# return first genus that begins with x_trimmed, e.g. when "E. spp."
if (length(found) > 0) {
x[i] <- found[1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
}
@@ -515,50 +555,80 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
if (!is.na(x_trimmed[i])) {
if (toupper(x_backup_without_spp[i]) %in% c('MRSA', 'MSSA', 'VISA', 'VRSA')) {
x[i] <- microorganismsDT[mo == 'B_STPHY_AUR', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (toupper(x_backup_without_spp[i]) %in% c('MRSE', 'MSSE')) {
x[i] <- microorganismsDT[mo == 'B_STPHY_EPI', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (toupper(x_backup_without_spp[i]) == "VRE"
| x_backup_without_spp[i] %like% '(enterococci|enterokok|enterococo)[a-z]*?$') {
x[i] <- microorganismsDT[mo == 'B_ENTRC', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (toupper(x_backup_without_spp[i]) %in% c("EHEC", "EPEC", "EIEC", "STEC", "ATEC")) {
x[i] <- microorganismsDT[mo == 'B_ESCHR_COL', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (toupper(x_backup_without_spp[i]) == 'MRPA') {
# multi resistant P. aeruginosa
x[i] <- microorganismsDT[mo == 'B_PSDMN_AER', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (toupper(x_backup_without_spp[i]) == 'CRS'
| toupper(x_backup_without_spp[i]) == 'CRSM') {
# co-trim resistant S. maltophilia
x[i] <- microorganismsDT[mo == 'B_STNTR_MAL', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (toupper(x_backup_without_spp[i]) %in% c('PISP', 'PRSP', 'VISP', 'VRSP')) {
# peni I, peni R, vanco I, vanco R: S. pneumoniae
x[i] <- microorganismsDT[mo == 'B_STRPT_PNE', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (x_backup_without_spp[i] %like% '^G[ABCDFGHK]S$') {
# Streptococci, like GBS = Group B Streptococci (B_STRPT_GRB)
x[i] <- microorganismsDT[mo == gsub("G([ABCDFGHK])S", "B_STRPT_GR\\1", x_backup_without_spp[i], ignore.case = TRUE), ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (x_backup_without_spp[i] %like% '(streptococ|streptokok).* [ABCDFGHK]$') {
# Streptococci in different languages, like "estreptococos grupo B"
x[i] <- microorganismsDT[mo == gsub(".*(streptococ|streptokok|estreptococ).* ([ABCDFGHK])$", "B_STRPT_GR\\2", x_backup_without_spp[i], ignore.case = TRUE), ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (x_backup_without_spp[i] %like% 'group [ABCDFGHK] (streptococ|streptokok|estreptococ)') {
# Streptococci in different languages, like "Group A Streptococci"
x[i] <- microorganismsDT[mo == gsub(".*group ([ABCDFGHK]) (streptococ|streptokok|estreptococ).*", "B_STRPT_GR\\1", x_backup_without_spp[i], ignore.case = TRUE), ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
# CoNS/CoPS in different languages (support for German, Dutch, Spanish, Portuguese) ----
@@ -567,6 +637,9 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
| x_backup_without_spp[i] %like% '[ck]o?ns[^a-z]?$') {
# coerce S. coagulase negative
x[i] <- microorganismsDT[mo == 'B_STPHY_CNS', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (x_backup_without_spp[i] %like% '[ck]oagulas[ea] positie?[vf]'
@@ -574,24 +647,38 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
| x_backup_without_spp[i] %like% '[ck]o?ps[^a-z]?$') {
# coerce S. coagulase positive
x[i] <- microorganismsDT[mo == 'B_STPHY_CPS', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (x_backup_without_spp[i] %like% 'gram[ -]?neg.*'
+ | x_backup_without_spp[i] %like% 'negatie?[vf]'
| x_trimmed[i] %like% 'gram[ -]?neg.*') {
# coerce Gram negatives
x[i] <- microorganismsDT[mo == 'B_GRAMN', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (x_backup_without_spp[i] %like% 'gram[ -]?pos.*'
+ | x_backup_without_spp[i] %like% 'positie?[vf]'
| x_trimmed[i] %like% 'gram[ -]?pos.*') {
# coerce Gram positives
x[i] <- microorganismsDT[mo == 'B_GRAMP', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (grepl("[sS]almonella [A-Z][a-z]+ ?.*", x_backup_without_spp[i], ignore.case = FALSE)) {
if (x_backup_without_spp[i] %like% "Salmonella group") {
# Salmonella Group A to Z, just return S. species for now
x[i] <- microorganismsDT[mo == 'B_SLMNL', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
options(mo_renamed = c(getOption("mo_renamed"),
magenta(paste0("Note: ",
italic("Salmonella"), " ", trimws(gsub("Salmonella", "", x_backup_without_spp[i])),
@@ -601,6 +688,9 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
} else {
# Salmonella with capital letter species like "Salmonella Goettingen" - they're all S. enterica
x[i] <- microorganismsDT[mo == 'B_SLMNL_ENT', ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
options(mo_renamed = c(getOption("mo_renamed"),
magenta(paste0("Note: ",
italic("Salmonella"), " ", trimws(gsub("Salmonella", "", x_backup_without_spp[i])),
@@ -618,12 +708,18 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
found <- microorganismsDT[fullname_lower %in% tolower(c(x_species[i], x_trimmed_species[i])), ..property][[1]]
if (length(found) > 0) {
x[i] <- found[1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
if (nchar(x_backup_without_spp[i]) >= 6) {
- found <- microorganismsDT[fullname_lower %like% paste0("^", x_backup_without_spp[i], "[a-z]+"), ..property][[1]]
+ found <- microorganismsDT[fullname_lower %like% paste0("^", unregex(x_backup_without_spp[i]), "[a-z]+"), ..property][[1]]
if (length(found) > 0) {
x[i] <- found[1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
}
@@ -636,6 +732,9 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
mo_found <- AMR::microorganisms.codes[toupper(x_backup[i]) == AMR::microorganisms.codes[, 1], "mo"][1L]
if (length(mo_found) > 0) {
x[i] <- microorganismsDT[mo == mo_found, ..property][[1]][1L]
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
}
@@ -737,6 +836,9 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
f.x_withspaces_end_only = x_withspaces_end_only[i],
g.x_backup_without_spp = x_backup_without_spp[i])
if (!empty_result(x[i])) {
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
# THEN TRY PREVALENT IN HUMAN INFECTIONS ----
@@ -749,6 +851,9 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
f.x_withspaces_end_only = x_withspaces_end_only[i],
g.x_backup_without_spp = x_backup_without_spp[i])
if (!empty_result(x[i])) {
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
# THEN UNPREVALENT IN HUMAN INFECTIONS ----
@@ -761,6 +866,9 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
f.x_withspaces_end_only = x_withspaces_end_only[i],
g.x_backup_without_spp = x_backup_without_spp[i])
if (!empty_result(x[i])) {
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
@@ -784,16 +892,19 @@ exec_as.mo <- function(x, Becker = FALSE, Lancefield = FALSE,
ref_old = found[1, ref],
ref_new = microorganismsDT[col_id == found[1, col_id_new], ref],
mo = microorganismsDT[col_id == found[1, col_id_new], mo])
+ if (property == "mo") {
+ set_mo_history(x_backup[i], x[i], force = force_mo_history)
+ }
next
}
# check for uncertain results ----
uncertain_fn <- function(a.x_backup,
-b.x_trimmed,
- c.x_withspaces_start_end,
-d.x_withspaces_start_only,
- f.x_withspaces_end_only,
-g.x_backup_without_spp) {
+ b.x_trimmed,
+ c.x_withspaces_start_end,
+ d.x_withspaces_start_only,
+ f.x_withspaces_end_only,
+ g.x_backup_without_spp) {
if (allow_uncertain == 0) {
# do not allow uncertainties
@@ -936,15 +1047,15 @@ g.x_backup_without_spp) {
}
x[i] <- uncertain_fn(x_backup[i],
x_trimmed[i],
- x_withspaces_start_end[i],
+ x_withspaces_start_end[i],
x_withspaces_start_only[i],
x_withspaces_end_only[i],
x_backup_without_spp[i])
if (!empty_result(x[i])) {
+ # no set_mo_history here; these are uncertain
next
}
-
# not found ----
x[i] <- microorganismsDT[mo == "UNKNOWN", ..property][[1]]
failures <- c(failures, x_backup[i])
@@ -1232,3 +1343,7 @@ nr2char <- function(x) {
x
}
}
+
+unregex <- function(x) {
+ gsub("[^a-zA-Z0-9 -]", "", x)
+}
diff --git a/R/mo_history.R b/R/mo_history.R
new file mode 100644
index 00000000..aac423dd
--- /dev/null
+++ b/R/mo_history.R
@@ -0,0 +1,74 @@
+# ==================================================================== #
+# TITLE #
+# Antimicrobial Resistance (AMR) Analysis #
+# #
+# SOURCE #
+# https://gitlab.com/msberends/AMR #
+# #
+# LICENCE #
+# (c) 2019 Berends MS (m.s.berends@umcg.nl), Luz CF (c.f.luz@umcg.nl) #
+# #
+# 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. #
+# #
+# This R package was created for academic research and was publicly #
+# released in the hope that it will be useful, but it comes WITHOUT #
+# ANY WARRANTY OR LIABILITY. #
+# Visit our website for more info: https://msberends.gitab.io/AMR. #
+# ==================================================================== #
+
+# print successful as.mo coercions to file, not uncertain ones
+#' @importFrom dplyr %>% filter
+set_mo_history <- function(x, mo, force = FALSE) {
+ file_location <- base::path.expand('~/.Rhistory_mo')
+ if ((base::interactive() & mo != "UNKNOWN") | force == TRUE) {
+ mo_hist <- read_mo_history(force = force)
+ if (NROW(mo_hist[base::which(mo_hist$x == x & mo_hist$package_version == utils::packageVersion("AMR")),]) == 0) {
+ base::write(x = c(x, mo, base::as.character(utils::packageVersion("AMR"))),
+ file = file_location,
+ ncolumns = 3,
+ append = TRUE,
+ sep = "\t")
+ }
+ }
+ return(base::invisible())
+}
+
+get_mo_history <- function(x, force = FALSE) {
+ file_read <- read_mo_history(force = force)
+ if (base::is.null(file_read)) {
+ NA
+ } else {
+ data.frame(x, stringsAsFactors = FALSE) %>%
+ left_join(file_read, by = "x") %>%
+ pull(mo)
+ }
+}
+
+read_mo_history <- function(force = FALSE) {
+ file_location <- base::path.expand('~/.Rhistory_mo')
+ if (!base::file.exists(file_location) | (!base::interactive() & force == FALSE)) {
+ return(NULL)
+ }
+ file_read <- utils::read.table(file = file_location,
+ header = FALSE,
+ sep = "\t",
+ col.names = c("x", "mo", "package_version"),
+ stringsAsFactors = FALSE)
+ # Below: filter on current package version.
+ # Future fullnames may even be replaced by new taxonomic names, so new versions of
+ # the Catalogue of Life must not lead to data corruption.
+ file_read[base::which(file_read$package_version == utils::packageVersion("AMR")), c("x", "mo")]
+}
+
+#' @rdname as.mo
+#' @export
+clean_mo_history <- function() {
+ file_location <- base::path.expand('~/.Rhistory_mo')
+ if (base::file.exists(file_location)) {
+ base::unlink(file_location)
+ }
+}
+
diff --git a/R/mo_source.R b/R/mo_source.R
index 34f5f940..cd1f2365 100644
--- a/R/mo_source.R
+++ b/R/mo_source.R
@@ -99,6 +99,8 @@
#' @inheritSection AMR Read more on our website!
set_mo_source <- function(path) {
+ file_location <- path.expand('~/mo_source.rds')
+
if (!is.character(path) | length(path) > 1) {
stop("`path` must be a character of length 1.")
}
@@ -106,9 +108,9 @@ set_mo_source <- function(path) {
if (path %in% c(NULL, "")) {
options(mo_source = NULL)
options(mo_source_timestamp = NULL)
- if (file.exists("~/.mo_source.rds")) {
- unlink("~/.mo_source.rds")
- message("Removed mo_source file '~/.mo_source.rds'.")
+ if (file.exists(file_location)) {
+ unlink(file_location)
+ message("Removed mo_source file '", file_location, "'.")
}
return(invisible())
}
@@ -165,23 +167,22 @@ set_mo_source <- function(path) {
df <- as.data.frame(df, stringAsFactors = FALSE)
# success
- if (file.exists("~/.mo_source.rds")) {
+ if (file.exists(file_location)) {
action <- "Updated"
} else {
action <- "Created"
}
- saveRDS(df, "~/.mo_source.rds")
+ saveRDS(df, file_location)
options(mo_source = path)
options(mo_source_timestamp = as.character(file.info(path)$mtime))
- message(action, " mo_source file '~/.mo_source.rds' from '", path, "'.")
+ message(action, " mo_source file '", file_location, "' from '", path, "'.")
}
#' @rdname mo_source
#' @export
get_mo_source <- function() {
-
if (is.null(getOption("mo_source", NULL))) {
- return(NULL)
+ NULL
} else {
old_time <- as.POSIXct(getOption("mo_source_timestamp"))
new_time <- as.POSIXct(as.character(file.info(getOption("mo_source", ""))$mtime))
@@ -195,9 +196,9 @@ get_mo_source <- function() {
# set updated source
set_mo_source(getOption("mo_source"))
}
+ file_location <- path.expand('~/mo_source.rds')
+ readRDS(file_location)
}
-
- readRDS("~/.mo_source.rds")
}
mo_source_isvalid <- function(x) {
diff --git a/README.md b/README.md
index 38be8ff9..adb301e1 100755
--- a/README.md
+++ b/README.md
@@ -25,11 +25,11 @@ Bhanu N.M. Sinha
-
-
-
-
+
+
+
+
+
## How to get this package
All stable versions of this package [are published on CRAN](https://CRAN.R-project.org/package=AMR), the official R network with a peer-reviewed submission process.
diff --git a/_pkgdown.yml b/_pkgdown.yml
index c6e66e05..5052090d 100644
--- a/_pkgdown.yml
+++ b/_pkgdown.yml
@@ -147,7 +147,7 @@ reference:
- '`WHONET`'
- '`microorganisms.codes`'
- '`microorganisms.old`'
- - title: Other
+ - title: Other functions
desc: >
These functions are mostly for internal use, but some of
them may also be suitable for your analysis. Especially the
@@ -155,7 +155,13 @@ reference:
contents:
- '`get_locale`'
- '`like`'
- - '`ab_property`'
+ - title: Deprecated functions
+ desc: >
+ These functions are deprecated, meaning that they still
+ work but show a warning with every use and will be removed
+ in a future version.
+ contents:
+ - '`AMR-deprecated`'
authors:
Matthijs S. Berends:
diff --git a/appveyor.yml b/appveyor.yml
index 6d0eeea6..a241a40d 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -55,9 +55,6 @@ on_failure:
- 7z a failure.zip *.Rcheck\*
- appveyor PushArtifact failure.zip
-#on_success:
-# - Rscript -e "library(covr); cc <- package_coverage(); codecov(coverage = cc, token = '50ffa0aa-fee0-4f8b-a11d-8c7edc6d32ca'); cat('Code coverage:', percent_coverage(cc))"
-
artifacts:
- path: '*.Rcheck\**\*.log'
name: Logs
diff --git a/docs/LICENSE-text.html b/docs/LICENSE-text.html
index 5e593eff..fc84075e 100644
--- a/docs/LICENSE-text.html
+++ b/docs/LICENSE-text.html
@@ -78,7 +78,7 @@
AMR (for R)
- 0.5.0.9022
+ 0.5.0.9023
diff --git a/docs/articles/AMR.html b/docs/articles/AMR.html
index e0076c6e..f06c27bd 100644
--- a/docs/articles/AMR.html
+++ b/docs/articles/AMR.html
@@ -40,7 +40,7 @@
AMR (for R)
- 0.5.0.9021
+ 0.5.0.9023
@@ -192,7 +192,7 @@
How to conduct AMR analysis
Matthijs S. Berends
- 05 March 2019
+ 15 March 2019
AMR.Rmd
@@ -201,7 +201,7 @@
-Note: values on this page will change with every website update since they are based on randomly created values and the page was written in RMarkdown. However, the methodology remains unchanged. This page was generated on 05 March 2019.
+Note: values on this page will change with every website update since they are based on randomly created values and the page was written in RMarkdown. However, the methodology remains unchanged. This page was generated on 15 March 2019.
Introduction
@@ -217,21 +217,21 @@
-2019-03-05 |
+2019-03-15 |
abcd |
Escherichia coli |
S |
S |
-2019-03-05 |
+2019-03-15 |
abcd |
Escherichia coli |
S |
R |
-2019-03-05 |
+2019-03-15 |
efgh |
Escherichia coli |
R |
@@ -327,21 +327,21 @@
-2010-01-23 |
-E2 |
+2011-03-23 |
+H4 |
Hospital B |
-Staphylococcus aureus |
-I |
+Escherichia coli |
+S |
S |
S |
S |
M |
-2017-12-07 |
-L8 |
+2016-02-07 |
+A10 |
Hospital B |
-Staphylococcus aureus |
+Escherichia coli |
S |
S |
S |
@@ -349,49 +349,49 @@
M |
-2012-07-19 |
-W5 |
-Hospital A |
-Staphylococcus aureus |
+2017-05-30 |
+Q9 |
+Hospital D |
+Escherichia coli |
+S |
S |
-R |
S |
S |
F |
-2013-11-26 |
-L7 |
-Hospital A |
-Escherichia coli |
-S |
-S |
-R |
-S |
-M |
-
-
-2016-01-24 |
-M7 |
+2016-09-19 |
+U5 |
Hospital B |
Escherichia coli |
S |
S |
S |
S |
-M |
+F |
-
-2016-11-13 |
-V10 |
-Hospital A |
-Escherichia coli |
+
+2016-03-20 |
+X10 |
+Hospital D |
+Streptococcus pneumoniae |
S |
S |
S |
S |
F |
+
+2012-07-29 |
+D10 |
+Hospital D |
+Escherichia coli |
+S |
+S |
+S |
+S |
+M |
+
Now, let’s start the cleaning and the analysis!
@@ -411,15 +411,15 @@
#>
#> Item Count Percent Cum. Count Cum. Percent
#> --- ----- ------- -------- ----------- -------------
-#> 1 M 10,562 52.8% 10,562 52.8%
-#> 2 F 9,438 47.2% 20,000 100.0%
+#> 1 M 10,422 52.1% 10,422 52.1%
+#> 2 F 9,578 47.9% 20,000 100.0%
So, we can draw at least two conclusions immediately. From a data scientist perspective, the data looks clean: only values M
and F
. From a researcher perspective: there are slightly more men. Nothing we didn’t already know.
The data is already quite clean, but we still need to transform some variables. The bacteria
column now consists of text, and we want to add more variables based on microbial IDs later on. So, we will transform this column to valid IDs. The mutate()
function of the dplyr
package makes this really easy:
-
We also want to transform the antibiotics, because in real life data we don’t know if they are really clean. The as.rsi()
function ensures reliability and reproducibility in these kind of variables. The mutate_at()
will run the as.rsi()
function on defined variables:
+
We also want to transform the antibiotics, because in real life data we don’t know if they are really clean. The as.rsi()
function ensures reliability and reproducibility in these kind of variables. The mutate_at()
will run the as.rsi()
function on defined variables:
+
mutate_at(vars(amox:gent), as.rsi)
Finally, we will apply EUCAST rules on our antimicrobial results. In Europe, most medical microbiological laboratories already apply these rules. Our package features their latest insights on intrinsic resistance and exceptional phenotypes. Moreover, the eucast_rules()
function can also apply additional rules, like forcing ampicillin = R when amoxicillin/clavulanic acid = R.
Because the amoxicillin (column amox
) and amoxicillin/clavulanic acid (column amcl
) in our data were generated randomly, some rows will undoubtedly contain amox = S and amcl = R, which is technically impossible. The eucast_rules()
fixes this:
data <- eucast_rules(data, col_mo = "bacteria")
@@ -443,10 +443,10 @@
#> Kingella kingae (no changes)
#>
#> EUCAST Expert Rules, Intrinsic Resistance and Exceptional Phenotypes (v3.1, 2016)
-#> Table 1: Intrinsic resistance in Enterobacteriaceae (1344 changes)
+#> Table 1: Intrinsic resistance in Enterobacteriaceae (1315 changes)
#> Table 2: Intrinsic resistance in non-fermentative Gram-negative bacteria (no changes)
#> Table 3: Intrinsic resistance in other Gram-negative bacteria (no changes)
-#> Table 4: Intrinsic resistance in Gram-positive bacteria (2767 changes)
+#> Table 4: Intrinsic resistance in Gram-positive bacteria (2799 changes)
#> Table 8: Interpretive rules for B-lactam agents and Gram-positive cocci (no changes)
#> Table 9: Interpretive rules for B-lactam agents and Gram-negative rods (no changes)
#> Table 10: Interpretive rules for B-lactam agents and other Gram-negative bacteria (no changes)
@@ -462,9 +462,9 @@
#> Non-EUCAST: piperacillin/tazobactam = S where piperacillin = S (no changes)
#> Non-EUCAST: trimethoprim/sulfa = S where trimethoprim = S (no changes)
#>
-#> => EUCAST rules affected 7,383 out of 20,000 rows
+#> => EUCAST rules affected 7,488 out of 20,000 rows
#> -> added 0 test results
-#> -> changed 4,111 test results (0 to S; 0 to I; 4,111 to R)
+#> -> changed 4,114 test results (0 to S; 0 to I; 4,114 to R)
+#> => Found 5,688 first isolates (28.4% of total)
So only 28.4% is suitable for resistance analysis! We can now filter on it with the filter()
function, also from the dplyr
package:
@@ -516,19 +516,19 @@
1 |
-2010-01-20 |
-L10 |
+2010-04-01 |
+K1 |
B_ESCHR_COL |
-I |
R |
S |
S |
+S |
TRUE |
2 |
-2010-03-26 |
-L10 |
+2010-04-30 |
+K1 |
B_ESCHR_COL |
R |
S |
@@ -538,10 +538,10 @@
3 |
-2010-05-05 |
-L10 |
+2010-10-12 |
+K1 |
B_ESCHR_COL |
-S |
+R |
S |
S |
S |
@@ -549,19 +549,19 @@
4 |
-2010-06-20 |
-L10 |
+2010-12-05 |
+K1 |
B_ESCHR_COL |
S |
S |
S |
-S |
+R |
FALSE |
5 |
-2010-07-10 |
-L10 |
+2011-01-19 |
+K1 |
B_ESCHR_COL |
S |
S |
@@ -571,21 +571,21 @@
6 |
-2010-08-01 |
-L10 |
+2011-04-07 |
+K1 |
B_ESCHR_COL |
S |
S |
S |
S |
-FALSE |
+TRUE |
7 |
-2010-08-27 |
-L10 |
+2011-06-16 |
+K1 |
B_ESCHR_COL |
-R |
+S |
S |
S |
S |
@@ -593,19 +593,19 @@
8 |
-2010-09-09 |
-L10 |
+2011-07-16 |
+K1 |
B_ESCHR_COL |
-R |
S |
+R |
S |
S |
FALSE |
9 |
-2010-09-26 |
-L10 |
+2011-08-25 |
+K1 |
B_ESCHR_COL |
R |
S |
@@ -615,18 +615,18 @@
10 |
-2010-10-11 |
-L10 |
+2011-09-11 |
+K1 |
B_ESCHR_COL |
R |
S |
-S |
-S |
+R |
+R |
FALSE |
-Only 1 isolates are marked as ‘first’ according to CLSI guideline. But when reviewing the antibiogram, it is obvious that some isolates are absolutely different strains and should be included too. This is why we weigh isolates, based on their antibiogram. The key_antibiotics()
function adds a vector with 18 key antibiotics: 6 broad spectrum ones, 6 small spectrum for Gram negatives and 6 small spectrum for Gram positives. These can be defined by the user.
+Only 2 isolates are marked as ‘first’ according to CLSI guideline. But when reviewing the antibiogram, it is obvious that some isolates are absolutely different strains and should be included too. This is why we weigh isolates, based on their antibiogram. The key_antibiotics()
function adds a vector with 18 key antibiotics: 6 broad spectrum ones, 6 small spectrum for Gram negatives and 6 small spectrum for Gram positives. These can be defined by the user.
If a column exists with a name like ‘key(…)ab’ the first_isolate()
function will automatically use it and determine the first weighted isolates. Mind the NOTEs in below output:
+#> => Found 15,948 first weighted isolates (79.7% of total)
1 |
-2010-01-20 |
-L10 |
+2010-04-01 |
+K1 |
B_ESCHR_COL |
-I |
R |
S |
S |
+S |
TRUE |
TRUE |
2 |
-2010-03-26 |
-L10 |
+2010-04-30 |
+K1 |
B_ESCHR_COL |
R |
S |
S |
S |
FALSE |
-TRUE |
+FALSE |
3 |
-2010-05-05 |
-L10 |
+2010-10-12 |
+K1 |
B_ESCHR_COL |
-S |
+R |
S |
S |
S |
FALSE |
-TRUE |
+FALSE |
4 |
-2010-06-20 |
-L10 |
+2010-12-05 |
+K1 |
+B_ESCHR_COL |
+S |
+S |
+S |
+R |
+FALSE |
+TRUE |
+
+
+5 |
+2011-01-19 |
+K1 |
B_ESCHR_COL |
S |
S |
S |
S |
FALSE |
-FALSE |
+TRUE |
+
+
+6 |
+2011-04-07 |
+K1 |
+B_ESCHR_COL |
+S |
+S |
+S |
+S |
+TRUE |
+TRUE |
-5 |
-2010-07-10 |
-L10 |
+7 |
+2011-06-16 |
+K1 |
B_ESCHR_COL |
S |
S |
@@ -713,21 +737,21 @@
FALSE |
-6 |
-2010-08-01 |
-L10 |
+8 |
+2011-07-16 |
+K1 |
B_ESCHR_COL |
S |
-S |
+R |
S |
S |
FALSE |
-FALSE |
+TRUE |
-7 |
-2010-08-27 |
-L10 |
+9 |
+2011-08-25 |
+K1 |
B_ESCHR_COL |
R |
S |
@@ -737,48 +761,24 @@
TRUE |
-8 |
-2010-09-09 |
-L10 |
-B_ESCHR_COL |
-R |
-S |
-S |
-S |
-FALSE |
-FALSE |
-
-
-9 |
-2010-09-26 |
-L10 |
-B_ESCHR_COL |
-R |
-S |
-S |
-S |
-FALSE |
-FALSE |
-
-
10 |
-2010-10-11 |
-L10 |
+2011-09-11 |
+K1 |
B_ESCHR_COL |
R |
S |
-S |
-S |
-FALSE |
+R |
+R |
FALSE |
+TRUE |
-Instead of 1, now 4 isolates are flagged. In total, 78.8% of all isolates are marked ‘first weighted’ - 50.5% more than when using the CLSI guideline. In real life, this novel algorithm will yield 5-10% more isolates than the classic CLSI guideline.
+Instead of 2, now 7 isolates are flagged. In total, 79.7% of all isolates are marked ‘first weighted’ - 51.3% more than when using the CLSI guideline. In real life, this novel algorithm will yield 5-10% more isolates than the classic CLSI guideline.
As with filter_first_isolate()
, there’s a shortcut for this new algorithm too:
-So we end up with 15,767 isolates for analysis.
+So we end up with 15,948 isolates for analysis.
We can remove unneeded columns:
@@ -786,6 +786,7 @@
-2010-01-23 |
-E2 |
+1 |
+2011-03-23 |
+H4 |
Hospital B |
-B_STPHY_AUR |
+B_ESCHR_COL |
+S |
+S |
+S |
+S |
+M |
+Gram negative |
+Escherichia |
+coli |
+TRUE |
+
+
+2 |
+2016-02-07 |
+A10 |
+Hospital B |
+B_ESCHR_COL |
+S |
+S |
+S |
+S |
+M |
+Gram negative |
+Escherichia |
+coli |
+TRUE |
+
+
+5 |
+2016-03-20 |
+X10 |
+Hospital D |
+B_STRPT_PNE |
+S |
+S |
+S |
+R |
+F |
+Gram positive |
+Streptococcus |
+pneumoniae |
+TRUE |
+
+
+7 |
+2015-08-01 |
+Q4 |
+Hospital A |
+B_ESCHR_COL |
+S |
I |
S |
-S |
-S |
-M |
-Gram positive |
-Staphylococcus |
-aureus |
-TRUE |
-
-
-2017-12-07 |
-L8 |
-Hospital B |
-B_STPHY_AUR |
-S |
-S |
-S |
-S |
-M |
-Gram positive |
-Staphylococcus |
-aureus |
-TRUE |
-
-
-2012-07-19 |
-W5 |
-Hospital A |
-B_STPHY_AUR |
-S |
R |
-S |
-S |
F |
-Gram positive |
-Staphylococcus |
-aureus |
-TRUE |
-
-
-2013-11-26 |
-L7 |
-Hospital A |
-B_ESCHR_COL |
-S |
-S |
-R |
-S |
-M |
Gram negative |
Escherichia |
coli |
TRUE |
-2016-01-24 |
-M7 |
-Hospital B |
+8 |
+2012-03-10 |
+Z10 |
+Hospital C |
B_ESCHR_COL |
+R |
S |
S |
S |
-S |
-M |
+F |
Gram negative |
Escherichia |
coli |
TRUE |
-2016-11-13 |
-V10 |
-Hospital A |
+11 |
+2014-10-21 |
+G8 |
+Hospital C |
B_ESCHR_COL |
S |
S |
S |
S |
-F |
+M |
Gram negative |
Escherichia |
coli |
@@ -908,9 +915,9 @@
Or can be used like the dplyr
way, which is easier readable:
-Frequency table of genus
and species
from a data.frame
(15,767 x 13)
+Frequency table of genus
and species
from a data.frame
(15,948 x 13)
Columns: 2
-Length: 15,767 (of which NA: 0 = 0.00%)
+Length: 15,948 (of which NA: 0 = 0.00%)
Unique: 4
Shortest: 16
Longest: 24
@@ -927,33 +934,33 @@ Longest: 24
1 |
Escherichia coli |
-7,762 |
-49.2% |
-7,762 |
-49.2% |
+7,952 |
+49.9% |
+7,952 |
+49.9% |
2 |
Staphylococcus aureus |
-4,014 |
-25.5% |
-11,776 |
-74.7% |
+3,886 |
+24.4% |
+11,838 |
+74.2% |
3 |
Streptococcus pneumoniae |
-2,450 |
-15.5% |
-14,226 |
-90.2% |
+2,509 |
+15.7% |
+14,347 |
+90.0% |
4 |
Klebsiella pneumoniae |
-1,541 |
-9.8% |
-15,767 |
+1,601 |
+10.0% |
+15,948 |
100.0% |
@@ -964,7 +971,7 @@ Longest: 24
Resistance percentages
The functions portion_R()
, portion_RI()
, portion_I()
, portion_IS()
and portion_S()
can be used to determine the portion of a specific antimicrobial outcome. They can be used on their own:
+#> [1] 0.4812516
Or can be used in conjuction with group_by()
and summarise()
, both from the dplyr
package:
@@ -1007,23 +1014,23 @@ Longest: 24
Hospital A |
-0.4717496 |
-4761 |
+0.4801481 |
+4861 |
Hospital B |
-0.4754662 |
-5523 |
+0.4811895 |
+5582 |
Hospital C |
-0.4748170 |
-2323 |
+0.4707087 |
+2441 |
Hospital D |
-0.4854430 |
-3160 |
+0.4915144 |
+3064 |
@@ -1043,27 +1050,27 @@ Longest: 24
Escherichia |
-0.7333162 |
-0.9035043 |
-0.9748776 |
+0.7282445 |
+0.9031690 |
+0.9756036 |
Klebsiella |
-0.7352369 |
-0.9104478 |
-0.9733939 |
+0.7270456 |
+0.9000625 |
+0.9787633 |
Staphylococcus |
-0.7416542 |
-0.9160438 |
-0.9763328 |
+0.7220793 |
+0.9184251 |
+0.9796706 |
Streptococcus |
-0.7473469 |
+0.7182144 |
0.0000000 |
-0.7473469 |
+0.7182144 |
diff --git a/docs/articles/AMR_files/figure-html/plot 1-1.png b/docs/articles/AMR_files/figure-html/plot 1-1.png
index 49a734cc42d6830128d117b8274df142774659c6..c93a5298c3077aae5c95081e833189561d500a34 100644
GIT binary patch
literal 35429
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
ZAuUQzW5c%xhsYPw4yhk}s&x9=e*q9KuJ8Z=
literal 35640
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