mirror of
https://github.com/msberends/AMR.git
synced 2026-11-15 22:20:47 +01:00
EUCAST import: blocking rows, note restrictions, PK-PD and parser fixes (#310)
Make the EUCAST Clinical Breakpoint Tables import (2019-2026) fail-safe: - Add blocking rows (NA breakpoints, reason in `note`) where EUCAST gives no breakpoint for an organism (IE, "-", Note, brackets, "except" clauses, table scope), so as.sir() no longer falls back to broader taxa - Apply restrictions from EUCAST notes via a curated rule table with a completeness guard (e.g. zone diameters for E. coli only) - Import PK-PD (non-species related) breakpoints 2019-2023, H. parainfluenzae MIC breakpoints, and explicit screening thresholds from notes (high-level aminoglycosides, cefoxitin MIC, unidentified CoNS) - Parser fixes: lost Staphylococcus sheets 2019/2020, note keys and bodies, struck-through cells, hidden sheets, missing disk contents, organism groups, site vocabulary, MIC dilution levels, off-scale breakpoints stored as 0.0001 - Keep EUCAST antifungal breakpoints 2019-2025 from WHONET; code WHONET streptomycin as STR1 instead of STR (streptoduocin) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5d9974e2b9
commit
dab4c47e86
25 files changed
+83693
-58604
No files matched your search
@@ -28,6 +28,9 @@ Planned as v3.1.0, mid October 2026.
|
||||
### 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
|
||||
* Human EUCAST breakpoints from 2019 (v9.0) on, are now retrieved directly from EUCAST Excel files instead of relying on the WHONET repository.
|
||||
* `clinical_breakpoints` now contains blocking rows (`NA` breakpoints, reason in `note`) where EUCAST gives no breakpoint for an organism, so `as.sir()` no longer falls back to the breakpoint of a broader taxon
|
||||
* Restrictions in EUCAST notes are applied, e.g. zone diameter breakpoints for *E. coli* only
|
||||
* EUCAST PK-PD (non-species related) breakpoints 2019-2023 and *H. parainfluenzae* MIC breakpoints are included
|
||||
* 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)
|
||||
* *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
|
||||
@@ -40,6 +43,7 @@ Planned as v3.1.0, mid October 2026.
|
||||
* New `wisca_plot()` to assess the susceptibility and incidence distributions from the Monte Carlo simulations
|
||||
|
||||
### Fixed
|
||||
* Streptomycin breakpoints imported from WHONET were coded as streptoduocin (`STR`) instead of streptomycin (`STR1`)
|
||||
* Setting `options(AMR_guideline = "EUCAST 2012")` or any year-qualified value no longer causes errors or silent wrong behaviour in `interpretive_rules()`, `resistance()`, `susceptibility()`, `count_resistant()`, `count_susceptible()`, and SIR plotting/printing functions (#298)
|
||||
* `as.sir()`
|
||||
* On data frames: already-converted SIR columns no longer dropped on re-run (#278)
|
||||
|
||||
@@ -297,20 +297,24 @@
|
||||
#' - `method`\cr Testing method, either `r vector_or(clinical_breakpoints$method, documentation = TRUE)`
|
||||
#' - `site`\cr Body site for which the breakpoint must be applied, e.g. "Oral" or "Respiratory"
|
||||
#' - `mo`\cr Microbial ID, see [as.mo()]
|
||||
#' - `rank_index`\cr Taxonomic rank index of `mo` from 1 (subspecies/infraspecies) to 5 (unknown microorganism)
|
||||
#' - `rank_index`\cr Taxonomic rank index of `mo` from 1 (subspecies/infraspecies) to 7 (non-species related breakpoints), used to choose the most specific breakpoint; blocking rows (see *Details*) have the rank index of their organism + 0.1
|
||||
#' - `ab`\cr Antimicrobial code as used by this package, EARS-Net and WHONET, see [as.ab()]
|
||||
#' - `ref_tbl`\cr Info about where the guideline rule can be found
|
||||
#' - `disk_dose`\cr Dose of the used disk diffusion method
|
||||
#' - `breakpoint_S`\cr Lowest MIC value or highest number of millimetres that leads to "S"
|
||||
#' - `breakpoint_S`\cr Lowest MIC value or highest number of millimetres that leads to "S", is `NA` for blocking rows (see *Details*)
|
||||
#' - `breakpoint_R`\cr Highest MIC value or lowest number of millimetres that leads to "R", can be `NA`
|
||||
#' - `uti`\cr A [logical] value (`TRUE`/`FALSE`) to indicate whether the rule applies to a urinary tract infection (UTI)
|
||||
#' - `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.
|
||||
#' - `note`\cr Notes from the guideline that apply to the breakpoint, if available
|
||||
#' @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.
|
||||
#'
|
||||
#' 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.
|
||||
#'
|
||||
#' ### Blocking Rows
|
||||
#' Where EUCAST lists an organism but gives no breakpoint for it (e.g. "IE", "-", "Note", breakpoints in brackets, or an organism excluded with "except"), [as.sir()] must not fall back to the breakpoint of a broader taxon, such as the breakpoint for *Vibrio* spp. where EUCAST gives "IE" for *V. fluvialis*. Such cases are included as "blocking rows": rows in which `breakpoint_S` and `breakpoint_R` are both `NA` and the `note` starts with `"[No breakpoint]"` followed by the reason. [as.sir()] returns `NA` for these. This currently applies to `r format(sum(is.na(clinical_breakpoints$breakpoint_S) & is.na(clinical_breakpoints$breakpoint_R)), big.mark = " ")` rows. Remove them with `subset(clinical_breakpoints, !is.na(breakpoint_S))` if only actual breakpoints are needed.
|
||||
#'
|
||||
#' ### Imported From WHONET
|
||||
#' Some breakpoints in this package were validated through and imported from [WHONET](https://whonet.org), a free desktop Windows application developed and supported by the WHO Collaborating Centre for Surveillance of Antimicrobial Resistance. More can be read on [their website](https://whonet.org). The developers of WHONET and this `AMR` package have been in contact about sharing their work. We highly appreciate their great development on the WHONET software.
|
||||
#'
|
||||
@@ -319,9 +323,10 @@
|
||||
#' * All CLSI breakpoints, including ECOFF
|
||||
#' * All non-human EUCAST breakpoints, including ECOFF
|
||||
#' * Human EUCAST breakpoints between `r min(as.integer(gsub("[^0-9]", "", subset(AMR::clinical_breakpoints, guideline %like% "EUCAST" & type == "human")$guideline)))` and 2018
|
||||
#' * Human EUCAST antifungal breakpoints between 2019 and 2025
|
||||
#'
|
||||
#' Human EUCAST breakpoints from 2019 onwards (antifungal breakpoints from 2026 onwards) were retrieved directly from the EUCAST Clinical Breakpoint Tables published on <https://www.eucast.org>, using [this script](https://github.com/msberends/AMR/blob/main/data-raw/_reproduction_scripts/reproduction_of_clinical_breakpoints_eucast.R).
|
||||
#'
|
||||
#' Human EUCAST breakpoints from 2019 onwards, were retrieved directly from <https://www.eucast.org> using [this script](https://github.com/msberends/AMR/blob/main/data-raw/_reproduction_scripts/reproduction_of_clinical_breakpoints_eucast.R).
|
||||
#'
|
||||
#' Our WHONET import script can be [found here](https://github.com/msberends/AMR/blob/main/data-raw/_reproduction_scripts/reproduction_of_clinical_breakpoints.R).
|
||||
#'
|
||||
#' ### Response From CLSI and EUCAST
|
||||
|
||||
Binary file not shown.
@@ -653,7 +653,8 @@ if (changed_md5(clin_break)) {
|
||||
try(saveRDS(clin_break, "data-raw/datasets/clinical_breakpoints.rds", version = 2, compress = "xz"), silent = TRUE)
|
||||
try(write.table(clinical_breakpoints, "data-raw/datasets/clinical_breakpoints.txt", sep = "\t", na = "", row.names = FALSE), silent = TRUE)
|
||||
try(haven::write_sav(clin_break, "data-raw/datasets/clinical_breakpoints.sav"), silent = TRUE)
|
||||
try(haven::write_dta(clin_break, "data-raw/datasets/clinical_breakpoints.dta"), silent = TRUE)
|
||||
# long notes as strL, otherwise Stata's fixed-width strings make the file exceed 100 MB; a missing string is "" in Stata
|
||||
try(haven::write_dta(clin_break %>% mutate(note = if_else(is.na(note), "", note)), "data-raw/datasets/clinical_breakpoints.dta", strl_threshold = 255), silent = TRUE)
|
||||
try(openxlsx2::write_xlsx(clin_break, "data-raw/datasets/clinical_breakpoints.xlsx"), silent = TRUE)
|
||||
try(arrow::write_feather(clin_break, "data-raw/datasets/clinical_breakpoints.feather"), silent = TRUE)
|
||||
try(arrow::write_parquet(clin_break, "data-raw/datasets/clinical_breakpoints.parquet"), silent = TRUE)
|
||||
|
||||
@@ -282,6 +282,24 @@ breakpoints |>
|
||||
breakpoints <- breakpoints |>
|
||||
filter(!is.na(WHONET_ABX_CODE))
|
||||
|
||||
# a WHONET code can also exist in `antimicrobials` as the code of another
|
||||
# agent, e.g. WHONET "STR" (streptomycin) is "STR" (streptoduocin) here, so
|
||||
# compare the code with WHONET's own name of the agent:
|
||||
whonet_code_check <- breakpoints |>
|
||||
distinct(WHONET_ABX_CODE) |>
|
||||
left_join(whonet_antibiotics_raw |> select(WHONET_ABX_CODE, ANTIBIOTIC), by = "WHONET_ABX_CODE") |>
|
||||
filter(!is.na(ANTIBIOTIC)) |>
|
||||
mutate(
|
||||
by_code = as.ab(if_else(WHONET_ABX_CODE == "STR", "STR1", WHONET_ABX_CODE), info = FALSE),
|
||||
by_name = as.ab(ANTIBIOTIC, info = FALSE)
|
||||
) |>
|
||||
filter(is.na(by_code) | is.na(by_name) | by_code != by_name)
|
||||
# 2026-10-01: SUD (WHONET: sulbactam-durlobactam, CLSI 2024-2026) is
|
||||
# sulfadimethoxine here, and sulbactam-durlobactam is not in `antimicrobials`
|
||||
# yet; this must be resolved before these breakpoints can be used. This
|
||||
# should otherwise be empty:
|
||||
whonet_code_check
|
||||
|
||||
|
||||
## Build new breakpoints table ----
|
||||
|
||||
@@ -304,7 +322,10 @@ breakpoints_new <- breakpoints |>
|
||||
mo_rank(mo, keep_synonyms = TRUE) == "order" ~ 5,
|
||||
TRUE ~ 6
|
||||
),
|
||||
ab = as.ab(WHONET_ABX_CODE),
|
||||
# WHONET code "STR" is streptomycin, but in this package "STR" is
|
||||
# streptoduocin (streptomycin is "STR1"), so as.ab("STR") would return
|
||||
# the wrong agent
|
||||
ab = as.ab(if_else(WHONET_ABX_CODE == "STR", "STR1", WHONET_ABX_CODE)),
|
||||
ref_tbl = ifelse(type == "ECOFF" & is.na(REFERENCE_TABLE), "ECOFF", REFERENCE_TABLE),
|
||||
disk_dose = POTENCY,
|
||||
breakpoint_S = ifelse(type == "ECOFF" & is.na(S) & !is.na(ECV_ECOFF), ECV_ECOFF, S),
|
||||
@@ -505,6 +526,9 @@ dim(clinical_breakpoints)
|
||||
|
||||
# Retrieve >= EUCAST 2019 directly from EUCAST ----
|
||||
|
||||
# This parses the EUCAST Clinical Breakpoint Tables in data-raw/ and creates
|
||||
# `breakpoints_eucast`, `eucast_coverage` and merge_eucast_breakpoints(), used
|
||||
# below to replace the WHONET-based human EUCAST rows that these tables cover
|
||||
source("data-raw/_reproduction_scripts/reproduction_of_clinical_breakpoints_eucast.R")
|
||||
|
||||
|
||||
@@ -525,8 +549,7 @@ breakpoints_new <- breakpoints_new |>
|
||||
# and arrange
|
||||
arrange(desc(guideline), mo, ab, type, host, method)
|
||||
|
||||
clinical_breakpoints <- breakpoints_new
|
||||
clinical_breakpoints <- clinical_breakpoints |> dataset_UTF8_to_ASCII()
|
||||
clinical_breakpoints <- merge_eucast_breakpoints(breakpoints_new, breakpoints_eucast, eucast_coverage)
|
||||
usethis::use_data(clinical_breakpoints, overwrite = TRUE, compress = "xz", version = 2)
|
||||
rm(clinical_breakpoints)
|
||||
devtools::load_all(".")
|
||||
File diff suppressed because it is too large.
Load diff
+21859
-12592
File diff suppressed because it is too large.
Load diff
Binary file not shown.
@@ -1 +1 @@
|
||||
634c5e23bed1e92783eeb4739c0d1486
|
||||
c23b72fd46f4a08b2033b104cef0d4e1
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+60497
-45736
File diff suppressed because it is too large.
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -27,12 +27,9 @@
|
||||
<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>
|
||||
|
||||
@@ -62,7 +59,7 @@ times](https://scholar.google.com/citations?view_op=view_citation&hl=en&citation
|
||||
in scientific research.
|
||||
|
||||
After installing this package, R knows [**~97 000 distinct microbial
|
||||
species**](./reference/microorganisms.html) (updated May 2026) and all
|
||||
species**](./reference/microorganisms.html) (updated mei 2026) and all
|
||||
[**~620 antimicrobial and antiviral
|
||||
drugs**](./reference/antimicrobials.html) by name and code (including
|
||||
ATC, EARS-Net, ASIARS-Net, PubChem, LOINC and SNOMED CT), and knows all
|
||||
@@ -227,8 +224,8 @@ wisca(example_isolates,
|
||||
```
|
||||
|
||||
| Piperacillin/tazobactam | Piperacillin/tazobactam + Gentamicin | Piperacillin/tazobactam + Tobramycin |
|
||||
|:---|:---|:---|
|
||||
| 70.2% (64.6-75.4%) | 93.6% (92.1-95%) | 89.9% (87-92.5%) |
|
||||
|:------------------------|:-------------------------------------|:-------------------------------------|
|
||||
| 70% (64.9-75.3%) | 93.6% (92.1-95%) | 89.9% (87.1-92.3%) |
|
||||
|
||||
WISCA supports stratification by any clinical variable, so you can
|
||||
generate syndrome-specific or ward-specific coverage estimates:
|
||||
@@ -242,10 +239,10 @@ wisca(example_isolates,
|
||||
```
|
||||
|
||||
| Syndromic Group | Piperacillin/tazobactam | Piperacillin/tazobactam + Gentamicin | Piperacillin/tazobactam + Tobramycin |
|
||||
|:---|:---|:---|:---|
|
||||
| Clinical | 74.7% (68.9-80.8%) | 93.7% (92.1-95.2%) | 90.5% (87-93.2%) |
|
||||
| ICU | 57% (48.2-65.7%) | 86.8% (83.4-89.8%) | 83% (78-87.6%) |
|
||||
| Outpatient | 57.2% (46.2-68.9%) | 76.6% (70.1-82.1%) | 67.7% (57.6-77.5%) |
|
||||
|:----------------|:------------------------|:-------------------------------------|:-------------------------------------|
|
||||
| Clinical | 74.8% (69.1-80.2%) | 93.6% (92.1-95.1%) | 90.4% (87.2-93.1%) |
|
||||
| ICU | 57.2% (49.2-65.6%) | 86.7% (83.4-89.9%) | 82.9% (78.1-87.2%) |
|
||||
| Outpatient | 57.6% (46.3-69.2%) | 76.5% (70.5-82%) | 67.6% (57.3-77.1%) |
|
||||
|
||||
**For AMR surveillance**, traditional antibiograms remain the right tool
|
||||
for tracking resistance per species over time:
|
||||
@@ -257,10 +254,10 @@ antibiogram(example_isolates,
|
||||
#> ℹ For `carbapenems()` using columns IPM (imipenem) and MEM (meropenem)
|
||||
```
|
||||
|
||||
| Pathogen | Amoxicillin/clavulanic acid | Imipenem | Meropenem | Piperacillin/tazobactam |
|
||||
|:---|:---|:---|:---|:---|
|
||||
| Gram-negative | 76% (73-79%,N=726) | 99% (98-100%,N=631) | 100% (99-100%,N=626) | 88% (85-91%,N=641) |
|
||||
| Gram-positive | 76% (74-79%,N=1138) | 81% (75-85%,N=257) | 77% (70-82%,N=203) | 86% (82-89%,N=345) |
|
||||
| Pathogen | Amoxicillin/clavulanic acid | Imipenem | Meropenem | Piperacillin/tazobactam |
|
||||
|:--------------|:----------------------------|:--------------------|:---------------------|:------------------------|
|
||||
| Gram-negative | 76% (73-79%,N=726) | 99% (98-100%,N=631) | 100% (99-100%,N=626) | 88% (85-91%,N=641) |
|
||||
| Gram-positive | 76% (74-79%,N=1138) | 81% (75-85%,N=257) | 77% (70-82%,N=203) | 86% (82-89%,N=345) |
|
||||
|
||||
Combination antibiograms show the additional coverage gained by adding a
|
||||
second agent, stratified by species:
|
||||
@@ -271,10 +268,10 @@ antibiogram(example_isolates,
|
||||
antimicrobials = c("TZP", "TZP+TOB", "TZP+GEN"))
|
||||
```
|
||||
|
||||
| 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()` and `wisca()`
|
||||
come with support for 28 languages that are often detected automatically
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
\alias{clinical_breakpoints}
|
||||
\title{Data Set with Clinical Breakpoints for SIR Interpretation}
|
||||
\format{
|
||||
A \link[tibble:tibble]{tibble} with 44 089 observations and 15 variables:
|
||||
A \link[tibble:tibble]{tibble} with 60 173 observations and 15 variables:
|
||||
\itemize{
|
||||
\item \code{guideline}\cr Name of the guideline
|
||||
\item \code{type}\cr Breakpoint type, either \code{"ECOFF"}, \code{"animal"}, or \code{"human"}
|
||||
@@ -13,14 +13,15 @@ A \link[tibble:tibble]{tibble} with 44 089 observations and 15 variables:
|
||||
\item \code{method}\cr Testing method, either \code{"DISK"} or \code{"MIC"}
|
||||
\item \code{site}\cr Body site for which the breakpoint must be applied, e.g. "Oral" or "Respiratory"
|
||||
\item \code{mo}\cr Microbial ID, see \code{\link[=as.mo]{as.mo()}}
|
||||
\item \code{rank_index}\cr Taxonomic rank index of \code{mo} from 1 (subspecies/infraspecies) to 5 (unknown microorganism)
|
||||
\item \code{rank_index}\cr Taxonomic rank index of \code{mo} from 1 (subspecies/infraspecies) to 7 (non-species related breakpoints), used to choose the most specific breakpoint; blocking rows (see \emph{Details}) have the rank index of their organism + 0.1
|
||||
\item \code{ab}\cr Antimicrobial code as used by this package, EARS-Net and WHONET, see \code{\link[=as.ab]{as.ab()}}
|
||||
\item \code{ref_tbl}\cr Info about where the guideline rule can be found
|
||||
\item \code{disk_dose}\cr Dose of the used disk diffusion method
|
||||
\item \code{breakpoint_S}\cr Lowest MIC value or highest number of millimetres that leads to "S"
|
||||
\item \code{breakpoint_S}\cr Lowest MIC value or highest number of millimetres that leads to "S", is \code{NA} for blocking rows (see \emph{Details})
|
||||
\item \code{breakpoint_R}\cr Highest MIC value or lowest number of millimetres that leads to "R", can be \code{NA}
|
||||
\item \code{uti}\cr A \link{logical} value (\code{TRUE}/\code{FALSE}) to indicate whether the rule applies to a urinary tract infection (UTI)
|
||||
\item \code{is_SDD}\cr A \link{logical} value (\code{TRUE}/\code{FALSE}) to indicate whether the intermediate range between "S" and "R" should be interpreted as "SDD", instead of "I". This currently applies to 72 breakpoints.
|
||||
\item \code{note}\cr Notes from the guideline that apply to the breakpoint, if available
|
||||
}
|
||||
}
|
||||
\usage{
|
||||
@@ -46,6 +47,11 @@ Supported types of breakpoints are ECOFF, animal, and human. ECOFF (Epidemiologi
|
||||
The default is \code{"human"}, which can also be set with the package option \code{\link[=AMR-options]{AMR_breakpoint_type}}. Use \code{\link[=as.sir]{as.sir(..., breakpoint_type = ...)}} to interpret raw data using a specific breakpoint type, e.g. \code{as.sir(..., breakpoint_type = "ECOFF")} to use ECOFFs.
|
||||
}
|
||||
|
||||
\subsection{Blocking Rows}{
|
||||
|
||||
Where EUCAST lists an organism but gives no breakpoint for it (e.g. "IE", "-", "Note", breakpoints in brackets, or an organism excluded with "except"), \code{\link[=as.sir]{as.sir()}} must not fall back to the breakpoint of a broader taxon, such as the breakpoint for \emph{Vibrio} spp. where EUCAST gives "IE" for \emph{V. fluvialis}. Such cases are included as "blocking rows": rows in which \code{breakpoint_S} and \code{breakpoint_R} are both \code{NA} and the \code{note} starts with \code{"[No breakpoint]"} followed by the reason. \code{\link[=as.sir]{as.sir()}} returns \code{NA} for these. This currently applies to 14 523 rows. Remove them with \code{subset(clinical_breakpoints, !is.na(breakpoint_S))} if only actual breakpoints are needed.
|
||||
}
|
||||
|
||||
\subsection{Imported From WHONET}{
|
||||
|
||||
Some breakpoints in this package were validated through and imported from \href{https://whonet.org}{WHONET}, a free desktop Windows application developed and supported by the WHO Collaborating Centre for Surveillance of Antimicrobial Resistance. More can be read on \href{https://whonet.org}{their website}. The developers of WHONET and this \code{AMR} package have been in contact about sharing their work. We highly appreciate their great development on the WHONET software.
|
||||
@@ -55,9 +61,10 @@ From WHONET, imported were:
|
||||
\item All CLSI breakpoints, including ECOFF
|
||||
\item All non-human EUCAST breakpoints, including ECOFF
|
||||
\item Human EUCAST breakpoints between 2011 and 2018
|
||||
\item Human EUCAST antifungal breakpoints between 2019 and 2025
|
||||
}
|
||||
|
||||
Human EUCAST breakpoints from 2019 onwards, were retrieved directly from \url{https://www.eucast.org} using \href{https://github.com/msberends/AMR/blob/main/data-raw/_reproduction_scripts/reproduction_of_clinical_breakpoints_eucast.R}{this script}.
|
||||
Human EUCAST breakpoints from 2019 onwards (antifungal breakpoints from 2026 onwards) were retrieved directly from the EUCAST Clinical Breakpoint Tables published on \url{https://www.eucast.org}, using \href{https://github.com/msberends/AMR/blob/main/data-raw/_reproduction_scripts/reproduction_of_clinical_breakpoints_eucast.R}{this script}.
|
||||
|
||||
Our WHONET import script can be \href{https://github.com/msberends/AMR/blob/main/data-raw/_reproduction_scripts/reproduction_of_clinical_breakpoints.R}{found here}.
|
||||
}
|
||||
|
||||
+1
-1
@@ -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 (Agresti, 2007, section 2.4.5
|
||||
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)}
|
||||
for the case where \code{x} is a matrix, \code{n * p * (1 - p)} otherwise).}
|
||||
}
|
||||
\description{
|
||||
|
||||
+3
-2
@@ -59,8 +59,9 @@ ggplot_pca(
|
||||
}
|
||||
|
||||
\item{pc.biplot}{
|
||||
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
|
||||
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
|
||||
variables scaled down by sqrt(n). Then inner products between
|
||||
variables approximate covariances and distances between observations
|
||||
approximate Mahalanobis distance.
|
||||
|
||||
@@ -63,10 +63,14 @@ test_that("test-data.R", {
|
||||
)
|
||||
|
||||
# check valid disks/MICs
|
||||
expect_false(anyNA(as.mic(clinical_breakpoints[which(clinical_breakpoints$method == "MIC" & clinical_breakpoints$ref_tbl != "ECOFF"), "breakpoint_S", drop = TRUE])))
|
||||
expect_true(anyNA(as.mic(clinical_breakpoints[which(clinical_breakpoints$method == "MIC" & clinical_breakpoints$ref_tbl != "ECOFF"), "breakpoint_R", drop = TRUE])))
|
||||
expect_false(anyNA(as.disk(clinical_breakpoints[which(clinical_breakpoints$method == "DISK" & clinical_breakpoints$ref_tbl != "ECOFF"), "breakpoint_S", drop = TRUE])))
|
||||
expect_true(anyNA(as.disk(clinical_breakpoints[which(clinical_breakpoints$method == "DISK" & clinical_breakpoints$ref_tbl != "ECOFF"), "breakpoint_R", drop = TRUE])))
|
||||
# rows without any breakpoint are EUCAST's blocking rows ("no breakpoint" for that organism), which must state their reason
|
||||
is_blocking <- is.na(clinical_breakpoints$breakpoint_S) & is.na(clinical_breakpoints$breakpoint_R)
|
||||
expect_true(all(grepl("^\\[No breakpoint\\] ", clinical_breakpoints$note[is_blocking])))
|
||||
expect_true(all(clinical_breakpoints$guideline[is_blocking] %like% "EUCAST"))
|
||||
expect_false(anyNA(as.mic(clinical_breakpoints[which(clinical_breakpoints$method == "MIC" & clinical_breakpoints$ref_tbl != "ECOFF" & !is_blocking), "breakpoint_S", drop = TRUE])))
|
||||
expect_true(anyNA(as.mic(clinical_breakpoints[which(clinical_breakpoints$method == "MIC" & clinical_breakpoints$ref_tbl != "ECOFF" & !is_blocking), "breakpoint_R", drop = TRUE])))
|
||||
expect_false(anyNA(as.disk(clinical_breakpoints[which(clinical_breakpoints$method == "DISK" & clinical_breakpoints$ref_tbl != "ECOFF" & !is_blocking), "breakpoint_S", drop = TRUE])))
|
||||
expect_true(anyNA(as.disk(clinical_breakpoints[which(clinical_breakpoints$method == "DISK" & clinical_breakpoints$ref_tbl != "ECOFF" & !is_blocking), "breakpoint_R", drop = TRUE])))
|
||||
|
||||
# antibiotic names must always be coercible to their original AB code
|
||||
expect_identical(as.ab(AMR::antimicrobials$name), AMR::antimicrobials$ab)
|
||||
|
||||
@@ -602,3 +602,45 @@ test_that("custom reference_data: host = NA acts as host-agnostic fallback", {
|
||||
)
|
||||
expect_equal(as.character(result), "R")
|
||||
})
|
||||
|
||||
test_that("EUCAST blocking rows prevent falling back to broader breakpoints", {
|
||||
skip_on_cran()
|
||||
sir <- function(x, mo, ab, guideline, include_screening = FALSE) {
|
||||
as.character(suppressMessages(suppressWarnings(
|
||||
as.sir(x, mo = mo, ab = ab, guideline = guideline, include_screening = include_screening)
|
||||
)))
|
||||
}
|
||||
# IE for V. fluvialis, while Vibrio spp. has breakpoints
|
||||
expect_identical(sir(as.mic(0.125), "Vibrio fluvialis", "CTX", "EUCAST 2026"), NA_character_)
|
||||
expect_identical(sir(as.mic(0.125), "Vibrio cholerae", "CTX", "EUCAST 2026"), "S")
|
||||
# fosfomycin zone diameter breakpoints apply to E. coli only
|
||||
expect_identical(sir(as.disk(25), "Klebsiella pneumoniae", "FOS", "EUCAST 2019"), NA_character_)
|
||||
expect_identical(sir(as.disk(25), "Escherichia coli", "FOS", "EUCAST 2019"), "S")
|
||||
# "-" for enterococci must not fall back to the PK-PD breakpoints
|
||||
expect_identical(sir(as.mic(1), "Enterococcus faecalis", "CTX", "EUCAST 2021"), NA_character_)
|
||||
# exceptions: "Klebsiella spp. (except K. aerogenes)"
|
||||
expect_identical(sir(as.mic(2), "Klebsiella aerogenes", "CXM", "EUCAST 2026"), NA_character_)
|
||||
# agent listed in the Enterobacterales table for other organisms only
|
||||
expect_identical(sir(as.mic(0.5), "Salmonella enterica", "CXM", "EUCAST 2026"), NA_character_)
|
||||
# no EUCAST breakpoints at all, so no PK-PD breakpoints either
|
||||
expect_identical(sir(as.mic(0.5), "Burkholderia cepacia complex", "MEM", "EUCAST 2020"), NA_character_)
|
||||
# PK-PD breakpoints only until EUCAST 2023
|
||||
expect_identical(sir(as.mic(0.25), "Nocardia asteroides", "AMX", "EUCAST 2020"), "S")
|
||||
expect_identical(sir(as.mic(0.25), "Nocardia asteroides", "AMX", "EUCAST 2024"), NA_character_)
|
||||
# H. influenzae MIC breakpoints apply to H. parainfluenzae, zone diameters do not
|
||||
expect_identical(sir(as.mic(0.5), "Haemophilus parainfluenzae", "CIP", "EUCAST 2026"), "R")
|
||||
expect_identical(sir(as.disk(30), "Haemophilus parainfluenzae", "CIP", "EUCAST 2026"), NA_character_)
|
||||
# cefoxitin screen: CoNS not identified to species level use S >= 25 mm
|
||||
expect_identical(sir(as.disk(23), "B_STPHY_CONS", "FOX", "EUCAST 2026", include_screening = TRUE), "R")
|
||||
expect_identical(sir(as.disk(23), "Staphylococcus hominis", "FOX", "EUCAST 2026", include_screening = TRUE), "S")
|
||||
expect_identical(sir(as.disk(26), "Staphylococcus epidermidis", "FOX", "EUCAST 2026", include_screening = TRUE), "R")
|
||||
expect_identical(sir(as.disk(26), "Staphylococcus epidermidis", "FOX", "EUCAST 2026"), NA_character_)
|
||||
# topical screening cut-off values do not replace systemic breakpoints
|
||||
expect_identical(sir(as.mic(0.5), "Staphylococcus aureus", "FUS", "EUCAST 2026"), "S")
|
||||
# off-scale breakpoint S <= 0.001 mg/L categorises wild type isolates as I
|
||||
expect_identical(sir(as.mic(0.0005), "Pseudomonas aeruginosa", "CIP", "EUCAST 2026"), "I")
|
||||
# EUCAST's 0.06 mg/L is the dilution 0.0625, i.e. 0.064 in this package
|
||||
expect_identical(sir(as.mic(0.064), "Haemophilus influenzae", "LVX", "EUCAST 2026"), "S")
|
||||
# high-level gentamicin resistance (screening test given in the notes)
|
||||
expect_identical(sir(as.mic(256), "Enterococcus faecium", "GEH", "EUCAST 2026"), "R")
|
||||
})
|
||||
Reference in new issue
Block a user