(v1.5.0.9039) handle first isolates for missing antibiograms

This commit is contained in:
dr. M.S. (Matthijs) Berends 2021-03-08 02:38:32 +01:00
parent 461793dc34
commit a7c9b4c295
21 changed files with 79 additions and 62 deletions

View File

@ -1,6 +1,6 @@
Package: AMR
Version: 1.5.0.9038
Date: 2021-03-07
Version: 1.5.0.9039
Date: 2021-03-08
Title: Antimicrobial Resistance Data Analysis
Authors@R: c(
person(role = c("aut", "cre"),

View File

@ -1,5 +1,5 @@
# AMR 1.5.0.9034
## <small>Last updated: 7 March 2021</small>
# AMR 1.5.0.9039
## <small>Last updated: 8 March 2021</small>
### New
* Support for EUCAST Clinical Breakpoints v11.0 (2021), effective in the `eucast_rules()` function and in `as.rsi()` to interpret MIC and disk diffusion values. This is now the default guideline in this package.
@ -73,6 +73,7 @@
* Support for GISA (glycopeptide-intermediate *S. aureus*), so e.g. `mo_genus("GISA")` will return `"Staphylococcus"`
* Added translations of German and Spanish for more than 200 antimicrobial drugs
* Speed improvement for `as.ab()` when the input is an official name or ATC code
* Added argument `include_untested_rsi` to the `first_isolate()` functions (defaults to `TRUE` to keep existing behaviour), to be able to exclude rows where all R/SI values (class `<rsi>`, see `as.rsi()`) are empty
### Other
* Big documentation updates

34
R/ab.R
View File

@ -109,23 +109,23 @@ as.ab <- function(x, flag_multiple_results = TRUE, info = TRUE, ...) {
x <- toupper(x)
x_nonNA <- x[!is.na(x)]
# if (all(x_nonNA %in% antibiotics$ab, na.rm = TRUE)) {
# # all valid AB codes, but not yet right class
# return(set_clean_class(x,
# new_class = c("ab", "character")))
# }
# if (all(x_nonNA %in% toupper(antibiotics$name), na.rm = TRUE)) {
# # all valid AB names
# out <- antibiotics$ab[match(x, toupper(antibiotics$name))]
# out[is.na(x)] <- NA_character_
# return(out)
# }
# if (all(x_nonNA %in% antibiotics$atc, na.rm = TRUE)) {
# # all valid ATC codes
# out <- antibiotics$ab[match(x, antibiotics$atc)]
# out[is.na(x)] <- NA_character_
# return(out)
# }
if (all(x_nonNA %in% antibiotics$ab, na.rm = TRUE)) {
# all valid AB codes, but not yet right class
return(set_clean_class(x,
new_class = c("ab", "character")))
}
if (all(x_nonNA %in% toupper(antibiotics$name), na.rm = TRUE)) {
# all valid AB names
out <- antibiotics$ab[match(x, toupper(antibiotics$name))]
out[is.na(x)] <- NA_character_
return(out)
}
if (all(x_nonNA %in% antibiotics$atc, na.rm = TRUE)) {
# all valid ATC codes
out <- antibiotics$ab[match(x, antibiotics$atc)]
out[is.na(x)] <- NA_character_
return(out)
}
# remove diacritics
x <- iconv(x, from = "UTF-8", to = "ASCII//TRANSLIT")

View File

@ -37,13 +37,14 @@
#' @param col_keyantibiotics column name of the key antibiotics to determine first (weighted) isolates, see [key_antibiotics()]. Defaults to the first column that starts with 'key' followed by 'ab' or 'antibiotics' (case insensitive). Use `col_keyantibiotics = FALSE` to prevent this.
#' @param episode_days episode in days after which a genus/species combination will be determined as 'first isolate' again. The default of 365 days is based on the guideline by CLSI, see *Source*.
#' @param testcodes_exclude character vector with test codes that should be excluded (case-insensitive)
#' @param icu_exclude logical whether ICU isolates should be excluded (rows with value `TRUE` in the column set with `col_icu`)
#' @param icu_exclude logical to indicate whether ICU isolates should be excluded (rows with value `TRUE` in the column set with `col_icu`)
#' @param specimen_group value in the column set with `col_specimen` to filter on
#' @param type type to determine weighed isolates; can be `"keyantibiotics"` or `"points"`, see *Details*
#' @param ignore_I logical to determine whether antibiotic interpretations with `"I"` will be ignored when `type = "keyantibiotics"`, see *Details*
#' @param ignore_I logical to indicate whether antibiotic interpretations with `"I"` will be ignored when `type = "keyantibiotics"`, see *Details*
#' @param points_threshold points until the comparison of key antibiotics will lead to inclusion of an isolate when `type = "points"`, see *Details*
#' @param info print progress
#' @param include_unknown logical to determine whether 'unknown' microorganisms should be included too, i.e. microbial code `"UNKNOWN"`, which defaults to `FALSE`. For WHONET users, this means that all records with organism code `"con"` (*contamination*) will be excluded at default. Isolates with a microbial ID of `NA` will always be excluded as first isolate.
#' @param include_unknown logical to indicate whether 'unknown' microorganisms should be included too, i.e. microbial code `"UNKNOWN"`, which defaults to `FALSE`. For WHONET users, this means that all records with organism code `"con"` (*contamination*) will be excluded at default. Isolates with a microbial ID of `NA` will always be excluded as first isolate.
#' @param include_untested_rsi logical to indicate whether also rows without antibiotic results are still eligible for becoming a first isolate. Use `include_untested_rsi = FALSE` to always return `FALSE` for such rows. This checks the data set for columns of class `<rsi>` and consequently requires transforming columns with antibiotic results using [as.rsi()] first.
#' @param ... arguments passed on to [first_isolate()] when using [filter_first_isolate()], or arguments passed on to [key_antibiotics()] when using [filter_first_weighted_isolate()]
#' @details
#' These functions are context-aware. This means that then the `x` argument can be left blank, see *Examples*.
@ -159,6 +160,7 @@ first_isolate <- function(x = NULL,
points_threshold = 2,
info = interactive(),
include_unknown = FALSE,
include_untested_rsi = TRUE,
...) {
if (is_null_or_grouped_tbl(x)) {
# when `x` is left blank, auto determine it (get_current_data() also contains dplyr::cur_data_all())
@ -188,6 +190,7 @@ first_isolate <- function(x = NULL,
meet_criteria(points_threshold, allow_class = c("numeric", "integer"), has_length = 1, is_positive = TRUE, is_finite = TRUE)
meet_criteria(info, allow_class = "logical", has_length = 1)
meet_criteria(include_unknown, allow_class = "logical", has_length = 1)
meet_criteria(include_untested_rsi, allow_class = "logical", has_length = 1)
# remove data.table, grouping from tibbles, etc.
x <- as.data.frame(x, stringsAsFactors = FALSE)
@ -472,6 +475,14 @@ first_isolate <- function(x = NULL,
}
x[which(is.na(x$newvar_mo)), "newvar_first_isolate"] <- FALSE
# handle isolates without antibiogram
if (include_untested_rsi == FALSE && any(is.rsi(x))) {
rsi_all_NA <- which(unname(vapply(FUN.VALUE = logical(1),
as.data.frame(t(x[, is.rsi(x), drop = FALSE])),
function(rsi_values) all(is.na(rsi_values)))))
x[rsi_all_NA, "newvar_first_isolate"] <- FALSE
}
# arrange back according to original sorting again
x <- x[order(x$newvar_row_index), ]
rownames(x) <- NULL

12
R/rsi.R
View File

@ -337,18 +337,14 @@ as.rsi.mic <- function(x,
meet_criteria(reference_data, allow_class = "data.frame")
check_reference_data(reference_data)
pkg_env$strange <- list(before = ab)
# for dplyr's across()
cur_column_dplyr <- import_fn("cur_column", "dplyr", error_on_fail = FALSE)
if (!is.null(cur_column_dplyr)) {
if (!is.null(cur_column_dplyr) && tryCatch(is.data.frame(get_current_data("ab", 0)), error = function(e) FALSE)) {
# try to get current column, which will only be available when in across()
ab <- tryCatch(cur_column_dplyr(),
error = function(e) ab)
}
pkg_env$strange$afteracross <- ab
# for auto-determining mo
mo_var_found <- ""
if (is.null(mo)) {
@ -373,7 +369,6 @@ as.rsi.mic <- function(x,
}
ab_coerced <- suppressWarnings(as.ab(ab))
pkg_env$strange$coerced <- ab_coerced
mo_coerced <- suppressWarnings(as.mo(mo))
guideline_coerced <- get_guideline(guideline, reference_data)
if (is.na(ab_coerced)) {
@ -433,7 +428,7 @@ as.rsi.disk <- function(x,
# for dplyr's across()
cur_column_dplyr <- import_fn("cur_column", "dplyr", error_on_fail = FALSE)
if (!is.null(cur_column_dplyr)) {
if (!is.null(cur_column_dplyr) && tryCatch(is.data.frame(get_current_data("ab", 0)), error = function(e) FALSE)) {
# try to get current column, which will only be available when in across()
ab <- tryCatch(cur_column_dplyr(),
error = function(e) ab)
@ -709,9 +704,6 @@ exec_as.rsi <- function(method,
conserve_capped_values,
add_intrinsic_resistance,
reference_data) {
pkg_env$strange$exec <- ab
pkg_env$strange$names <- names(pkg_env$strange)
metadata_mo <- get_mo_failures_uncertainties_renamed()
x_bak <- data.frame(x_mo = paste0(x, mo), stringsAsFactors = FALSE)

Binary file not shown.

View File

@ -81,7 +81,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="https://msberends.github.io/AMR//index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9034</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>

View File

@ -81,7 +81,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9034</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>

View File

@ -81,7 +81,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="../index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9034</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>

View File

@ -81,7 +81,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9034</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>

View File

@ -43,7 +43,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9034</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>

View File

@ -81,7 +81,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="../index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9034</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>
@ -236,13 +236,13 @@
<small>Source: <a href='https://github.com/msberends/AMR/blob/master/NEWS.md'><code>NEWS.md</code></a></small>
</div>
<div id="amr-1509034" class="section level1">
<h1 class="page-header" data-toc-text="1.5.0.9034">
<a href="#amr-1509034" class="anchor"></a>AMR 1.5.0.9034<small> Unreleased </small>
<div id="amr-1509039" class="section level1">
<h1 class="page-header" data-toc-text="1.5.0.9039">
<a href="#amr-1509039" class="anchor"></a>AMR 1.5.0.9039<small> Unreleased </small>
</h1>
<div id="last-updated-7-march-2021" class="section level2">
<div id="last-updated-8-march-2021" class="section level2">
<h2 class="hasAnchor">
<a href="#last-updated-7-march-2021" class="anchor"></a><small>Last updated: 7 March 2021</small>
<a href="#last-updated-8-march-2021" class="anchor"></a><small>Last updated: 8 March 2021</small>
</h2>
<div id="new" class="section level3">
<h3 class="hasAnchor">
@ -351,6 +351,7 @@
</li>
<li>Added translations of German and Spanish for more than 200 antimicrobial drugs</li>
<li>Speed improvement for <code><a href="../reference/as.ab.html">as.ab()</a></code> when the input is an official name or ATC code</li>
<li>Added argument <code>include_untested_rsi</code> to the <code><a href="../reference/first_isolate.html">first_isolate()</a></code> functions (defaults to <code>TRUE</code> to keep existing behaviour), to be able to exclude rows where all R/SI values (class <code>&lt;rsi&gt;</code>, see <code><a href="../reference/as.rsi.html">as.rsi()</a></code>) are empty</li>
</ul>
</div>
<div id="other" class="section level3">

View File

@ -12,7 +12,7 @@ articles:
datasets: datasets.html
resistance_predict: resistance_predict.html
welcome_to_AMR: welcome_to_AMR.html
last_built: 2021-03-07T19:41Z
last_built: 2021-03-08T01:35Z
urls:
reference: https://msberends.github.io/AMR//reference
article: https://msberends.github.io/AMR//articles

View File

@ -82,7 +82,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="../index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9019</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>
@ -260,6 +260,7 @@
points_threshold <span class='op'>=</span> <span class='fl'>2</span>,
info <span class='op'>=</span> <span class='fu'><a href='https://rdrr.io/r/base/interactive.html'>interactive</a></span><span class='op'>(</span><span class='op'>)</span>,
include_unknown <span class='op'>=</span> <span class='cn'>FALSE</span>,
include_untested_rsi <span class='op'>=</span> <span class='cn'>TRUE</span>,
<span class='va'>...</span>
<span class='op'>)</span>
@ -325,7 +326,7 @@
</tr>
<tr>
<th>icu_exclude</th>
<td><p>logical whether ICU isolates should be excluded (rows with value <code>TRUE</code> in the column set with <code>col_icu</code>)</p></td>
<td><p>logical to indicate whether ICU isolates should be excluded (rows with value <code>TRUE</code> in the column set with <code>col_icu</code>)</p></td>
</tr>
<tr>
<th>specimen_group</th>
@ -337,7 +338,7 @@
</tr>
<tr>
<th>ignore_I</th>
<td><p>logical to determine whether antibiotic interpretations with <code>"I"</code> will be ignored when <code>type = "keyantibiotics"</code>, see <em>Details</em></p></td>
<td><p>logical to indicate whether antibiotic interpretations with <code>"I"</code> will be ignored when <code>type = "keyantibiotics"</code>, see <em>Details</em></p></td>
</tr>
<tr>
<th>points_threshold</th>
@ -349,7 +350,11 @@
</tr>
<tr>
<th>include_unknown</th>
<td><p>logical to determine whether 'unknown' microorganisms should be included too, i.e. microbial code <code>"UNKNOWN"</code>, which defaults to <code>FALSE</code>. For WHONET users, this means that all records with organism code <code>"con"</code> (<em>contamination</em>) will be excluded at default. Isolates with a microbial ID of <code>NA</code> will always be excluded as first isolate.</p></td>
<td><p>logical to indicate whether 'unknown' microorganisms should be included too, i.e. microbial code <code>"UNKNOWN"</code>, which defaults to <code>FALSE</code>. For WHONET users, this means that all records with organism code <code>"con"</code> (<em>contamination</em>) will be excluded at default. Isolates with a microbial ID of <code>NA</code> will always be excluded as first isolate.</p></td>
</tr>
<tr>
<th>include_untested_rsi</th>
<td><p>logical to indicate whether also rows without antibiotic results are still eligible for becoming a first isolate. Use <code>include_untested_rsi = FALSE</code> to always return <code>FALSE</code> for such rows. This checks the data set for columns of class <code>&lt;rsi&gt;</code> and consequently requires transforming columns with antibiotic results using <code><a href='as.rsi.html'>as.rsi()</a></code> first.</p></td>
</tr>
<tr>
<th>...</th>

View File

@ -81,7 +81,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="../index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9034</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>

View File

@ -82,7 +82,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="../index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9019</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>
@ -317,7 +317,7 @@
</tr>
<tr>
<th>ignore_I</th>
<td><p>logical to determine whether antibiotic interpretations with <code>"I"</code> will be ignored when <code>type = "keyantibiotics"</code>, see <em>Details</em></p></td>
<td><p>logical to indicate whether antibiotic interpretations with <code>"I"</code> will be ignored when <code>type = "keyantibiotics"</code>, see <em>Details</em></p></td>
</tr>
<tr>
<th>points_threshold</th>

View File

@ -81,7 +81,7 @@
</button>
<span class="navbar-brand">
<a class="navbar-link" href="index.html">AMR (for R)</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9034</span>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="Latest development version">1.5.0.9039</span>
</span>
</div>

View File

@ -29,6 +29,7 @@ first_isolate(
points_threshold = 2,
info = interactive(),
include_unknown = FALSE,
include_untested_rsi = TRUE,
...
)
@ -70,19 +71,21 @@ filter_first_weighted_isolate(
\item{testcodes_exclude}{character vector with test codes that should be excluded (case-insensitive)}
\item{icu_exclude}{logical whether ICU isolates should be excluded (rows with value \code{TRUE} in the column set with \code{col_icu})}
\item{icu_exclude}{logical to indicate whether ICU isolates should be excluded (rows with value \code{TRUE} in the column set with \code{col_icu})}
\item{specimen_group}{value in the column set with \code{col_specimen} to filter on}
\item{type}{type to determine weighed isolates; can be \code{"keyantibiotics"} or \code{"points"}, see \emph{Details}}
\item{ignore_I}{logical to determine whether antibiotic interpretations with \code{"I"} will be ignored when \code{type = "keyantibiotics"}, see \emph{Details}}
\item{ignore_I}{logical to indicate whether antibiotic interpretations with \code{"I"} will be ignored when \code{type = "keyantibiotics"}, see \emph{Details}}
\item{points_threshold}{points until the comparison of key antibiotics will lead to inclusion of an isolate when \code{type = "points"}, see \emph{Details}}
\item{info}{print progress}
\item{include_unknown}{logical to determine whether 'unknown' microorganisms should be included too, i.e. microbial code \code{"UNKNOWN"}, which defaults to \code{FALSE}. For WHONET users, this means that all records with organism code \code{"con"} (\emph{contamination}) will be excluded at default. Isolates with a microbial ID of \code{NA} will always be excluded as first isolate.}
\item{include_unknown}{logical to indicate whether 'unknown' microorganisms should be included too, i.e. microbial code \code{"UNKNOWN"}, which defaults to \code{FALSE}. For WHONET users, this means that all records with organism code \code{"con"} (\emph{contamination}) will be excluded at default. Isolates with a microbial ID of \code{NA} will always be excluded as first isolate.}
\item{include_untested_rsi}{logical to indicate whether also rows without antibiotic results are still eligible for becoming a first isolate. Use \code{include_untested_rsi = FALSE} to always return \code{FALSE} for such rows. This checks the data set for columns of class \verb{<rsi>} and consequently requires transforming columns with antibiotic results using \code{\link[=as.rsi]{as.rsi()}} first.}
\item{...}{arguments passed on to \code{\link[=first_isolate]{first_isolate()}} when using \code{\link[=filter_first_isolate]{filter_first_isolate()}}, or arguments passed on to \code{\link[=key_antibiotics]{key_antibiotics()}} when using \code{\link[=filter_first_weighted_isolate]{filter_first_weighted_isolate()}}}
}

View File

@ -58,7 +58,7 @@ key_antibiotics_equal(
\item{type}{type to determine weighed isolates; can be \code{"keyantibiotics"} or \code{"points"}, see \emph{Details}}
\item{ignore_I}{logical to determine whether antibiotic interpretations with \code{"I"} will be ignored when \code{type = "keyantibiotics"}, see \emph{Details}}
\item{ignore_I}{logical to indicate whether antibiotic interpretations with \code{"I"} will be ignored when \code{type = "keyantibiotics"}, see \emph{Details}}
\item{points_threshold}{points until the comparison of key antibiotics will lead to inclusion of an isolate when \code{type = "points"}, see \emph{Details}}

View File

@ -196,6 +196,10 @@ test_that("first isolates work", {
expect_equal(sum(first_isolate(test_unknown)),
1045)
# empty rsi results
expect_equal(sum(first_isolate(example_isolates, include_untested_rsi = FALSE)),
1287)
# shortcuts
expect_identical(filter_first_isolate(example_isolates),
subset(example_isolates, first_isolate(example_isolates)))

View File

@ -95,20 +95,20 @@ test_that("mic2rsi works", {
mo = "B_STRPT_PNMN",
ab = "AMP",
guideline = "EUCAST 2020")),
c("S", "S", "I", "I", "R"), info = pkg_env$strange)
c("S", "S", "I", "I", "R"))
# S. pneumoniae/amoxicillin in CLSI 2019: 2-8 ug/ml (R is 8 and > 8)
expect_equal(as.character(
as.rsi(x = as.mic(c(1, 2, 4, 8, 16)),
mo = "B_STRPT_PNMN",
ab = "AMX",
guideline = "CLSI 2019")),
c("S", "S", "I", "R", "R"), info = pkg_env$strange)
c("S", "S", "I", "R", "R"))
# cutoffs at MIC = 8
expect_equal(as.rsi(as.mic(2), "E. coli", "ampicillin", guideline = "EUCAST 2020"),
as.rsi("S"), info = pkg_env$strange)
as.rsi("S"))
expect_equal(as.rsi(as.mic(32), "E. coli", "ampicillin", guideline = "EUCAST 2020"),
as.rsi("R"), info = pkg_env$strange)
as.rsi("R"))
expect_true(suppressWarnings(example_isolates %>%
mutate(amox_mic = as.mic(2)) %>%