diff --git a/DESCRIPTION b/DESCRIPTION index 140c7b258..787073fbc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: AMR -Version: 1.5.0.9007 -Date: 2021-01-18 +Version: 1.5.0.9008 +Date: 2021-01-22 Title: Antimicrobial Resistance Analysis Authors@R: c( person(role = c("aut", "cre"), diff --git a/NAMESPACE b/NAMESPACE index b5b96919a..5caeab7e4 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -22,6 +22,7 @@ S3method("[[<-",isolate_identifier) S3method("[[<-",mic) S3method("[[<-",mo) S3method("[[<-",rsi) +S3method(all.equal,isolate_identifier) S3method(as.data.frame,ab) S3method(as.data.frame,mo) S3method(as.double,mic) diff --git a/NEWS.md b/NEWS.md index 73246277c..5cbbc5b54 100755 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,5 @@ -# AMR 1.5.0.9007 -## Last updated: 18 January 2021 +# AMR 1.5.0.9008 +## Last updated: 22 January 2021 ### 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. @@ -32,10 +32,12 @@ * Updated the data set `microorganisms.codes` (which contains popular LIS and WHONET codes for microorganisms) for some species of *Mycobacterium* that previously incorrectly returned *M. africanum* * Added Pretomanid (PMD, J04AK08) to the `antibiotics` data set * WHONET code `"PNV"` will now correctly be interpreted as `PHN`, the antibiotic code for phenoxymethylpenicillin ('peni V') -* Fix for verbose output of `mdro(..., verbose = TRUE)` for German guideline (3MGRN and 4MGRN) and *P. aeruginosa* in Dutch guideline (BRMO) +* Fix for verbose output of `mdro(..., verbose = TRUE)` for German guideline (3MGRN and 4MGRN) and Dutch guideline (BRMO, only *P. aeruginosa*) +* `is.rsi.eligible()` now returns `FALSE` immediately if the input does not contain any of the values "R", "S" or "I". This drastically improves speed, also for a lot of other functions that rely on automatic determination of antibiotic columns. ### Other * Big documentation updates +* Loading the package (i.e., `library(AMR)`) now is ~50 times faster than before # AMR 1.5.0 diff --git a/R/aa_helper_functions.R b/R/aa_helper_functions.R index c8fc76ae1..15b470ef8 100755 --- a/R/aa_helper_functions.R +++ b/R/aa_helper_functions.R @@ -585,7 +585,7 @@ get_current_data <- function(arg_name, call) { stop_("argument `", arg_name, "` is missing with no default", call = call) } } - + # try a (base R) method, by going over the complete system call stack with sys.frames() not_set <- TRUE frms <- lapply(sys.frames(), function(el) { @@ -615,6 +615,7 @@ get_current_data <- function(arg_name, call) { NULL } }) + vars_df <- tryCatch(frms[[which(!vapply(FUN.VALUE = logical(1), frms, is.null))]], error = function(e) NULL) if (is.data.frame(vars_df)) { return(vars_df) diff --git a/R/ab_class_selectors.R b/R/ab_class_selectors.R index db3a62ba3..ddbcfc217 100644 --- a/R/ab_class_selectors.R +++ b/R/ab_class_selectors.R @@ -173,7 +173,15 @@ ab_selector <- function(ab_class, function_name) { } vars_df <- get_current_data(arg_name = NA, call = -3) - ab_in_data <- get_column_abx(vars_df, info = FALSE) + + # improve speed here so it will only run once when e.g. in one select call + if (!identical(pkg_env$ab_selector, unique_call_id())) { + ab_in_data <- get_column_abx(vars_df, info = FALSE) + pkg_env$ab_selector <- unique_call_id() + pkg_env$ab_selector_cols <- ab_in_data + } else { + ab_in_data <- pkg_env$ab_selector_cols + } if (length(ab_in_data) == 0) { message_("No antimicrobial agents found.") @@ -199,13 +207,14 @@ ab_selector <- function(ab_class, function_name) { } else { agents_formatted <- paste0("column '", font_bold(agents, collapse = NULL), "'") agents_names <- ab_name(names(agents), tolower = TRUE, language = NULL) - agents_formatted[agents != agents_names] <- paste0(agents_formatted[agents != agents_names], - " (", agents_names[agents != agents_names], ")") + need_name <- tolower(agents) != tolower(agents_names) + agents_formatted[need_name] <- paste0(agents_formatted[need_name], + " (", agents_names[need_name], ")") message_("Selecting ", ab_group, ": ", paste(agents_formatted, collapse = ", "), as_note = FALSE, extra_indent = nchar(paste0("Selecting ", ab_group, ": "))) } - remember_thrown_message(function_name) - } + remember_thrown_message(function_name) + } unname(agents) } diff --git a/R/eucast_rules.R b/R/eucast_rules.R index a148f68f5..37c1e1a98 100755 --- a/R/eucast_rules.R +++ b/R/eucast_rules.R @@ -1049,6 +1049,7 @@ eucast_rules <- function(x, warn_lacking_rsi_class <- unique(warn_lacking_rsi_class) warning_("Not all columns with antimicrobial results are of class . Transform them on beforehand, with e.g.:\n", " ", x_deparsed, " %>% mutate_if(is.rsi.eligible, as.rsi)\n", + " ", x_deparsed, " %>% mutate(across((is.rsi.eligible), as.rsi))\n", " ", x_deparsed, " %>% as.rsi(", ifelse(length(warn_lacking_rsi_class) == 1, warn_lacking_rsi_class, paste0(warn_lacking_rsi_class[1], ":", warn_lacking_rsi_class[length(warn_lacking_rsi_class)])), diff --git a/R/guess_ab_col.R b/R/guess_ab_col.R index b273b6a2a..a48b72ab6 100755 --- a/R/guess_ab_col.R +++ b/R/guess_ab_col.R @@ -137,25 +137,25 @@ get_column_abx <- function(x, } else if (info == TRUE) { message_("...", appendLF = FALSE, as_note = FALSE) } - x_bak <- x + # only check columns that are a valid AB code, ATC code, name, abbreviation or synonym, # or already have the class (as.rsi) # and that they have no more than 50% invalid values vectr_antibiotics <- unique(toupper(unlist(antibiotics[, c("ab", "atc", "name", "abbreviations", "synonyms")]))) vectr_antibiotics <- vectr_antibiotics[!is.na(vectr_antibiotics) & nchar(vectr_antibiotics) >= 3] - x_columns <- vapply(FUN.VALUE = character(1), colnames(x), function(col, df = x_bak) { + x_columns <- vapply(FUN.VALUE = character(1), colnames(x), function(col, df = x) { if (toupper(col) %in% vectr_antibiotics || - is.rsi(as.data.frame(df, stringsAsFactors = FALSE)[, col, drop = TRUE]) || - is.rsi.eligible(as.data.frame(df, stringsAsFactors = FALSE)[, col, drop = TRUE], - threshold = 0.5)) { + is.rsi(x[, col, drop = TRUE]) || + is.rsi.eligible(x[, col, drop = TRUE], threshold = 0.5) + ) { return(col) } else { return(NA_character_) } }) + x_columns <- x_columns[!is.na(x_columns)] x <- x[, x_columns, drop = FALSE] # without drop = TRUE, x will become a vector when x_columns is length 1 - df_trans <- data.frame(colnames = colnames(x), abcode = suppressWarnings(as.ab(colnames(x), info = FALSE)), stringsAsFactors = FALSE) @@ -217,7 +217,6 @@ get_column_abx <- function(x, } } - if (!is.null(hard_dependencies)) { hard_dependencies <- unique(hard_dependencies) if (!all(hard_dependencies %in% names(x))) { diff --git a/R/isolate_identifier.R b/R/isolate_identifier.R index 8a2ceed8d..94a2c49c4 100644 --- a/R/isolate_identifier.R +++ b/R/isolate_identifier.R @@ -26,9 +26,10 @@ #' Create Identifier of an Isolate #' #' This function will paste the microorganism code with all antimicrobial results into one string for each row in a data set. This is useful to compare isolates, e.g. between institutions or regions, when there is no genotyping available. -#' @inheritSection lifecycle Maturing Lifecycle +#' @inheritSection lifecycle Experimental Lifecycle #' @inheritParams eucast_rules #' @param cols_ab a character vector of column names of `x`, or (a combination with) an [antibiotic selector function]([ab_class()]), such as [carbapenems()] and [aminoglycosides()] +#' @rdname isolate_identifier #' @export #' @inheritSection AMR Read more on Our Website! #' @examples @@ -43,7 +44,12 @@ isolate_identifier <- function(x, col_mo = NULL, cols_ab = NULL) { if (is.null(col_mo)) { col_mo <- search_type_in_df(x, "mo") + if (is.null(col_mo)) { + # no column found, then ignore the argument + col_mo <- FALSE + } } + if (isFALSE(col_mo)) { # is FALSE then ignore mo column x$col_mo <- "" @@ -60,14 +66,77 @@ isolate_identifier <- function(x, col_mo = NULL, cols_ab = NULL) { # tryCatch adds 4 calls, so total is -5 error = function(e) stop_(e$message, call = -5)) } - if (length(cols_ab) == 0) { - warning_("no columns with antimicrobial agents found", call = TRUE) + + # cope with empty values + if (length(cols_ab) == 0 && all(x[, col_mo, drop = TRUE] == "", na.rm = TRUE)) { + warning_("in isolate_identifier(): no column with microorganisms and no columns with antimicrobial agents found", call = FALSE) + } else if (length(cols_ab) == 0) { + warning_("in isolate_identifier(): no columns with antimicrobial agents found", call = FALSE) } out <- x[, c(col_mo, cols_ab), drop = FALSE] out <- do.call(paste, c(out, sep = "")) out <- gsub("NA", ".", out, fixed = TRUE) - set_clean_class(out, new_class = c("isolate_identifier", "character")) + out <- set_clean_class(out, new_class = c("isolate_identifier", "character")) + attr(out, "ab") <- cols_ab + out +} + +#' @method all.equal isolate_identifier +#' @rdname isolate_identifier +#' @export +all.equal.isolate_identifier <- function(target, current, ignore_empty_results = TRUE, ...) { + if (isTRUE(all.equal.character(target, current))) { + return(TRUE) + } + # vectorise over both target and current + if (length(target) > 1 && length(current) == 1) { + current <- rep(current, length(target)) + } else if (length(current) > 1 && length(target) == 1) { + target <- rep(target, length(current)) + } + stop_if(length(target) != length(current), + "length of `target` and `current` must be the same, or one must be 1") + + get_vector <- function(x) { + if (grepl("|", x, fixed = TRUE)) { + mo <- gsub("(.*)\\|.*", "\\1", x) + } else { + mo <- NULL + } + if (grepl("|", x, fixed = TRUE)) { + ab <- gsub(".*\\|(.*)", "\\1", x) + } else { + ab <- x + } + ab <- strsplit(ab, "")[[1L]] + if (is.null(mo)) { + out <- as.character(ab) + names(out) <- attributes(x)$ab + } else { + out <- as.character(c(mo, ab)) + names(out) <- c("mo", attributes(x)$ab) + } + out + } + + # run it + for (i in seq_len(length(target))) { + if (i == 1) { + df <- data.frame(object = paste0(c("target[", "current["), i, "]")) + } + trgt <- get_vector(target[i]) + crnt <- get_vector(current[i]) + if (ignore_empty_results == TRUE) { + diff <- names(trgt[trgt != crnt & trgt != "." & crnt != "."]) + } else { + diff <- names(trgt[trgt != crnt]) + } + + } + + stop("THIS FUNCTION IS WORK IN PROGRESS AND NOT AVAILABLE IN THIS BETA VERSION") + } #' @method print isolate_identifier diff --git a/R/rsi.R b/R/rsi.R index 47d1a1494..f30b038f4 100755 --- a/R/rsi.R +++ b/R/rsi.R @@ -49,16 +49,16 @@ #' 2. For **interpreting minimum inhibitory concentration (MIC) values** according to EUCAST or CLSI. You must clean your MIC values first using [as.mic()], that also gives your columns the new data class [`mic`]. Also, be sure to have a column with microorganism names or codes. It will be found automatically, but can be set manually using the `mo` argument. #' * Using `dplyr`, R/SI interpretation can be done very easily with either: #' ``` -#' your_data %>% mutate_if(is.mic, as.rsi) # until dplyr 1.0.0 -#' your_data %>% mutate(across(where(is.mic), as.rsi)) # since dplyr 1.0.0 +#' your_data %>% mutate_if(is.mic, as.rsi) # until dplyr 1.0.0 +#' your_data %>% mutate(across((is.mic), as.rsi)) # since dplyr 1.0.0 #' ``` #' * Operators like "<=" will be stripped before interpretation. When using `conserve_capped_values = TRUE`, an MIC value of e.g. ">2" will always return "R", even if the breakpoint according to the chosen guideline is ">=4". This is to prevent that capped values from raw laboratory data would not be treated conservatively. The default behaviour (`conserve_capped_values = FALSE`) considers ">2" to be lower than ">=4" and might in this case return "S" or "I". #' #' 3. For **interpreting disk diffusion diameters** according to EUCAST or CLSI. You must clean your disk zones first using [as.disk()], that also gives your columns the new data class [`disk`]. Also, be sure to have a column with microorganism names or codes. It will be found automatically, but can be set manually using the `mo` argument. #' * Using `dplyr`, R/SI interpretation can be done very easily with either: #' ``` -#' your_data %>% mutate_if(is.disk, as.rsi) # until dplyr 1.0.0 -#' your_data %>% mutate(across(where(is.disk), as.rsi)) # since dplyr 1.0.0 +#' your_data %>% mutate_if(is.disk, as.rsi) # until dplyr 1.0.0 +#' your_data %>% mutate(across((is.disk), as.rsi)) # since dplyr 1.0.0 #' ``` #' #' 4. For **interpreting a complete data set**, with automatic determination of MIC values, disk diffusion diameters, microorganism names or codes, and antimicrobial test results. This is done very simply by running `as.rsi(data)`. @@ -133,7 +133,7 @@ #' if (require("dplyr")) { #' df %>% mutate_if(is.mic, as.rsi) #' df %>% mutate_if(function(x) is.mic(x) | is.disk(x), as.rsi) -#' df %>% mutate(across(where(is.mic), as.rsi)) +#' df %>% mutate(across((is.mic), as.rsi)) #' df %>% mutate_at(vars(AMP:TOB), as.rsi) #' df %>% mutate(across(AMP:TOB, as.rsi)) #' @@ -179,7 +179,7 @@ #' #' # note: from dplyr 1.0.0 on, this will be: #' # example_isolates %>% -#' # mutate(across(where(is.rsi.eligible), as.rsi)) +#' # mutate(across((is.rsi.eligible), as.rsi)) #' } #' } as.rsi <- function(x, ...) { @@ -202,14 +202,19 @@ is.rsi.eligible <- function(x, threshold = 0.05) { "numeric", "integer", "mo", + "ab", "Date", - "POSIXct", + "POSIXt", "rsi", "raw", - "hms") + "hms", + "mic", + "disk") %in% class(x))) { # no transformation needed - FALSE + return(FALSE) + } else if (!any(c("R", "S", "I") %in% x, na.rm = TRUE)) { + return(FALSE) } else { x <- x[!is.na(x) & !is.null(x) & !identical(x, "")] if (length(x) == 0) { diff --git a/R/rsi_calc.R b/R/rsi_calc.R index d9ec0dd88..e55c19499 100755 --- a/R/rsi_calc.R +++ b/R/rsi_calc.R @@ -148,7 +148,9 @@ rsi_calc <- function(..., if (print_warning == TRUE) { if (message_not_thrown_before("rsi_calc")) { - warning_("Increase speed by transforming to class on beforehand: your_data %>% mutate_if(is.rsi.eligible, as.rsi)", + warning_("Increase speed by transforming to class on beforehand:\n", + " your_data %>% mutate_if(is.rsi.eligible, as.rsi)\n", + " your_data %>% mutate(across((is.rsi.eligible), as.rsi))", call = FALSE) remember_thrown_message("rsi_calc") } diff --git a/R/sysdata.rda b/R/sysdata.rda index 9c6d291d9..d3d3c27a8 100644 Binary files a/R/sysdata.rda and b/R/sysdata.rda differ diff --git a/R/zzz.R b/R/zzz.R index 7ed138083..577d377f0 100755 --- a/R/zzz.R +++ b/R/zzz.R @@ -28,35 +28,6 @@ pkg_env <- new.env(hash = FALSE) pkg_env$mo_failed <- character(0) .onLoad <- function(libname, pkgname) { - - assign(x = "AB_lookup", - value = create_AB_lookup(), - envir = asNamespace("AMR")) - - assign(x = "MO_lookup", - value = create_MO_lookup(), - envir = asNamespace("AMR")) - - assign(x = "MO.old_lookup", - value = create_MO.old_lookup(), - envir = asNamespace("AMR")) - - assign(x = "INTRINSIC_R", - value = create_intr_resistance(), - envir = asNamespace("AMR")) - - assign(x = "LANGUAGES_SUPPORTED", - value = sort(c("en", unique(translations_file$lang))), - envir = asNamespace("AMR")) - - assign(x = "MO_CONS", - value = create_species_cons_cops("CoNS"), - envir = asNamespace("AMR")) - - assign(x = "MO_COPS", - value = create_species_cons_cops("CoPS"), - envir = asNamespace("AMR")) - # Support for tibble headers (type_sum) and tibble columns content (pillar_shaft) # without the need to depend on other packages. This was suggested by the # developers of the vctrs package: @@ -102,89 +73,5 @@ pkg_env$mo_failed <- character(0) font_bold("options(AMR_silentstart = TRUE)"), "]")) } -create_intr_resistance <- function() { - # for mo_is_intrinsic_resistant() - saves a lot of time when executed on this vector - paste(AMR::microorganisms[match(AMR::intrinsic_resistant$microorganism, AMR::microorganisms$fullname), "mo", drop = TRUE], - AMR::antibiotics[match(AMR::intrinsic_resistant$antibiotic, AMR::antibiotics$name), "ab", drop = TRUE]) -} -create_species_cons_cops <- function(type = c("CoNS", "CoPS")) { - # Determination of which staphylococcal species are CoNS/CoPS according to: - # - Becker et al. 2014, PMID 25278577 - # - Becker et al. 2019, PMID 30872103 - # - Becker et al. 2020, PMID 32056452 - # this function returns class - MO_staph <- AMR::microorganisms - MO_staph <- MO_staph[which(MO_staph$genus == "Staphylococcus"), , drop = FALSE] - if (type == "CoNS") { - MO_staph[which(MO_staph$species %in% c("coagulase-negative", "argensis", "arlettae", - "auricularis", "caeli", "capitis", "caprae", - "carnosus", "chromogenes", "cohnii", "condimenti", - "debuckii", "devriesei", "edaphicus", "epidermidis", - "equorum", "felis", "fleurettii", "gallinarum", - "haemolyticus", "hominis", "jettensis", "kloosii", - "lentus", "lugdunensis", "massiliensis", "microti", - "muscae", "nepalensis", "pasteuri", "petrasii", - "pettenkoferi", "piscifermentans", "pseudoxylosus", - "rostri", "saccharolyticus", "saprophyticus", - "sciuri", "simulans", "stepanovicii", "succinus", - "vitulinus", "warneri", "xylosus") - | (MO_staph$species == "schleiferi" & MO_staph$subspecies %in% c("schleiferi", ""))), - "mo", drop = TRUE] - } else if (type == "CoPS") { - MO_staph[which(MO_staph$species %in% c("coagulase-positive", - "simiae", "agnetis", - "delphini", "lutrae", - "hyicus", "intermedius", - "pseudintermedius", "pseudointermedius", - "schweitzeri", "argenteus") - | (MO_staph$species == "schleiferi" & MO_staph$subspecies == "coagulans")), - "mo", drop = TRUE] - } -} -create_AB_lookup <- function() { - AB_lookup <- AMR::antibiotics - AB_lookup$generalised_name <- generalise_antibiotic_name(AB_lookup$name) - AB_lookup$generalised_synonyms <- lapply(AB_lookup$synonyms, generalise_antibiotic_name) - AB_lookup$generalised_abbreviations <- lapply(AB_lookup$abbreviations, generalise_antibiotic_name) - AB_lookup$generalised_loinc <- lapply(AB_lookup$loinc, generalise_antibiotic_name) - AB_lookup -} - -create_MO_lookup <- function() { - MO_lookup <- AMR::microorganisms - - MO_lookup$kingdom_index <- NA_real_ - MO_lookup[which(MO_lookup$kingdom == "Bacteria" | MO_lookup$mo == "UNKNOWN"), "kingdom_index"] <- 1 - MO_lookup[which(MO_lookup$kingdom == "Fungi"), "kingdom_index"] <- 2 - MO_lookup[which(MO_lookup$kingdom == "Protozoa"), "kingdom_index"] <- 3 - MO_lookup[which(MO_lookup$kingdom == "Archaea"), "kingdom_index"] <- 4 - # all the rest - MO_lookup[which(is.na(MO_lookup$kingdom_index)), "kingdom_index"] <- 5 - - # use this paste instead of `fullname` to work with Viridans Group Streptococci, etc. - MO_lookup$fullname_lower <- tolower(trimws(paste(MO_lookup$genus, - MO_lookup$species, - MO_lookup$subspecies))) - ind <- MO_lookup$genus == "" | grepl("^[(]unknown ", MO_lookup$fullname) - MO_lookup[ind, "fullname_lower"] <- tolower(MO_lookup[ind, "fullname"]) - MO_lookup$fullname_lower <- trimws(gsub("[^.a-z0-9/ \\-]+", "", MO_lookup$fullname_lower, perl = TRUE)) - - # add a column with only "e coli" like combinations - MO_lookup$g_species <- gsub("^([a-z])[a-z]+ ([a-z]+) ?.*", "\\1 \\2", MO_lookup$fullname_lower, perl = TRUE) - - # so arrange data on prevalence first, then kingdom, then full name - MO_lookup[order(MO_lookup$prevalence, MO_lookup$kingdom_index, MO_lookup$fullname_lower), ] -} - -create_MO.old_lookup <- function() { - MO.old_lookup <- AMR::microorganisms.old - MO.old_lookup$fullname_lower <- trimws(gsub("[^.a-z0-9/ \\-]+", "", tolower(trimws(MO.old_lookup$fullname)))) - - # add a column with only "e coli"-like combinations - MO.old_lookup$g_species <- trimws(gsub("^([a-z])[a-z]+ ([a-z]+) ?.*", "\\1 \\2", MO.old_lookup$fullname_lower)) - - # so arrange data on prevalence first, then full name - MO.old_lookup[order(MO.old_lookup$prevalence, MO.old_lookup$fullname_lower), ] -} diff --git a/cran-comments.md b/cran-comments.md index 823a18bb8..d41772858 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1 +1 @@ -* Since version 0.3.0 (2018-08-14), CHECK returns a NOTE for having a data directory over 3 MB. This is needed to offer users reference data for the complete taxonomy of microorganisms - one of the most important features of this package. +* Ever since one of the first CRAN releases, CHECK returns a NOTE for having a data and R directory over 3 MB. This is needed to offer users reference data for the complete taxonomy of microorganisms - one of the most important features of this package. diff --git a/data-raw/AMR_1.5.0.9007.tar.gz b/data-raw/AMR_1.5.0.9007.tar.gz deleted file mode 100644 index af5e782e5..000000000 Binary files a/data-raw/AMR_1.5.0.9007.tar.gz and /dev/null differ diff --git a/data-raw/AMR_1.5.0.9008.tar.gz b/data-raw/AMR_1.5.0.9008.tar.gz new file mode 100644 index 000000000..231e2b612 Binary files /dev/null and b/data-raw/AMR_1.5.0.9008.tar.gz differ diff --git a/data-raw/internals.R b/data-raw/internals.R index 7f45b666c..10203ebc3 100644 --- a/data-raw/internals.R +++ b/data-raw/internals.R @@ -23,12 +23,108 @@ # how to conduct AMR analysis: https://msberends.github.io/AMR/ # # ==================================================================== # -# Run this file to update the package using: ------------------------------- +# Run this file to update the package using: # source("data-raw/internals.R") -# -------------------------------------------------------------------------- + +library(dplyr, warn.conflicts = FALSE) +devtools::load_all(quiet = TRUE) + +old_globalenv <- ls(envir = globalenv()) + +# Helper functions -------------------------------------------------------- + +create_species_cons_cops <- function(type = c("CoNS", "CoPS")) { + # Determination of which staphylococcal species are CoNS/CoPS according to: + # - Becker et al. 2014, PMID 25278577 + # - Becker et al. 2019, PMID 30872103 + # - Becker et al. 2020, PMID 32056452 + # this function returns class + MO_staph <- AMR::microorganisms + MO_staph <- MO_staph[which(MO_staph$genus == "Staphylococcus"), , drop = FALSE] + if (type == "CoNS") { + MO_staph[which(MO_staph$species %in% c("coagulase-negative", "argensis", "arlettae", + "auricularis", "caeli", "capitis", "caprae", + "carnosus", "chromogenes", "cohnii", "condimenti", + "debuckii", "devriesei", "edaphicus", "epidermidis", + "equorum", "felis", "fleurettii", "gallinarum", + "haemolyticus", "hominis", "jettensis", "kloosii", + "lentus", "lugdunensis", "massiliensis", "microti", + "muscae", "nepalensis", "pasteuri", "petrasii", + "pettenkoferi", "piscifermentans", "pseudoxylosus", + "rostri", "saccharolyticus", "saprophyticus", + "sciuri", "simulans", "stepanovicii", "succinus", + "vitulinus", "warneri", "xylosus") + | (MO_staph$species == "schleiferi" & MO_staph$subspecies %in% c("schleiferi", ""))), + "mo", drop = TRUE] + } else if (type == "CoPS") { + MO_staph[which(MO_staph$species %in% c("coagulase-positive", + "simiae", "agnetis", + "delphini", "lutrae", + "hyicus", "intermedius", + "pseudintermedius", "pseudointermedius", + "schweitzeri", "argenteus") + | (MO_staph$species == "schleiferi" & MO_staph$subspecies == "coagulans")), + "mo", drop = TRUE] + } +} + +create_AB_lookup <- function() { + AB_lookup <- AMR::antibiotics + AB_lookup$generalised_name <- generalise_antibiotic_name(AB_lookup$name) + AB_lookup$generalised_synonyms <- lapply(AB_lookup$synonyms, generalise_antibiotic_name) + AB_lookup$generalised_abbreviations <- lapply(AB_lookup$abbreviations, generalise_antibiotic_name) + AB_lookup$generalised_loinc <- lapply(AB_lookup$loinc, generalise_antibiotic_name) + AB_lookup +} + +create_MO_lookup <- function() { + MO_lookup <- AMR::microorganisms + + MO_lookup$kingdom_index <- NA_real_ + MO_lookup[which(MO_lookup$kingdom == "Bacteria" | MO_lookup$mo == "UNKNOWN"), "kingdom_index"] <- 1 + MO_lookup[which(MO_lookup$kingdom == "Fungi"), "kingdom_index"] <- 2 + MO_lookup[which(MO_lookup$kingdom == "Protozoa"), "kingdom_index"] <- 3 + MO_lookup[which(MO_lookup$kingdom == "Archaea"), "kingdom_index"] <- 4 + # all the rest + MO_lookup[which(is.na(MO_lookup$kingdom_index)), "kingdom_index"] <- 5 + + # use this paste instead of `fullname` to work with Viridans Group Streptococci, etc. + MO_lookup$fullname_lower <- tolower(trimws(paste(MO_lookup$genus, + MO_lookup$species, + MO_lookup$subspecies))) + ind <- MO_lookup$genus == "" | grepl("^[(]unknown ", MO_lookup$fullname) + MO_lookup[ind, "fullname_lower"] <- tolower(MO_lookup[ind, "fullname"]) + MO_lookup$fullname_lower <- trimws(gsub("[^.a-z0-9/ \\-]+", "", MO_lookup$fullname_lower, perl = TRUE)) + + # add a column with only "e coli" like combinations + MO_lookup$g_species <- gsub("^([a-z])[a-z]+ ([a-z]+) ?.*", "\\1 \\2", MO_lookup$fullname_lower, perl = TRUE) + + # so arrange data on prevalence first, then kingdom, then full name + MO_lookup[order(MO_lookup$prevalence, MO_lookup$kingdom_index, MO_lookup$fullname_lower), ] +} + +create_MO.old_lookup <- function() { + MO.old_lookup <- AMR::microorganisms.old + MO.old_lookup$fullname_lower <- trimws(gsub("[^.a-z0-9/ \\-]+", "", tolower(trimws(MO.old_lookup$fullname)))) + + # add a column with only "e coli"-like combinations + MO.old_lookup$g_species <- trimws(gsub("^([a-z])[a-z]+ ([a-z]+) ?.*", "\\1 \\2", MO.old_lookup$fullname_lower)) + + # so arrange data on prevalence first, then full name + MO.old_lookup[order(MO.old_lookup$prevalence, MO.old_lookup$fullname_lower), ] +} + +create_intr_resistance <- function() { + # for mo_is_intrinsic_resistant() - saves a lot of time when executed on this vector + paste(AMR::microorganisms[match(AMR::intrinsic_resistant$microorganism, AMR::microorganisms$fullname), "mo", drop = TRUE], + AMR::antibiotics[match(AMR::intrinsic_resistant$antibiotic, AMR::antibiotics$name), "ab", drop = TRUE]) +} + + + +# Save internal data sets to R/sysdata.rda -------------------------------- # See 'data-raw/eucast_rules.tsv' for the EUCAST reference file -library(dplyr, warn.conflicts = FALSE) eucast_rules_file <- utils::read.delim(file = "data-raw/eucast_rules.tsv", skip = 10, sep = "\t", @@ -48,7 +144,7 @@ eucast_rules_file <- utils::read.delim(file = "data-raw/eucast_rules.tsv", mutate(reference.rule_group = as.character(reference.rule_group)) %>% select(-sorting_rule) -# Translations ---- +# Translations translations_file <- utils::read.delim(file = "data-raw/translations.tsv", sep = "\t", stringsAsFactors = FALSE, @@ -62,23 +158,42 @@ translations_file <- utils::read.delim(file = "data-raw/translations.tsv", allowEscapes = TRUE, # else "\\1" will be imported as "\\\\1" quote = "") -# Old microorganism codes ------------------------------------------------- - +# Old microorganism codes microorganisms.translation <- readRDS("data-raw/microorganisms.translation.rds") +# for mo_is_intrinsic_resistant() - saves a lot of time when executed on this vector +INTRINSIC_R <- create_intr_resistance() + +# for checking input in `language` argument in e.g. mo_*() and ab_*() functions +LANGUAGES_SUPPORTED <- sort(c("en", unique(translations_file$lang))) + +# vectors of CoNS and CoPS, improves speed in as.mo() +MO_CONS <- create_species_cons_cops("CoNS") +MO_COPS <- create_species_cons_cops("CoPS") + +# reference data - they have additional columns compared to `antibiotics` and `microorganisms` to improve speed +AB_lookup <- create_AB_lookup() +MO_lookup <- create_MO_lookup() +MO.old_lookup <- create_MO.old_lookup() + # Export to package as internal data ---- -usethis::use_data(eucast_rules_file, translations_file, microorganisms.translation, +usethis::use_data(eucast_rules_file, + translations_file, + microorganisms.translation, + INTRINSIC_R, + LANGUAGES_SUPPORTED, + MO_CONS, + MO_COPS, + AB_lookup, + MO_lookup, + MO.old_lookup, internal = TRUE, overwrite = TRUE, version = 2, compress = "xz") -# Remove from global environment ---- -rm(eucast_rules_file) -rm(translations_file) -rm(microorganisms.translation) +# Export data sets to the repository in different formats ----------------- -# Save to raw data to repository ---- write_md5 <- function(object) { conn <- file(paste0("data-raw/", deparse(substitute(object)), ".md5")) writeLines(digest::digest(object, "md5"), conn) @@ -93,7 +208,7 @@ changed_md5 <- function(object) { }, error = function(e) TRUE) } usethis::ui_done(paste0("Saving raw data to {usethis::ui_value('/data-raw/')}")) -devtools::load_all(quiet = TRUE) + # give official names to ABs and MOs rsi <- dplyr::mutate(rsi_translation, ab = ab_name(ab), mo = mo_name(mo)) if (changed_md5(rsi)) { @@ -169,5 +284,7 @@ if (changed_md5(dosage)) { try(openxlsx::write.xlsx(dosage, "data-raw/dosage.xlsx"), silent = TRUE) } -rm(write_md5) -rm(changed_md5) +# remove leftovers from global env +current_globalenv <- ls(envir = globalenv()) +rm(list = current_globalenv[!current_globalenv %in% old_globalenv]) +rm(current_globalenv) diff --git a/docs/404.html b/docs/404.html index e4192c1a0..b2626d442 100644 --- a/docs/404.html +++ b/docs/404.html @@ -81,7 +81,7 @@ AMR (for R) - 1.5.0.9007 + 1.5.0.9008 diff --git a/docs/LICENSE-text.html b/docs/LICENSE-text.html index 53200bbbf..aaf1ad728 100644 --- a/docs/LICENSE-text.html +++ b/docs/LICENSE-text.html @@ -81,7 +81,7 @@ AMR (for R) - 1.5.0.9007 + 1.5.0.9008 diff --git a/docs/articles/SPSS.html b/docs/articles/SPSS.html index a802f7639..183b98d88 100644 --- a/docs/articles/SPSS.html +++ b/docs/articles/SPSS.html @@ -39,7 +39,7 @@ AMR (for R) - 1.5.0 + 1.5.0.9008 @@ -193,7 +193,7 @@

How to import data from SPSS / SAS / Stata

Matthijs S. Berends

-

29 December 2020

+

22 January 2021

Source: vignettes/SPSS.Rmd @@ -228,7 +228,7 @@
  • R has a huge community.

    -

    Many R users just ask questions on websites like StackOverflow.com, the largest online community for programmers. At the time of writing, more than 360,000 R-related questions have already been asked on this platform (which covers questions and answers for any programming language). In my own experience, most questions are answered within a couple of minutes.

    +

    Many R users just ask questions on websites like StackOverflow.com, the largest online community for programmers. At the time of writing, 383,346 R-related questions have already been asked on this platform (that covers questions and answers for any programming language). In my own experience, most questions are answered within a couple of minutes.

  • R understands any data type, including SPSS/SAS/Stata.

    @@ -243,7 +243,7 @@
  • R is (nowadays) the preferred analysis software in academic papers.

    At present, R is among the world most powerful statistical languages, and it is generally very popular in science (Bollmann et al., 2017). For all the above reasons, the number of references to R as an analysis method in academic papers is rising continuously and has even surpassed SPSS for academic use (Muenchen, 2014).

    -

    I believe that the thing with SPSS is, that it has always had a great user interface which is very easy to learn and use. Back when they developed it, they had very little competition, let alone from R. R didn’t even had a professional user interface until the last decade (called RStudio, see below). How people used R between the nineties and 2010 is almost completely incomparable to how R is being used now. The language itself has been restyled completely by volunteers who are dedicated professionals in the field of data science. SPSS was great when there was nothing else that could compete. But now in 2020, I don’t see any reason why SPSS would be of any better use than R.

    +

    I believe that the thing with SPSS is, that it has always had a great user interface which is very easy to learn and use. Back when they developed it, they had very little competition, let alone from R. R didn’t even had a professional user interface until the last decade (called RStudio, see below). How people used R between the nineties and 2010 is almost completely incomparable to how R is being used now. The language itself has been restyled completely by volunteers who are dedicated professionals in the field of data science. SPSS was great when there was nothing else that could compete. But now in 2021, I don’t see any reason why SPSS would be of any better use than R.

  • To demonstrate the first point:

    diff --git a/docs/articles/datasets.html b/docs/articles/datasets.html index b1ea78e58..ed3a0aeca 100644 --- a/docs/articles/datasets.html +++ b/docs/articles/datasets.html @@ -39,7 +39,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/articles/index.html b/docs/articles/index.html index cfd9a553d..320157640 100644 --- a/docs/articles/index.html +++ b/docs/articles/index.html @@ -81,7 +81,7 @@ AMR (for R) - 1.5.0.9007 + 1.5.0.9008 diff --git a/docs/authors.html b/docs/authors.html index 63d122fe2..dcc70bfeb 100644 --- a/docs/authors.html +++ b/docs/authors.html @@ -81,7 +81,7 @@ AMR (for R) - 1.5.0.9007 + 1.5.0.9008 diff --git a/docs/extra.css b/docs/extra.css index 8bf2825fc..11c2f0ad8 100644 --- a/docs/extra.css +++ b/docs/extra.css @@ -24,14 +24,6 @@ # how to conduct AMR analysis: https://msberends.github.io/AMR/ # # ==================================================================== # */ -@media (prefers-color-scheme: dark) { - .navbar-default { - background-color: #213730; - } - .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { - background-color: #355951; - } -} /* R for Data Science (r4ds) */ #r4ds a { @@ -209,16 +201,6 @@ thead ~ tbody { /* only when it has a header */ border-bottom: 2px solid black; } -@media (prefers-color-scheme: dark) { - thead { - border-top: 2px solid white; - border-bottom: 2px solid white; - } - thead ~ tbody { - /* only when it has a header */ - border-bottom: 2px solid white; - } -} thead th { text-align: inherit; } diff --git a/docs/index.html b/docs/index.html index bb3dd48a2..ccdaeec5c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -43,7 +43,7 @@ AMR (for R) - 1.5.0.9007 + 1.5.0.9008 diff --git a/docs/news/index.html b/docs/news/index.html index e2bbca0f4..3faabf1c1 100644 --- a/docs/news/index.html +++ b/docs/news/index.html @@ -81,7 +81,7 @@ AMR (for R) - 1.5.0.9007 + 1.5.0.9008 @@ -236,13 +236,13 @@ Source: NEWS.md -
    -

    -AMR 1.5.0.9007 Unreleased +
    +

    +AMR 1.5.0.9008 Unreleased

    -
    +

    -Last updated: 18 January 2021 +Last updated: 22 January 2021

    @@ -285,7 +285,9 @@
  • Added Pretomanid (PMD, J04AK08) to the antibiotics data set
  • WHONET code "PNV" will now correctly be interpreted as PHN, the antibiotic code for phenoxymethylpenicillin (‘peni V’)
  • -
  • Fix for verbose output of mdro(..., verbose = TRUE) for German guideline (3MGRN and 4MGRN) and P. aeruginosa in Dutch guideline (BRMO)
  • +
  • Fix for verbose output of mdro(..., verbose = TRUE) for German guideline (3MGRN and 4MGRN) and Dutch guideline (BRMO, only P. aeruginosa)
  • +
  • +is.rsi.eligible() now returns FALSE immediately if the input does not contain any of the values “R”, “S” or “I”. This drastically improves speed, also for a lot of other functions that rely on automatic determination of antibiotic columns.
  • @@ -293,6 +295,7 @@ Other

    • Big documentation updates
    • +
    • Loading the package (i.e., library(AMR)) now is ~50 times faster than before
    diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml index d2d6b68f2..64b9961d1 100644 --- a/docs/pkgdown.yml +++ b/docs/pkgdown.yml @@ -12,7 +12,7 @@ articles: datasets: datasets.html resistance_predict: resistance_predict.html welcome_to_AMR: welcome_to_AMR.html -last_built: 2021-01-18T17:45Z +last_built: 2021-01-22T08:54Z urls: reference: https://msberends.github.io/AMR//reference article: https://msberends.github.io/AMR//articles diff --git a/docs/reference/AMR-deprecated.html b/docs/reference/AMR-deprecated.html index 569c7830f..fa263efbf 100644 --- a/docs/reference/AMR-deprecated.html +++ b/docs/reference/AMR-deprecated.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/AMR.html b/docs/reference/AMR.html index 6d91eb58e..9a029ce0c 100644 --- a/docs/reference/AMR.html +++ b/docs/reference/AMR.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/WHOCC.html b/docs/reference/WHOCC.html index e156223c3..0e40d2ce0 100644 --- a/docs/reference/WHOCC.html +++ b/docs/reference/WHOCC.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/WHONET.html b/docs/reference/WHONET.html index f5d417c1f..433a7d7dd 100644 --- a/docs/reference/WHONET.html +++ b/docs/reference/WHONET.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/ab_from_text.html b/docs/reference/ab_from_text.html index a32d2fe4c..6af7b67e0 100644 --- a/docs/reference/ab_from_text.html +++ b/docs/reference/ab_from_text.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/ab_property.html b/docs/reference/ab_property.html index 4f23523d8..c5d5fae53 100644 --- a/docs/reference/ab_property.html +++ b/docs/reference/ab_property.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/age.html b/docs/reference/age.html index 663d38f13..509e6b636 100644 --- a/docs/reference/age.html +++ b/docs/reference/age.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/age_groups.html b/docs/reference/age_groups.html index ae38e5f95..f00727b79 100644 --- a/docs/reference/age_groups.html +++ b/docs/reference/age_groups.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/antibiotic_class_selectors.html b/docs/reference/antibiotic_class_selectors.html index 6d97cfa07..954b9a29d 100644 --- a/docs/reference/antibiotic_class_selectors.html +++ b/docs/reference/antibiotic_class_selectors.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/antibiotics.html b/docs/reference/antibiotics.html index fd015a9d9..787ea69df 100644 --- a/docs/reference/antibiotics.html +++ b/docs/reference/antibiotics.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/as.ab.html b/docs/reference/as.ab.html index e719ca428..7612861c3 100644 --- a/docs/reference/as.ab.html +++ b/docs/reference/as.ab.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/as.disk.html b/docs/reference/as.disk.html index 83424f552..bd23f96da 100644 --- a/docs/reference/as.disk.html +++ b/docs/reference/as.disk.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/as.mic.html b/docs/reference/as.mic.html index 6a5a6bc5a..e2165146a 100644 --- a/docs/reference/as.mic.html +++ b/docs/reference/as.mic.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/as.mo.html b/docs/reference/as.mo.html index bea9a702e..f5fe5180d 100644 --- a/docs/reference/as.mo.html +++ b/docs/reference/as.mo.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/as.rsi.html b/docs/reference/as.rsi.html index addeab991..9a87940af 100644 --- a/docs/reference/as.rsi.html +++ b/docs/reference/as.rsi.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 @@ -346,14 +346,14 @@

    The as.rsi() function works in four ways:

    1. For cleaning raw / untransformed data. The data will be cleaned to only contain values S, I and R and will try its best to determine this with some intelligence. For example, mixed values with R/SI interpretations and MIC values such as "<0.25; S" will be coerced to "S". Combined interpretations for multiple test methods (as seen in laboratory records) such as "S; S" will be coerced to "S", but a value like "S; I" will return NA with a warning that the input is unclear.

    2. For interpreting minimum inhibitory concentration (MIC) values according to EUCAST or CLSI. You must clean your MIC values first using as.mic(), that also gives your columns the new data class mic. Also, be sure to have a column with microorganism names or codes. It will be found automatically, but can be set manually using the mo argument.

        -
      • Using dplyr, R/SI interpretation can be done very easily with either:

        your_data %>% mutate_if(is.mic, as.rsi)             # until dplyr 1.0.0
        -your_data %>% mutate(across(where(is.mic), as.rsi)) # since dplyr 1.0.0
        +
      • Using dplyr, R/SI interpretation can be done very easily with either:

        your_data %>% mutate_if(is.mic, as.rsi)         # until dplyr 1.0.0
        +your_data %>% mutate(across((is.mic), as.rsi))  # since dplyr 1.0.0
         
      • Operators like "<=" will be stripped before interpretation. When using conserve_capped_values = TRUE, an MIC value of e.g. ">2" will always return "R", even if the breakpoint according to the chosen guideline is ">=4". This is to prevent that capped values from raw laboratory data would not be treated conservatively. The default behaviour (conserve_capped_values = FALSE) considers ">2" to be lower than ">=4" and might in this case return "S" or "I".

    3. For interpreting disk diffusion diameters according to EUCAST or CLSI. You must clean your disk zones first using as.disk(), that also gives your columns the new data class disk. Also, be sure to have a column with microorganism names or codes. It will be found automatically, but can be set manually using the mo argument.

        -
      • Using dplyr, R/SI interpretation can be done very easily with either:

        your_data %>% mutate_if(is.disk, as.rsi)             # until dplyr 1.0.0
        -your_data %>% mutate(across(where(is.disk), as.rsi)) # since dplyr 1.0.0
        +
      • Using dplyr, R/SI interpretation can be done very easily with either:

        your_data %>% mutate_if(is.disk, as.rsi)         # until dplyr 1.0.0
        +your_data %>% mutate(across((is.disk), as.rsi))  # since dplyr 1.0.0
         
    4. For interpreting a complete data set, with automatic determination of MIC values, disk diffusion diameters, microorganism names or codes, and antimicrobial test results. This is done very simply by running as.rsi(data).

    5. @@ -452,7 +452,7 @@ The lifecycle of this function is stableif (require("dplyr")) { df %>% mutate_if(is.mic, as.rsi) df %>% mutate_if(function(x) is.mic(x) | is.disk(x), as.rsi) - df %>% mutate(across(where(is.mic), as.rsi)) + df %>% mutate(across((is.mic), as.rsi)) df %>% mutate_at(vars(AMP:TOB), as.rsi) df %>% mutate(across(AMP:TOB, as.rsi)) @@ -497,7 +497,7 @@ The lifecycle of this function is stable# note: from dplyr 1.0.0 on, this will be: # example_isolates %>% - # mutate(across(where(is.rsi.eligible), as.rsi)) + # mutate(across((is.rsi.eligible), as.rsi)) } # } diff --git a/docs/reference/atc_online.html b/docs/reference/atc_online.html index bd5f237ba..fae9e5fe3 100644 --- a/docs/reference/atc_online.html +++ b/docs/reference/atc_online.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/availability.html b/docs/reference/availability.html index 4633ad463..6e2f58ce8 100644 --- a/docs/reference/availability.html +++ b/docs/reference/availability.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/bug_drug_combinations.html b/docs/reference/bug_drug_combinations.html index 7ee74544f..8c2ed01a4 100644 --- a/docs/reference/bug_drug_combinations.html +++ b/docs/reference/bug_drug_combinations.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/catalogue_of_life.html b/docs/reference/catalogue_of_life.html index e18babf37..80a338a47 100644 --- a/docs/reference/catalogue_of_life.html +++ b/docs/reference/catalogue_of_life.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/catalogue_of_life_version.html b/docs/reference/catalogue_of_life_version.html index eac244e43..7f271b2ee 100644 --- a/docs/reference/catalogue_of_life_version.html +++ b/docs/reference/catalogue_of_life_version.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/count.html b/docs/reference/count.html index feb89c2f4..da71389b8 100644 --- a/docs/reference/count.html +++ b/docs/reference/count.html @@ -83,7 +83,7 @@ count_resistant() should be used to count resistant isolates, count_susceptible( AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/dosage.html b/docs/reference/dosage.html index abb625f77..78e3e094b 100644 --- a/docs/reference/dosage.html +++ b/docs/reference/dosage.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/eucast_rules.html b/docs/reference/eucast_rules.html index 34753480e..12933c278 100644 --- a/docs/reference/eucast_rules.html +++ b/docs/reference/eucast_rules.html @@ -83,7 +83,7 @@ To improve the interpretation of the antibiogram before EUCAST rules are applied AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/example_isolates.html b/docs/reference/example_isolates.html index 65bd5cfa4..53a51bb23 100644 --- a/docs/reference/example_isolates.html +++ b/docs/reference/example_isolates.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/example_isolates_unclean.html b/docs/reference/example_isolates_unclean.html index 368b6070d..e32d1d966 100644 --- a/docs/reference/example_isolates_unclean.html +++ b/docs/reference/example_isolates_unclean.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/filter_ab_class.html b/docs/reference/filter_ab_class.html index 6e6af35fb..3b2da8ec9 100644 --- a/docs/reference/filter_ab_class.html +++ b/docs/reference/filter_ab_class.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/first_isolate.html b/docs/reference/first_isolate.html index 5e874f1d8..146f35b8e 100644 --- a/docs/reference/first_isolate.html +++ b/docs/reference/first_isolate.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/g.test.html b/docs/reference/g.test.html index 14d48ca5b..3470910b9 100644 --- a/docs/reference/g.test.html +++ b/docs/reference/g.test.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/get_episode.html b/docs/reference/get_episode.html index 6b425466a..9093c38cc 100644 --- a/docs/reference/get_episode.html +++ b/docs/reference/get_episode.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/ggplot_pca.html b/docs/reference/ggplot_pca.html index 0379d1567..03ad375d7 100644 --- a/docs/reference/ggplot_pca.html +++ b/docs/reference/ggplot_pca.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/ggplot_rsi.html b/docs/reference/ggplot_rsi.html index fbef82f1d..8649d827d 100644 --- a/docs/reference/ggplot_rsi.html +++ b/docs/reference/ggplot_rsi.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/guess_ab_col.html b/docs/reference/guess_ab_col.html index ea55ffd12..2db3a2cdb 100644 --- a/docs/reference/guess_ab_col.html +++ b/docs/reference/guess_ab_col.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/index.html b/docs/reference/index.html index ceb53d07a..c6d2adc7c 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -81,7 +81,7 @@ AMR (for R) - 1.5.0.9007 + 1.5.0.9008 @@ -459,7 +459,7 @@ -

      isolate_identifier()

      +

      isolate_identifier() all.equal(<isolate_identifier>)

      Create Identifier of an Isolate

      diff --git a/docs/reference/intrinsic_resistant.html b/docs/reference/intrinsic_resistant.html index bfcf90556..3dbaf40dd 100644 --- a/docs/reference/intrinsic_resistant.html +++ b/docs/reference/intrinsic_resistant.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/isolate_identifier.html b/docs/reference/isolate_identifier.html index 0aaa012a1..21e7fb583 100644 --- a/docs/reference/isolate_identifier.html +++ b/docs/reference/isolate_identifier.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 @@ -242,7 +242,10 @@

      This function will paste the microorganism code with all antimicrobial results into one string for each row in a data set. This is useful to compare isolates, e.g. between institutions or regions, when there is no genotyping available.

      -
      isolate_identifier(x, col_mo = NULL, cols_ab = NULL)
      +
      isolate_identifier(x, col_mo = NULL, cols_ab = NULL)
      +
      +# S3 method for isolate_identifier
      +all.equal(target, current, ignore_empty_results = TRUE, ...)

      Arguments

      @@ -259,14 +262,18 @@ + + + +
      cols_ab

      a character vector of column names of x, or (a combination with) an antibiotic selector function, such as carbapenems() and aminoglycosides()

      ...

      column name of an antibiotic, see section Antibiotics below

      -

      Maturing Lifecycle

      +

      Experimental Lifecycle

      -


      -The lifecycle of this function is maturing. The unlying code of a maturing function has been roughed out, but finer details might still change. Since this function needs wider usage and more extensive testing, you are very welcome to suggest changes at our repository or write us an email (see section 'Contact Us').

      +


      +The lifecycle of this function is experimental. An experimental function is in early stages of development. The unlying code might be changing frequently. Experimental functions might be removed without deprecation, so you are generally best off waiting until a function is more mature before you use it in production code. Experimental functions are only available in development versions of this AMR package and will thus not be included in releases that are submitted to CRAN, since such functions have not yet matured enough.

      Read more on Our Website!

      diff --git a/docs/reference/join.html b/docs/reference/join.html index 4bd46665b..b6da0cad7 100644 --- a/docs/reference/join.html +++ b/docs/reference/join.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/key_antibiotics.html b/docs/reference/key_antibiotics.html index 39945a9ce..21e512d59 100644 --- a/docs/reference/key_antibiotics.html +++ b/docs/reference/key_antibiotics.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/kurtosis.html b/docs/reference/kurtosis.html index 7f841b6df..957c3739d 100644 --- a/docs/reference/kurtosis.html +++ b/docs/reference/kurtosis.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/lifecycle.html b/docs/reference/lifecycle.html index 1682ba1a4..2a6e01e47 100644 --- a/docs/reference/lifecycle.html +++ b/docs/reference/lifecycle.html @@ -84,7 +84,7 @@ This page contains a section for every lifecycle (with text borrowed from the af AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/like.html b/docs/reference/like.html index 08df34844..c8c0afc32 100644 --- a/docs/reference/like.html +++ b/docs/reference/like.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/mdro.html b/docs/reference/mdro.html index c793a3bfe..daccc21f9 100644 --- a/docs/reference/mdro.html +++ b/docs/reference/mdro.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/microorganisms.codes.html b/docs/reference/microorganisms.codes.html index 1932c7ec4..dbf9cc233 100644 --- a/docs/reference/microorganisms.codes.html +++ b/docs/reference/microorganisms.codes.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/microorganisms.html b/docs/reference/microorganisms.html index 04a6aabee..05c2850a5 100644 --- a/docs/reference/microorganisms.html +++ b/docs/reference/microorganisms.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/microorganisms.old.html b/docs/reference/microorganisms.old.html index 7bccad5cd..7946f46d3 100644 --- a/docs/reference/microorganisms.old.html +++ b/docs/reference/microorganisms.old.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/mo_matching_score.html b/docs/reference/mo_matching_score.html index d129ab3c9..187ea1cd1 100644 --- a/docs/reference/mo_matching_score.html +++ b/docs/reference/mo_matching_score.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/mo_property.html b/docs/reference/mo_property.html index 2260754b9..77c4ab8bd 100644 --- a/docs/reference/mo_property.html +++ b/docs/reference/mo_property.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/mo_source.html b/docs/reference/mo_source.html index f9e35b02c..9315bec1c 100644 --- a/docs/reference/mo_source.html +++ b/docs/reference/mo_source.html @@ -83,7 +83,7 @@ This is the fastest way to have your organisation (or analysis) specific codes p AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/pca.html b/docs/reference/pca.html index 354cbeb94..2379e238f 100644 --- a/docs/reference/pca.html +++ b/docs/reference/pca.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/plot.html b/docs/reference/plot.html index 3a5b8e253..0fd878495 100644 --- a/docs/reference/plot.html +++ b/docs/reference/plot.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/proportion.html b/docs/reference/proportion.html index 2c9d9268a..560cc6a25 100644 --- a/docs/reference/proportion.html +++ b/docs/reference/proportion.html @@ -83,7 +83,7 @@ resistance() should be used to calculate resistance, susceptibility() should be AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/random.html b/docs/reference/random.html index 5058efc8f..18d028732 100644 --- a/docs/reference/random.html +++ b/docs/reference/random.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/resistance_predict.html b/docs/reference/resistance_predict.html index ae871da0a..0d5c3d5f8 100644 --- a/docs/reference/resistance_predict.html +++ b/docs/reference/resistance_predict.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/rsi_translation.html b/docs/reference/rsi_translation.html index 8fd79c768..2041954ac 100644 --- a/docs/reference/rsi_translation.html +++ b/docs/reference/rsi_translation.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/skewness.html b/docs/reference/skewness.html index 35a7ee418..175b74fc7 100644 --- a/docs/reference/skewness.html +++ b/docs/reference/skewness.html @@ -83,7 +83,7 @@ When negative ('left-skewed'): the left tail is longer; the mass of the distribu AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/reference/translate.html b/docs/reference/translate.html index 19ddf4e04..72c453f7b 100644 --- a/docs/reference/translate.html +++ b/docs/reference/translate.html @@ -82,7 +82,7 @@ AMR (for R) - 1.5.0.9006 + 1.5.0.9008 diff --git a/docs/survey.html b/docs/survey.html index b1b9d7cc2..9f0370530 100644 --- a/docs/survey.html +++ b/docs/survey.html @@ -81,7 +81,7 @@ AMR (for R) - 1.5.0.9007 + 1.5.0.9008 diff --git a/man/as.rsi.Rd b/man/as.rsi.Rd index 2bf0eabe7..61c247c48 100755 --- a/man/as.rsi.Rd +++ b/man/as.rsi.Rd @@ -87,15 +87,15 @@ The \code{\link[=as.rsi]{as.rsi()}} function works in four ways: \item For \strong{cleaning raw / untransformed data}. The data will be cleaned to only contain values S, I and R and will try its best to determine this with some intelligence. For example, mixed values with R/SI interpretations and MIC values such as \code{"<0.25; S"} will be coerced to \code{"S"}. Combined interpretations for multiple test methods (as seen in laboratory records) such as \code{"S; S"} will be coerced to \code{"S"}, but a value like \code{"S; I"} will return \code{NA} with a warning that the input is unclear. \item For \strong{interpreting minimum inhibitory concentration (MIC) values} according to EUCAST or CLSI. You must clean your MIC values first using \code{\link[=as.mic]{as.mic()}}, that also gives your columns the new data class \code{\link{mic}}. Also, be sure to have a column with microorganism names or codes. It will be found automatically, but can be set manually using the \code{mo} argument. \itemize{ -\item Using \code{dplyr}, R/SI interpretation can be done very easily with either:\preformatted{your_data \%>\% mutate_if(is.mic, as.rsi) # until dplyr 1.0.0 -your_data \%>\% mutate(across(where(is.mic), as.rsi)) # since dplyr 1.0.0 +\item Using \code{dplyr}, R/SI interpretation can be done very easily with either:\preformatted{your_data \%>\% mutate_if(is.mic, as.rsi) # until dplyr 1.0.0 +your_data \%>\% mutate(across((is.mic), as.rsi)) # since dplyr 1.0.0 } \item Operators like "<=" will be stripped before interpretation. When using \code{conserve_capped_values = TRUE}, an MIC value of e.g. ">2" will always return "R", even if the breakpoint according to the chosen guideline is ">=4". This is to prevent that capped values from raw laboratory data would not be treated conservatively. The default behaviour (\code{conserve_capped_values = FALSE}) considers ">2" to be lower than ">=4" and might in this case return "S" or "I". } \item For \strong{interpreting disk diffusion diameters} according to EUCAST or CLSI. You must clean your disk zones first using \code{\link[=as.disk]{as.disk()}}, that also gives your columns the new data class \code{\link{disk}}. Also, be sure to have a column with microorganism names or codes. It will be found automatically, but can be set manually using the \code{mo} argument. \itemize{ -\item Using \code{dplyr}, R/SI interpretation can be done very easily with either:\preformatted{your_data \%>\% mutate_if(is.disk, as.rsi) # until dplyr 1.0.0 -your_data \%>\% mutate(across(where(is.disk), as.rsi)) # since dplyr 1.0.0 +\item Using \code{dplyr}, R/SI interpretation can be done very easily with either:\preformatted{your_data \%>\% mutate_if(is.disk, as.rsi) # until dplyr 1.0.0 +your_data \%>\% mutate(across((is.disk), as.rsi)) # since dplyr 1.0.0 } } \item For \strong{interpreting a complete data set}, with automatic determination of MIC values, disk diffusion diameters, microorganism names or codes, and antimicrobial test results. This is done very simply by running \code{as.rsi(data)}. @@ -193,7 +193,7 @@ as.rsi(x = as.disk(18), if (require("dplyr")) { df \%>\% mutate_if(is.mic, as.rsi) df \%>\% mutate_if(function(x) is.mic(x) | is.disk(x), as.rsi) - df \%>\% mutate(across(where(is.mic), as.rsi)) + df \%>\% mutate(across((is.mic), as.rsi)) df \%>\% mutate_at(vars(AMP:TOB), as.rsi) df \%>\% mutate(across(AMP:TOB, as.rsi)) @@ -238,7 +238,7 @@ if (require("dplyr")) { # note: from dplyr 1.0.0 on, this will be: # example_isolates \%>\% - # mutate(across(where(is.rsi.eligible), as.rsi)) + # mutate(across((is.rsi.eligible), as.rsi)) } } } diff --git a/man/isolate_identifier.Rd b/man/isolate_identifier.Rd index c6d2c3e76..4c95e4873 100644 --- a/man/isolate_identifier.Rd +++ b/man/isolate_identifier.Rd @@ -2,9 +2,12 @@ % Please edit documentation in R/isolate_identifier.R \name{isolate_identifier} \alias{isolate_identifier} +\alias{all.equal.isolate_identifier} \title{Create Identifier of an Isolate} \usage{ isolate_identifier(x, col_mo = NULL, cols_ab = NULL) + +\method{all.equal}{isolate_identifier}(target, current, ignore_empty_results = TRUE, ...) } \arguments{ \item{x}{data with antibiotic columns, such as \code{amox}, \code{AMX} and \code{AMC}} @@ -12,14 +15,16 @@ isolate_identifier(x, col_mo = NULL, cols_ab = NULL) \item{col_mo}{column name of the IDs of the microorganisms (see \code{\link[=as.mo]{as.mo()}}), defaults to the first column of class \code{\link{mo}}. Values will be coerced using \code{\link[=as.mo]{as.mo()}}.} \item{cols_ab}{a character vector of column names of \code{x}, or (a combination with) an \href{[ab_class()]}{antibiotic selector function}, such as \code{\link[=carbapenems]{carbapenems()}} and \code{\link[=aminoglycosides]{aminoglycosides()}}} + +\item{...}{column name of an antibiotic, see section \emph{Antibiotics} below} } \description{ This function will paste the microorganism code with all antimicrobial results into one string for each row in a data set. This is useful to compare isolates, e.g. between institutions or regions, when there is no genotyping available. } -\section{Maturing Lifecycle}{ +\section{Experimental Lifecycle}{ -\if{html}{\figure{lifecycle_maturing.svg}{options: style=margin-bottom:5px} \cr} -The \link[=lifecycle]{lifecycle} of this function is \strong{maturing}. The unlying code of a maturing function has been roughed out, but finer details might still change. Since this function needs wider usage and more extensive testing, you are very welcome \href{https://github.com/msberends/AMR/issues}{to suggest changes at our repository} or \link[=AMR]{write us an email (see section 'Contact Us')}. +\if{html}{\figure{lifecycle_experimental.svg}{options: style=margin-bottom:5px} \cr} +The \link[=lifecycle]{lifecycle} of this function is \strong{experimental}. An experimental function is in early stages of development. The unlying code might be changing frequently. Experimental functions might be removed without deprecation, so you are generally best off waiting until a function is more mature before you use it in production code. Experimental functions are only available in development versions of this \code{AMR} package and will thus not be included in releases that are submitted to CRAN, since such functions have not yet matured enough. } \section{Read more on Our Website!}{ diff --git a/pkgdown/extra.css b/pkgdown/extra.css index 8bf2825fc..11c2f0ad8 100644 --- a/pkgdown/extra.css +++ b/pkgdown/extra.css @@ -24,14 +24,6 @@ # how to conduct AMR analysis: https://msberends.github.io/AMR/ # # ==================================================================== # */ -@media (prefers-color-scheme: dark) { - .navbar-default { - background-color: #213730; - } - .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { - background-color: #355951; - } -} /* R for Data Science (r4ds) */ #r4ds a { @@ -209,16 +201,6 @@ thead ~ tbody { /* only when it has a header */ border-bottom: 2px solid black; } -@media (prefers-color-scheme: dark) { - thead { - border-top: 2px solid white; - border-bottom: 2px solid white; - } - thead ~ tbody { - /* only when it has a header */ - border-bottom: 2px solid white; - } -} thead th { text-align: inherit; } diff --git a/tests/testthat/test-isolate_identifier.R b/tests/testthat/test-isolate_identifier.R new file mode 100644 index 000000000..fd63bcc3b --- /dev/null +++ b/tests/testthat/test-isolate_identifier.R @@ -0,0 +1,44 @@ +# ==================================================================== # +# TITLE # +# Antimicrobial Resistance (AMR) Analysis for R # +# # +# SOURCE # +# https://github.com/msberends/AMR # +# # +# LICENCE # +# (c) 2018-2021 Berends MS, Luz CF et al. # +# Developed at the University of Groningen, the Netherlands, in # +# collaboration with non-profit organisations Certe Medical # +# Diagnostics & Advice, and University Medical Center Groningen. # +# # +# This R package is free software; you can freely use and distribute # +# it for both personal and commercial purposes under the terms of the # +# GNU General Public License version 2.0 (GNU GPL-2), as published by # +# the Free Software Foundation. # +# We created this package for both routine data analysis and academic # +# research and it was publicly released in the hope that it will be # +# useful, but it comes WITHOUT ANY WARRANTY OR LIABILITY. # +# # +# Visit our website for the full manual and a complete tutorial about # +# how to conduct AMR analysis: https://msberends.github.io/AMR/ # +# ==================================================================== # + +context("isolate_identifier.R") + +test_that("isolate_identifier works", { + x <- suppressMessages(isolate_identifier(example_isolates)) + expect_s3_class(x, "isolate_identifier") + expect_s3_class(x, "character") + + expect_equal(suppressMessages( + unique(nchar(isolate_identifier(example_isolates, cols_ab = carbapenems(), col_mo = FALSE)))), + 2) + + expect_warning(isolate_identifier(example_isolates[, 1:3, drop = FALSE])) # without mo and without rsi + expect_warning(isolate_identifier(example_isolates[, 1:9, drop = FALSE])) # only without rsi + + + expect_output(print(x)) + expect_s3_class(unique(c(x, x)), "isolate_identifier") + +}) diff --git a/vignettes/SPSS.Rmd b/vignettes/SPSS.Rmd index 75c8d653e..53eb0cddf 100755 --- a/vignettes/SPSS.Rmd +++ b/vignettes/SPSS.Rmd @@ -49,7 +49,7 @@ As said, SPSS is easier to learn than R. But SPSS, SAS and Stata come with major * **R has a huge community.** - Many R users just ask questions on websites like [StackOverflow.com](https://stackoverflow.com), the largest online community for programmers. At the time of writing, more than [360,000 R-related questions](https://stackoverflow.com/questions/tagged/r?sort=votes) have already been asked on this platform (which covers questions and answers for any programming language). In my own experience, most questions are answered within a couple of minutes. + Many R users just ask questions on websites like [StackOverflow.com](https://stackoverflow.com), the largest online community for programmers. At the time of writing, [`r format(suppressWarnings(readr::read_csv("https://data.stackexchange.com/stackoverflow/csv/1674647", col_types = "d")[[1]]), big.mark = ",")` R-related questions](https://stackoverflow.com/questions/tagged/r?sort=votes) have already been asked on this platform (that covers questions and answers for any programming language). In my own experience, most questions are answered within a couple of minutes. * **R understands any data type, including SPSS/SAS/Stata.**