mirror of https://github.com/msberends/AMR.git
376 lines
12 KiB
R
376 lines
12 KiB
R
# ==================================================================== #
|
|
# TITLE #
|
|
# Antimicrobial Resistance (AMR) Analysis #
|
|
# #
|
|
# AUTHORS #
|
|
# Berends MS (m.s.berends@umcg.nl), Luz CF (c.f.luz@umcg.nl) #
|
|
# #
|
|
# LICENCE #
|
|
# This program is free software; you can redistribute it and/or modify #
|
|
# it under the terms of the GNU General Public License version 2.0, #
|
|
# as published by the Free Software Foundation. #
|
|
# #
|
|
# This program is distributed in the hope that it will be useful, #
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
# GNU General Public License for more details. #
|
|
# ==================================================================== #
|
|
|
|
#' Class 'rsi'
|
|
#'
|
|
#' This transforms a vector to a new class \code{rsi}, which is an ordered factor with levels \code{S < I < R}. Invalid antimicrobial interpretations will be translated as \code{NA} with a warning.
|
|
#' @rdname as.rsi
|
|
#' @param x vector
|
|
#' @return New class \code{rsi}
|
|
#' @export
|
|
#' @importFrom dplyr %>%
|
|
#' @examples
|
|
#' rsi_data <- as.rsi(c(rep("S", 474), rep("I", 36), rep("R", 370)))
|
|
#' rsi_data <- as.rsi(c(rep("S", 474), rep("I", 36), rep("R", 370), "A", "B", "C"))
|
|
#' is.rsi(rsi_data)
|
|
#' plot(rsi_data)
|
|
#'
|
|
#' \donttest{
|
|
#' library(dplyr)
|
|
#' tbl %>%
|
|
#' mutate_at(vars(ends_with("_rsi")), as.rsi)
|
|
#' sapply(mic_data, is.rsi)
|
|
#' }
|
|
as.rsi <- function(x) {
|
|
if (is.rsi(x)) {
|
|
x
|
|
} else {
|
|
|
|
x <- x %>% unlist()
|
|
x.bak <- x
|
|
|
|
na_before <- x[is.na(x) | x == ''] %>% length()
|
|
x <- gsub('[^RSI]+', '', x %>% toupper())
|
|
# needed for UMCG in cases of "S;S" but also "S;I"; the latter will be NA:
|
|
x <- gsub('^S+$', 'S', x)
|
|
x <- gsub('^I+$', 'I', x)
|
|
x <- gsub('^R+$', 'R', x)
|
|
x[!x %in% c('S', 'I', 'R')] <- NA
|
|
na_after <- x[is.na(x) | x == ''] %>% length()
|
|
|
|
if (na_before != na_after) {
|
|
list_missing <- x.bak[is.na(x) & !is.na(x.bak) & x.bak != ''] %>%
|
|
unique() %>%
|
|
sort()
|
|
list_missing <- paste0('"', list_missing , '"', collapse = ", ")
|
|
warning(na_after - na_before, ' results truncated (',
|
|
round(((na_after - na_before) / length(x)) / 100),
|
|
'%) that were invalid antimicrobial interpretations: ',
|
|
list_missing, call. = FALSE)
|
|
}
|
|
|
|
x <- x %>% toupper() %>% factor(levels = c("S", "I", "R"), ordered = TRUE)
|
|
class(x) <- c('rsi', 'ordered', 'factor')
|
|
x
|
|
}
|
|
}
|
|
|
|
#' @rdname as.rsi
|
|
#' @export
|
|
#' @importFrom dplyr %>%
|
|
is.rsi <- function(x) {
|
|
class(x) %>% identical(c('rsi', 'ordered', 'factor'))
|
|
}
|
|
|
|
#' @exportMethod print.rsi
|
|
#' @export
|
|
#' @importFrom dplyr %>%
|
|
#' @noRd
|
|
print.rsi <- function(x, ...) {
|
|
n_total <- x %>% length()
|
|
x <- x[!is.na(x)]
|
|
n <- x %>% length()
|
|
S <- x[x == 'S'] %>% length()
|
|
I <- x[x == 'I'] %>% length()
|
|
R <- x[x == 'R'] %>% length()
|
|
IR <- x[x %in% c('I', 'R')] %>% length()
|
|
cat("Class 'rsi': ", n, " isolates\n", sep = '')
|
|
cat('\n')
|
|
cat('<NA>: ', n_total - n, '\n')
|
|
cat('Sum of S: ', S, '\n')
|
|
cat('Sum of IR: ', IR, '\n')
|
|
cat('- Sum of R:', R, '\n')
|
|
cat('- Sum of I:', I, '\n')
|
|
cat('\n')
|
|
print(c(
|
|
`%S` = round((S / n) * 100, 1),
|
|
`%IR` = round((IR / n) * 100, 1),
|
|
`%I` = round((I / n) * 100, 1),
|
|
`%R` = round((R / n) * 100, 1)
|
|
))
|
|
}
|
|
|
|
#' @exportMethod summary.rsi
|
|
#' @export
|
|
#' @importFrom dplyr %>%
|
|
#' @noRd
|
|
summary.rsi <- function(object, ...) {
|
|
x <- object
|
|
n_total <- x %>% length()
|
|
x <- x[!is.na(x)]
|
|
n <- x %>% length()
|
|
S <- x[x == 'S'] %>% length()
|
|
I <- x[x == 'I'] %>% length()
|
|
R <- x[x == 'R'] %>% length()
|
|
IR <- x[x %in% c('I', 'R')] %>% length()
|
|
lst <- c('rsi', n_total - n, S, IR, R, I)
|
|
names(lst) <- c("Mode", "<NA>", "Sum S", "Sum IR", "Sum R", "Sum I")
|
|
lst
|
|
}
|
|
|
|
#' @exportMethod plot.rsi
|
|
#' @export
|
|
#' @importFrom dplyr %>% group_by summarise filter mutate if_else
|
|
#' @importFrom graphics plot text
|
|
#' @noRd
|
|
plot.rsi <- function(x, ...) {
|
|
x_name <- deparse(substitute(x))
|
|
|
|
data <- data.frame(x = x,
|
|
y = 1,
|
|
stringsAsFactors = TRUE) %>%
|
|
group_by(x) %>%
|
|
summarise(n = sum(y)) %>%
|
|
filter(!is.na(x)) %>%
|
|
mutate(s = round((n / sum(n)) * 100, 1))
|
|
data$x <- factor(data$x, levels = c('S', 'I', 'R'), ordered = TRUE)
|
|
|
|
ymax <- if_else(max(data$s) > 95, 105, 100)
|
|
|
|
plot(x = data$x,
|
|
y = data$s,
|
|
lwd = 2,
|
|
col = c('green', 'orange', 'red'),
|
|
ylim = c(0, ymax),
|
|
ylab = 'Percentage',
|
|
xlab = 'Antimicrobial Interpretation',
|
|
main = paste('Susceptibilty Analysis of', x_name),
|
|
...)
|
|
text(x = data$x,
|
|
y = data$s + 5,
|
|
labels = paste0(data$s, '% (n = ', data$n, ')'))
|
|
}
|
|
|
|
#' Class 'mic'
|
|
#'
|
|
#' This transforms a vector to a new class\code{mic}, which is an ordered factor valid MIC values as levels. Invalid MIC values will be translated as \code{NA} with a warning.
|
|
#' @rdname as.mic
|
|
#' @param x vector
|
|
#' @param na.rm a logical indicating whether missing values should be removed
|
|
#' @return New class \code{mic}
|
|
#' @export
|
|
#' @importFrom dplyr %>%
|
|
#' @examples
|
|
#' mic_data <- as.mic(c(">=32", "1.0", "1", "1.00", 8, "<=0.128", "8", "16", "16"))
|
|
#' is.mic(mic_data)
|
|
#' plot(mic_data)
|
|
#'
|
|
#' \donttest{
|
|
#' library(dplyr)
|
|
#' tbl %>%
|
|
#' mutate_at(vars(ends_with("_mic")), as.mic)
|
|
#' sapply(mic_data, is.mic)
|
|
#' }
|
|
as.mic <- function(x, na.rm = FALSE) {
|
|
if (is.mic(x)) {
|
|
x
|
|
} else {
|
|
x <- x %>% unlist()
|
|
if (na.rm == TRUE) {
|
|
x <- x[!is.na(x)]
|
|
}
|
|
x.bak <- x
|
|
|
|
# comma to dot
|
|
x <- gsub(',', '.', x, fixed = TRUE)
|
|
# starting dots must start with 0
|
|
x <- gsub('^[.]', '0.', x)
|
|
# <=0.2560.512 should be 0.512
|
|
x <- gsub('.*[.].*[.]', '0.', x)
|
|
# remove ending .0
|
|
x <- gsub('[.]0$', '', x)
|
|
# remove all after last digit
|
|
x <- gsub('[^0-9]$', '', x)
|
|
# remove last zeroes
|
|
x <- gsub('[.]?0+$', '', x)
|
|
|
|
lvls <- c("<0.002", "<=0.002", "0.002", ">=0.002", ">0.002",
|
|
"<0.003", "<=0.003", "0.003", ">=0.003", ">0.003",
|
|
"<0.004", "<=0.004", "0.004", ">=0.004", ">0.004",
|
|
"<0.006", "<=0.006", "0.006", ">=0.006", ">0.006",
|
|
"<0.008", "<=0.008", "0.008", ">=0.008", ">0.008",
|
|
"<0.012", "<=0.012", "0.012", ">=0.012", ">0.012",
|
|
"<0.016", "<=0.016", "0.016", ">=0.016", ">0.016",
|
|
"<0.023", "<=0.023", "0.023", ">=0.023", ">0.023",
|
|
"<0.03", "<=0.03", "0.03", ">=0.03", ">0.03",
|
|
"<0.032", "<=0.032", "0.032", ">=0.032", ">0.032",
|
|
"<0.047", "<=0.047", "0.047", ">=0.047", ">0.047",
|
|
"<0.05", "<=0.05", "0.05", ">=0.05", ">0.05",
|
|
"<0.06", "<=0.06", "0.06", ">=0.06", ">0.06",
|
|
"<0.0625", "<=0.0625", "0.0625", ">=0.0625", ">0.0625",
|
|
"<0.064", "<=0.064", "0.064", ">=0.064", ">0.064",
|
|
"<0.09", "<=0.09", "0.09", ">=0.09", ">0.09",
|
|
"<0.094", "<=0.094", "0.094", ">=0.094", ">0.094",
|
|
"<0.12", "<=0.12", "0.12", ">=0.12", ">0.12",
|
|
"<0.125", "<=0.125", "0.125", ">=0.125", ">0.125",
|
|
"<0.128", "<=0.128", "0.128", ">=0.128", ">0.128",
|
|
"<0.19", "<=0.19", "0.19", ">=0.19", ">0.19",
|
|
"<0.25", "<=0.25", "0.25", ">=0.25", ">0.25",
|
|
"<0.256", "<=0.256", "0.256", ">=0.256", ">0.256",
|
|
"<0.38", "<=0.38", "0.38", ">=0.38", ">0.38",
|
|
"<0.5", "<=0.5", "0.5", ">=0.5", ">0.5",
|
|
"<0.512", "<=0.512", "0.512", ">=0.512", ">0.512",
|
|
"<0.75", "<=0.75", "0.75", ">=0.75", ">0.75",
|
|
"<1", "<=1", "1", ">=1", ">1",
|
|
"<1.5", "<=1.5", "1.5", ">=1.5", ">1.5",
|
|
"<2", "<=2", "2", ">=2", ">2",
|
|
"<3", "<=3", "3", ">=3", ">3",
|
|
"<4", "<=4", "4", ">=4", ">4",
|
|
"<6", "<=6", "6", ">=6", ">6",
|
|
"<8", "<=8", "8", ">=8", ">8",
|
|
"<10", "<=10", "10", ">=10", ">10",
|
|
"<12", "<=12", "12", ">=12", ">12",
|
|
"<16", "<=16", "16", ">=16", ">16",
|
|
"<20", "<=20", "20", ">=20", ">20",
|
|
"<24", "<=24", "24", ">=24", ">24",
|
|
"<32", "<=32", "32", ">=32", ">32",
|
|
"<40", "<=40", "40", ">=40", ">40",
|
|
"<48", "<=48", "48", ">=48", ">48",
|
|
"<64", "<=64", "64", ">=64", ">64",
|
|
"<80", "<=80", "80", ">=80", ">80",
|
|
"<96", "<=96", "96", ">=96", ">96",
|
|
"<128", "<=128", "128", ">=128", ">128",
|
|
"<160", "<=160", "160", ">=160", ">160",
|
|
"<256", "<=256", "256", ">=256", ">256",
|
|
"<320", "<=320", "320", ">=320", ">320",
|
|
"<512", "<=512", "512", ">=512", ">512",
|
|
"<1024", "<=1024", "1024", ">=1024", ">1024")
|
|
x <- x %>% as.character()
|
|
|
|
na_before <- x[is.na(x) | x == ''] %>% length()
|
|
x[!x %in% lvls] <- NA
|
|
na_after <- x[is.na(x) | x == ''] %>% length()
|
|
|
|
if (na_before != na_after) {
|
|
list_missing <- x.bak[is.na(x) & !is.na(x.bak) & x.bak != ''] %>%
|
|
unique() %>%
|
|
sort()
|
|
list_missing <- paste0('"', list_missing , '"', collapse = ", ")
|
|
warning(na_after - na_before, ' results truncated (',
|
|
round(((na_after - na_before) / length(x)) / 100),
|
|
'%) that were invalid MICs: ',
|
|
list_missing, call. = FALSE)
|
|
}
|
|
|
|
x <- factor(x = x,
|
|
levels = lvls,
|
|
ordered = TRUE)
|
|
class(x) <- c('mic', 'ordered', 'factor')
|
|
x
|
|
}
|
|
}
|
|
|
|
#' @rdname as.mic
|
|
#' @export
|
|
#' @importFrom dplyr %>%
|
|
is.mic <- function(x) {
|
|
class(x) %>% identical(c('mic', 'ordered', 'factor'))
|
|
}
|
|
|
|
#' @exportMethod as.double.mic
|
|
#' @export
|
|
#' @importFrom dplyr %>%
|
|
#' @noRd
|
|
as.double.mic <- function(x, ...) {
|
|
as.double(gsub('(<=)|(>=)', '', as.character(x)))
|
|
}
|
|
|
|
#' @exportMethod as.integer.mic
|
|
#' @export
|
|
#' @importFrom dplyr %>%
|
|
#' @noRd
|
|
as.integer.mic <- function(x, ...) {
|
|
as.integer(gsub('(<=)|(>=)', '', as.character(x)))
|
|
}
|
|
|
|
#' @exportMethod as.numeric.mic
|
|
#' @export
|
|
#' @importFrom dplyr %>%
|
|
#' @noRd
|
|
as.numeric.mic <- function(x, ...) {
|
|
as.numeric(gsub('(<=)|(>=)', '', as.character(x)))
|
|
}
|
|
|
|
#' @exportMethod print.mic
|
|
#' @export
|
|
#' @importFrom dplyr %>% tibble group_by summarise pull
|
|
#' @noRd
|
|
print.mic <- function(x, ...) {
|
|
n_total <- x %>% length()
|
|
x <- x[!is.na(x)]
|
|
n <- x %>% length()
|
|
cat("Class 'mic': ", n, " isolates\n", sep = '')
|
|
cat('\n')
|
|
cat('<NA> ', n_total - n, '\n')
|
|
cat('\n')
|
|
tbl <- tibble(x = x, y = 1) %>% group_by(x) %>% summarise(y = sum(y))
|
|
cnt <- tbl %>% pull(y)
|
|
names(cnt) <- tbl %>% pull(x)
|
|
print(cnt)
|
|
}
|
|
|
|
#' @exportMethod summary.mic
|
|
#' @export
|
|
#' @importFrom dplyr %>% tibble group_by summarise pull
|
|
#' @noRd
|
|
summary.mic <- function(object, ...) {
|
|
x <- object
|
|
n_total <- x %>% length()
|
|
x <- x[!is.na(x)]
|
|
n <- x %>% length()
|
|
return(c("Mode" = 'mic',
|
|
"NA" = n_total - n,
|
|
"Min." = sort(x)[1] %>% as.character(),
|
|
"Max." = sort(x)[n] %>% as.character()
|
|
))
|
|
cat("Class 'mic': ", n, " isolates\n", sep = '')
|
|
cat('\n')
|
|
cat('<NA> ', n_total - n, '\n')
|
|
cat('\n')
|
|
tbl <- tibble(x = x, y = 1) %>% group_by(x) %>% summarise(y = sum(y))
|
|
cnt <- tbl %>% pull(y)
|
|
names(cnt) <- tbl %>% pull(x)
|
|
print(cnt)
|
|
}
|
|
|
|
#' @exportMethod plot.mic
|
|
#' @export
|
|
#' @importFrom dplyr %>% group_by summarise
|
|
#' @importFrom graphics plot text
|
|
#' @noRd
|
|
plot.mic <- function(x, ...) {
|
|
x_name <- deparse(substitute(x))
|
|
|
|
data <- data.frame(mic = x, cnt = 1) %>%
|
|
group_by(mic) %>%
|
|
summarise(cnt = sum(cnt)) %>%
|
|
droplevels()
|
|
|
|
plot(x = data$mic,
|
|
y = data$cnt,
|
|
lwd = 2,
|
|
ylim = c(-0.5, max(5, max(data$cnt))),
|
|
ylab = 'Frequency',
|
|
xlab = 'MIC value',
|
|
main = paste('MIC values of', x_name),
|
|
...)
|
|
text(x = data$mic,
|
|
y = -0.5,
|
|
labels = paste('n =', data$cnt))
|
|
}
|