diff --git a/.Rbuildignore b/.Rbuildignore index 5e7d5da9..e6ae83e1 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -8,3 +8,14 @@ ^\.github$ ^cran-comments\.md$ ^CODE_OF_CONDUCT.md$ +^README\.Rmd$ +^README.html$ +^data-raw$ +^vignettes/articles$ +^CODE_OF_CONDUCT.md$ +sees_dmcmc_09.30.2021.rds$ +SEES_2022-10-24_redacted_2023-10-12.csv$ +allpopsamples_hlye.csv$ +^serocalculator\.Rcheck$ +^serocalculator.*\.tar\.gz$ +^serocalculator.*\.tgz$ diff --git a/.gitignore b/.gitignore index 814b4f18..0c6c65bd 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ docs src-i386 src-x64 ..Rcheck +serocalculator.Rcheck/ +serocalculator*.tar.gz +serocalculator*.tgz diff --git a/DESCRIPTION b/DESCRIPTION index dd5aed41..d270d91b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -8,32 +8,40 @@ Authors@R: c( person(given = "Kristina", family = "Lai", role = c("aut")), person(given = "Kristen", family = "Aiemjoy", email = "kaiemjoy@ucdavis.edu", role = c("aut")), person(given = "Douglas Ezra", family = "Morrison", email = "demorrison@ucdavis.edu", role = c("aut", "cre"))) -Description: Translates antibody levels measured in a cross-sectional population - sample into an estimate of the frequency with which seroconversions (infections) - occur in the sampled population. Forked from the "seroincidence" package v2.0.0 on CRAN. -Depends: R (>= 2.10) +Description: Translates antibody levels measured in cross-sectional population + samples into estimates of the frequency with which seroconversions (infections) + occur in the sampled populations. Replaces the previous `seroincidence` package. +Depends: R (>= 3.5.0) License: GPL-3 Imports: - bookdown, dplyr, + magrittr, + parallel, Rcpp, + rlang, stats, + tibble, + tidyr, utils Suggests: knitr, rmarkdown, - parallel, pander, Hmisc, tidyverse, - fs + fs, + testthat (>= 3.0.0), + readr, + ggplot2, + bookdown VignetteBuilder: knitr LazyData: true Encoding: UTF-8 URL: https://github.com/UCD-SERG/serocalculator, https://ucd-serg.github.io/serocalculator/ -RoxygenNote: 7.2.3 +RoxygenNote: 7.2.3.9000 NeedsCompilation: no LinkingTo: Rcpp Language: en-US Roxygen: list(markdown = TRUE) +Config/testthat/edition: 3 diff --git a/MD5 b/MD5 index c0b69f86..252d1766 100644 --- a/MD5 +++ b/MD5 @@ -4,7 +4,7 @@ ce096f7d73a14d083004dc4cd4827088 *NEWS 2f0d05fa159c0cbaf611b95b9fb8198c *R/data-help.R a1522b6b5522ee3108f4c18369b9cd4d *R/deltaFunc.R 2459fe699d9f2dee2d4096a8459a69c3 *R/densFunc.R -59400925562a9721e63e7991ff154bcb *R/estimateSeroincidence.R +59400925562a9721e63e7991ff154bcb *R/est.incidence.by.R 97fa0b804650de611a334024916baaca *R/getAdditionalData.R f0d9baae9d10e02db385f555555931fe *R/nll.R 3ef0eb791a21c2221dafe07457466876 *R/nllByType.R @@ -38,7 +38,7 @@ a23cfd5e4e5e88a96e2774853f48aa65 *man/campylobacterDelftParams4.Rd e6415e1ea335b82a24cc3ef9aa5478bc *man/campylobacterSSIParams2.Rd 4d2797bc3c01ab24effb7a6900ae879a *man/campylobacterSSIParams4.Rd f35091d97beb8e70dd2fa2f655c4321b *man/campylobacterSimLowData.Rd -c0e69fa2dec067fa5db26cdaeab47998 *man/estimateSeroincidence.Rd +c0e69fa2dec067fa5db26cdaeab47998 *man/est.incidence.by.Rd a351cb2497a6e921c2eced22d0d95c1a *man/getAdditionalData.Rd 01c20490f1e8ed5ec32473649160c8ad *man/pertussisIgGPTParams1.Rd 02a459fb98436acfdfb292a74947c09c *man/pertussisIgGPTParams2.Rd diff --git a/NAMESPACE b/NAMESPACE index 0e5fbc0b..ff2b43bd 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,17 +1,48 @@ # Generated by roxygen2: do not edit by hand -S3method(print,seroincidence) -S3method(print,summary.seroincidence) -S3method(summary,seroincidence) -export(estimateSeroincidence) +S3method(print,seroincidence.ests) +S3method(print,summary.seroincidence.ests) +S3method(summary,seroincidence.ests) +export(.optNll) +export(est.incidence) +export(est.incidence.by) export(fdev) export(getAdditionalData) +export(postprocess_fit) importFrom(Rcpp,sourceCpp) +importFrom(dplyr,across) +importFrom(dplyr,all_of) +importFrom(dplyr,anti_join) +importFrom(dplyr,any_of) +importFrom(dplyr,bind_rows) +importFrom(dplyr,distinct) +importFrom(dplyr,everything) +importFrom(dplyr,filter) +importFrom(dplyr,inner_join) importFrom(dplyr,mutate) +importFrom(dplyr,pull) +importFrom(dplyr,relocate) +importFrom(dplyr,rename) +importFrom(dplyr,row_number) +importFrom(dplyr,select) +importFrom(dplyr,semi_join) +importFrom(dplyr,tibble) +importFrom(magrittr,"%>%") +importFrom(parallel,clusterEvalQ) +importFrom(parallel,clusterExport) +importFrom(parallel,parLapplyLB) +importFrom(rlang,.data) +importFrom(rlang,.env) importFrom(stats,dlnorm) +importFrom(stats,nlm) importFrom(stats,optim) importFrom(stats,pgamma) importFrom(stats,plnorm) +importFrom(stats,qnorm) +importFrom(tibble,as_tibble) +importFrom(tibble,column_to_rownames) +importFrom(tibble,tibble) +importFrom(tidyr,drop_na) importFrom(utils,download.file) importFrom(utils,unzip) useDynLib(serocalculator, .registration = TRUE) diff --git a/R/build_likelihood_function.R b/R/build_likelihood_function.R new file mode 100644 index 00000000..00cd6f7c --- /dev/null +++ b/R/build_likelihood_function.R @@ -0,0 +1,29 @@ +build_likelihood_function = function( + cross_sectional_data, + longitudinal_parameter_samples, + noise_params, + antigen_isos = names(cross_sectional_data)) +{ + + likelihood_function = function(llam) + { + + res = 0 + + # add terms, e.g. for other antibodies + for (cur_antigen in antigen_isos) + { + res = res + + fdev( + llam, + cross_sectional_data[[cur_antigen]], + longitudinal_parameter_samples[[cur_antigen]], + noise_params[[cur_antigen]]) + } + + return(res) + + } + + return(likelihood_function) +} diff --git a/R/est.incidence.R b/R/est.incidence.R new file mode 100644 index 00000000..7df960de --- /dev/null +++ b/R/est.incidence.R @@ -0,0 +1,121 @@ + +# +#' Age specific seroincidence function +#' add some details here +#' +#' @param dpop cross-sectional population data +#' @param c.age age category +#' @param start starting value for incidence rate +#' @param antigen_isos antigen-isotype(s) (a [character()] vector of one or more antigen names) +#' @param noise_params a [data.frame()] containing columns `nu`, etc. specifying conditional noise parameters +#' @param iterlim a positive integer specifying the maximum number of iterations to be performed before the program is terminated. +#' @param dmcmc mcmc samples from distribution of longitudinal decay curve parameters +#' @param verbose logical: if TRUE, print verbose log information to console +#' @inheritParams postprocess_fit +#' @inheritDotParams stats::nlm -f -p -hessian -iterlim +#' +#' @return A [data.frame()] containing the following: +#' * `est.start`: the starting guess for incidence rate +#' * `ageCat`: the age category we are analyzing +#' * `incidence.rate`: the estimated incidence rate, per person year +#' * `CI.lwr`: lower limit of confidence interval for incidence rate +#' * `CI.upr`: upper limit of confidence interval for incidence rate +#' * `coverage`: coverage probability +#' * `neg.llik`: negative log-likelihood +#' * `iterations`: the number of iterations used +#' +#' @export + +est.incidence <- function( + dpop, + dmcmc, + noise_params, + c.age = NULL, + antigen_isos = dpop$antigen_iso |> unique(), + start = 0.1, + iterlim = 100, + coverage = .95, + verbose = FALSE, + ...) +{ + + lambda = start # initial estimate: starting value + log.lambda = log(lambda) + + if(!is.null(c.age)) + { + dpop = dpop %>% dplyr::filter(.data[["ageCat"]] == c.age) + dmcmc = dmcmc %>% dplyr::filter(.data[["ageCat"]] == c.age) + + if("ageCat" %in% names(noise_params)) + { + noise_params = + noise_params %>% + dplyr::filter(.data[["ageCat"]] == c.age) + } + } + + ps = list() + cs = list() + conds = list() + + for (cur_antigen in antigen_isos) + { + ps[[cur_antigen]] = get_xspd_one_antigen( + dpop = dpop, + antigen = cur_antigen) + + cs[[cur_antigen]] = get_curve_params_one_antigen( + params = dmcmc, + antigen = cur_antigen) + + conds[[cur_antigen]] = + noise_params %>% + dplyr::filter(.data[["antigen_iso"]] == cur_antigen) + + } + + # noise parameters + # cond.hlye.IgG + + objfunc = build_likelihood_function( + cross_sectional_data = ps, + longitudinal_parameter_samples = cs, + noise_params = conds) + + # seroincidence estimation + { + fit = nlm( + f = objfunc, + p = log.lambda, + hessian = TRUE, + iterlim = iterlim, + ...) + } |> system.time() -> time + + if(verbose) + { + message('elapsed time: ') + print(time) + } + + if(fit$iterations >= iterlim) + { + warning( + "Maximum `nlm()` iterations reached; consider increasing `iterlim` argument.") + } + + log.lambda.est = + fit |> + postprocess_fit( + coverage = coverage, + start = start + ) |> + mutate( + ageCat = c.age, + antigen.iso = antigen_isos |> paste(collapse = "+")) %>% + structure( + noise.parameters = noise_params) + + return(log.lambda.est) +} diff --git a/R/est.incidence.by.R b/R/est.incidence.by.R new file mode 100644 index 00000000..d10d6bec --- /dev/null +++ b/R/est.incidence.by.R @@ -0,0 +1,145 @@ +#' Estimate Seroincidence +#' +#' Function to estimate seroincidences based on cross-section serology data and longitudinal +#' response model. +#' +#' @param data Data frame with cross-sectional serology data per antibody and age, and additional columns to identify possible `strata`. +#' @param strata Character vector of stratum-defining variables. Values must be variable names in `data`. Default = "". +#' @param curve_strata_varnames A subset of `strata`. Values must be variable names in `curve_params`. Default = "". +#' @param noise_strata_varnames A subset of `strata`. Values must be variable names in `noise_params`. Default = "". +#' @param numCores Number of processor cores to use for calculations when computing by strata. If set to more than 1 and package \pkg{parallel} is available, then the computations are executed in parallel. Default = 1L. + +#' @inheritParams .optNll +#' @inheritDotParams .optNll +#' +#' @return A set of lambda estimates for each strata. +#' +#' +#' @export +est.incidence.by <- function( + data, + curve_params, + noise_params, + strata = "", + curve_strata_varnames = strata, + noise_strata_varnames = strata, + numCores = 1L, + antigen_isos = data |> pull("antigen_iso") |> unique(), + verbose = FALSE, + ...) +{ + + .errorCheck( + data = data, + antibodies = antigen_isos, + strata = strata, + params = curve_params) + + curve_params = + curve_params |> + dplyr::filter(.data$antigen_iso %in% antigen_isos) |> + mutate( + alpha = .data$alpha * 365.25, + d = .data$r - 1) + + noise_params = + noise_params |> + dplyr::filter(.data$antigen_iso %in% antigen_isos) + # %>% + # select(y1, alpha, d, antigen_iso, any_of(strata)) + + # Split data per stratum + stratumDataList <- prep_data( + data = data, + antibodies = antigen_isos, + curve_params = curve_params, + noise_params = noise_params, + strata_varnames = strata, + curve_strata_varnames = curve_strata_varnames, + noise_strata_varnames = noise_strata_varnames) + + if(verbose) message("Data has been stratified.") + + # Loop over data per stratum + if (numCores > 1L && requireNamespace("parallel", quietly = TRUE)) { + + if(verbose) message("Setting up parallel processing.") + + libPaths <- .libPaths() + cl <- + numCores |> + min(parallel::detectCores() - 1) |> + parallel::makeCluster() + on.exit({ + parallel::stopCluster(cl) + }) + + parallel::clusterExport(cl, c("libPaths"), envir = environment()) + parallel::clusterEvalQ(cl, { + .libPaths(libPaths) + require(serocalculator) # note - this gets out of sync when using load_all() in development + require(dplyr) + + }) + + { + fits <- parallel::parLapplyLB( + cl = cl, + X = stratumDataList, + fun = function(x) + .optNll( + dataList = x, + ...) + ) + } |> system.time() -> time + + if(verbose) + { + message("Elapsed time for parallelized code: ") + print(time) + } + } else + { + # fits <- lapply( + # X = stratumDataList, + # FUN = function(x) .optNll(dataList = x, verbose = verbose, ...)) + + fits = list() + + { + + for (cur_stratum in names(stratumDataList)) + { + if(verbose) + { + message('starting new stratum: ', cur_stratum) + stratumDataList |> + attr("strata") |> + dplyr::filter(.data$Stratum == cur_stratum) |> + print() + } + + fits[[cur_stratum]] = + .optNll( + dataList = stratumDataList[[cur_stratum]], + verbose = verbose, + ...) + + } + } |> system.time() -> time + + if(verbose) + { + message("Elapsed time for loop over strata: ") + print(time) + } + } + + incidenceData <- structure( + fits, + Antibodies = antigen_isos, + Strata = stratumDataList |> attr("strata"), + class = "seroincidence.ests" |> union(class(fits))) + + return(incidenceData) +} diff --git a/R/estimateSeroincidence.R b/R/estimateSeroincidence.R deleted file mode 100644 index 1ccfc5de..00000000 --- a/R/estimateSeroincidence.R +++ /dev/null @@ -1,119 +0,0 @@ -#' Estimate Seroincidence -#' -#' Function to estimate seroincidences based on cross-section serology data and longitudinal -#' response model. -#' -#' @param data Data frame with cross-sectional serology data per antibody and age, and additional -#' columns to identify possible `strata`. -#' @param antibodies Character vector with one or more antibody names. Values must match `data`. -#' @param strata Character vector of strata. Values must match with `data`. Default = "". -#' @param params List of data frames of all longitudinal parameters. Each data frame contains -#' Monte Carlo samples for each antibody type. -#' @param censorLimits List of cutoffs for one or more named antibody types (corresponding to -#' `data`). -#' @param par0 List of parameters for the (lognormal) distribution of antibody concentrations -#' for true seronegatives (i.e. those who never seroconverted), by named antibody type -#' (corresponding to `data`). -#' @param start A starting value for `log(lambda)`. Value of -6 corresponds roughly to 1 day -#' (log(1/365.25)), -4 corresponds roughly to 1 week (log(7 / 365.25)). Default = -6. -#' @param numCores Number of processor cores to use for calculations when computing by strata. If -#' set to more than 1 and package \pkg{parallel} is available, then the computations are -#' executed in parallel. Default = 1L. -#' -#' @return -#' A set of lambda estimates for each strata. -#' -#' @examples -#' -#' \dontrun{ -#' estimateSeroincidence(data = csData, -#' antibodies = c("IgG", "IgM", "IgA"), -#' strata = "", -#' params = campylobacterDelftParams4, -#' censorLimits = cutOffs, -#' par0 = baseLn, -#' start = -4) -#' -#' estimateSeroincidence(data = csData, -#' antibodies = c("IgG", "IgM", "IgA"), -#' strata = "", -#' params = campylobacterDelftParams4, -#' censorLimits = cutOffs, -#' par0 = baseLn, -#' start = -4, -#' numCores = parallel::detectCores()) -#' } -#' -#' @export -estimateSeroincidence <- function( - data, - antibodies, - strata = "", - params, - censorLimits, - par0, - start = -6, - numCores = 1L) -{ - if (!"Age" %in% names(data)) { - data$Age <- rep(NA, nrow(data)) - } - - .errorCheck(data = data, - antibodies = antibodies, - strata = strata, - params = params) - - antibodiesData <- .prepData(data = data, - antibodies = antibodies, - strata = strata) - - ivc <- antibodiesData$Ivc - - # Split data per stratum - stratumDataList <- split(antibodiesData$Data, - antibodiesData$Data$Stratum) - - # Loop over data per stratum - if (numCores > 1L && requireNamespace("parallel", quietly = TRUE)) { - libPaths <- .libPaths() - cl <- parallel::makeCluster(min(numCores, parallel::detectCores())) - on.exit({ - parallel::stopCluster(cl) - }) - - parallel::clusterExport(cl, c("libPaths"), envir = environment()) - parallel::clusterEvalQ(cl, { - .libPaths(libPaths) - library(seroincidence) - }) - fits <- parallel::parLapplyLB(cl, - stratumDataList, - .optNll, - antibodies = antibodies, - params = params, - censorLimits = censorLimits, - ivc = ivc, - m = 0, - par0 = par0, - start = start) - } else { - fits <- lapply(stratumDataList, - .optNll, - antibodies = antibodies, - params = params, - censorLimits = censorLimits, - ivc = ivc, - m = 0, - par0 = par0, - start = start) - } - - incidenceData <- list(Fits = fits, - Antibodies = antibodies, - Strata = strata, - CensorLimits = censorLimits) - class(incidenceData) <- c("seroincidence", "list") - - return(incidenceData) -} diff --git a/R/get_curve_params_one_antigen.R b/R/get_curve_params_one_antigen.R new file mode 100644 index 00000000..75412d05 --- /dev/null +++ b/R/get_curve_params_one_antigen.R @@ -0,0 +1,9 @@ +get_curve_params_one_antigen = function(params, antigen) +{ + params %>% + dplyr::filter(.data[["antigen_iso"]] == .env[["antigen"]]) %>% + mutate( + alpha = .data[["alpha"]] * 365.25, + d = .data[["r"]] - 1) %>% + select("y1", "alpha", "d") +} diff --git a/R/get_strata.R b/R/get_strata.R new file mode 100644 index 00000000..acaed9ba --- /dev/null +++ b/R/get_strata.R @@ -0,0 +1,8 @@ +get_strata = function(data, strata_varnames) +{ + to_return = + data |> + distinct(across(any_of(strata_varnames))) |> + mutate(Stratum = paste("Stratum", row_number())) + +} diff --git a/R/get_xspd_one_antigen.R b/R/get_xspd_one_antigen.R new file mode 100644 index 00000000..cf334c70 --- /dev/null +++ b/R/get_xspd_one_antigen.R @@ -0,0 +1,9 @@ +get_xspd_one_antigen = function(dpop, antigen) +{ + + dpop %>% + dplyr::filter(.data$antigen_iso %in% .env$antigen) %>% + select("y", "a") %>% + drop_na() + +} diff --git a/R/makeStrata.R b/R/makeStrata.R new file mode 100644 index 00000000..8f3bdedb --- /dev/null +++ b/R/makeStrata.R @@ -0,0 +1,18 @@ +.makeStrata <- function(data, strata = "") +{ + dataStrata <- data + + if (all(strata != "")) + { + if(all(strata %in% names(data))) + { + dataStrata$Stratum <- interaction(dataStrata[, strata]) + } else + { + return(dataStrata) # no stratum variable + } + } else { + dataStrata$Stratum <- factor("all data") + } + return(dataStrata) +} diff --git a/R/nll.R b/R/nll.R index c98a2f31..7b6df142 100644 --- a/R/nll.R +++ b/R/nll.R @@ -1,60 +1,46 @@ #' Calculate log-likelihood #' -#' @param stratumData Data frame with cross-sectional serology data per antibody and age, and additional -#' columns, for one stratum -#' @param antibodies Character vector with one or more antibody names. Values must match `data`. -#' @param params List of data frames of all longitudinal parameters. Each data frame contains +#' @param data Data frame with cross-sectional serology data per antibody and age, and additional columns +#' @param antigen_isos Character vector with one or more antibody names. Values must match `data`. +#' @param curve_params List of data frames of all longitudinal parameters. Each data frame contains #' Monte Carlo samples for each antibody type. -#' @param censorLimits List of cutoffs for one or more named antibody types (corresponding to -#' `stratumData`). -#' @param ivc If `ivc = TRUE`, the biomarker data are interval-censored. -#' @param m this parameter's meaning is uncertain -#' @param par0 List of parameters for the (lognormal) distribution of antibody concentrations -#' for true seronegatives (i.e. those who never seroconverted), by named antibody type -#' (corresponding to `data`). -#' @param start starting value for `log(lambda)`. Value of -6 corresponds roughly to 1 day -#' (log(1/365.25)), -4 corresponds roughly to 1 week (log(7 / 365.25)). Default = -6. -#' +#' @param noise_params a [list()] (or [data.frame()], or [tibble()]) containing noise parameters +#' @param verbose logical: if TRUE, print verbose log information to console +#' @param ... additional arguments passed to other functions (not currently used). +#' @inheritParams fdev + #' @return the log-likelihood of the data with the current parameter values -.nll <- function(stratumData, antibodies, params, censorLimits, ivc = FALSE, m = 0, par0, start) +.nll <- function( + log.lambda, + data, + antigen_isos, + curve_params, + noise_params, + verbose = FALSE, + ...) { # Start with zero total nllTotal <- 0 - if (ivc) { - # Loop over antibodies - for (abIdx in seq_along(antibodies)) { - antibody <- .stripNames(antibodies[abIdx]) - param <- params[[antibody]] - p0 <- par0[[antibody]] - modelType <- .selectModel(param) - data <- cbind(stratumData[[antibodies[abIdx]]], - stratumData[[antibodies[abIdx + 1]]], - stratumData$Age) + # Loop over antibodies + for (cur_antibody in antigen_isos) + { + cur_data = data[[cur_antibody]] + cur_curve_params = curve_params[[cur_antibody]] + cur_noise_params = noise_params[[cur_antibody]] - nllSingle <- .nllByType(data = data, param = param, censorLimit = NULL, ivc = ivc, m = m, - par0 = p0, start = start, modelType = modelType) - if (!is.na(nllSingle)) { - nllTotal <- nllTotal + nllSingle - } - } - } else { - # Loop over antibodies - for (abIdx in seq_along(antibodies)) { - antibody <- .stripNames(antibodies[abIdx]) - param <- params[[antibody]] - p0 <- par0[[antibody]] - censorLimit <- censorLimits[[antibody]] - modelType <- .selectModel(param) + nllSingle <- + fdev( + log.lambda = log.lambda, + csdata = cur_data, + lnpars = cur_curve_params, + cond = cur_noise_params + ) - data <- cbind(stratumData[[antibodies[abIdx]]], - stratumData$Age) - nllSingle <- .nllByType(data = data, param = param, censorLimit = censorLimit, ivc = ivc, - m = m, par0 = p0, start = start, modelType = modelType) - if (!is.na(nllSingle)) { - nllTotal <- nllTotal + nllSingle # DEM note: summing log likelihoods represents an independence assumption for multiple Antibodies, given time since seroconversion - } + if (!is.na(nllSingle)) { + nllTotal <- nllTotal + nllSingle # DEM note: summing log likelihoods represents an independence assumption for multiple Antibodies, given time since seroconversion } + } # Return total log-likelihood diff --git a/R/nllByType.R b/R/nllByType.R deleted file mode 100644 index 334526e3..00000000 --- a/R/nllByType.R +++ /dev/null @@ -1,56 +0,0 @@ -.nllByType <- function(data, param, censorLimit, ivc = FALSE, m = 0, par0, start, modelType) -{ - lambda <- exp(start) - pdfModel <- switch(modelType, - "1" = .rhoPdf1, - "2" = .rhoPdf2, - "3" = .rhoPdf3, - "4" = .rhoPdf4, - "5" = .rhoPdf5) - cdfModel <- switch(modelType, - "1" = .rhoCdf1, - "2" = .rhoCdf2, - "3" = .rhoCdf3, - "4" = .rhoCdf4, - "5" = .rhoCdf5) - - if (ivc) { - # data must have .hi and .lo observations - rho <- apply(X = data, MARGIN = 1, FUN = .deltaFunc, - lambda = lambda, m = m, param = param, fun = cdfModel, par0 = par0) - # Remove empty outcomes - rho <- rho[rho != 0] - return(-sum(log(rho))) - } - - # Deal with uncensored data - dataUncens <- data[data[, 1] > censorLimit, ] - if (length(dataUncens) == 2) { - dataUncens <- as.matrix(t(dataUncens)) - } - rho <- numeric(0) - if (length(dataUncens) > 0) { - rhoUc <- apply(X = dataUncens, MARGIN = 1, FUN = .densFunc, - lambda = lambda, m = m, param = param, fun = pdfModel, par0 = par0) - rho <- c(rho, rhoUc) - } - - # Deal with censored data - dataCens <- data[data[, 1] <= censorLimit, ] - if (length(dataCens) == 2) { - dataCens[1] <- censorLimit - dataCens <- as.matrix(t(dataCens)) - } - if (length(dataCens) > 2) { - dataCens[, 1] <- censorLimit - } - if (length(dataCens) > 0) { - rhoCn <- apply(X = dataCens, MARGIN = 1, FUN = .densFunc, - lambda = lambda, m = m, param = param, fun = cdfModel, par0 = par0) - rho <- c(rho, rhoCn) - } - - # Remove empty outcomes - rho <- rho[!is.na(rho) & rho != 0] - return(-sum(log(rho))) -} diff --git a/R/.onUnload.R b/R/onUnload.R similarity index 100% rename from R/.onUnload.R rename to R/onUnload.R diff --git a/R/optNll.R b/R/optNll.R index af0aa0ff..721cc53d 100644 --- a/R/optNll.R +++ b/R/optNll.R @@ -1,21 +1,95 @@ -.optNll <- function(stratumData, antibodies, params, censorLimits, ivc = FALSE, m, par0, start) +# .optNll = function(x,...) x[[1]] |> filter(antigen_iso == "HlyE_IgA") |> head() + + +#' Find the maximum likelihood estimate of the incidence rate parameter +#' +#' @param lambda.start starting guess for incidence rate, in years/event. +#' @param antigen_isos Character vector with one or more antibody names. Values must match `data` +#' @param dataList Optional argument; as an alternative to passing in `data`, `curve_params`, and `noise_params` individually, you may create a list containing these three elements (with these names) and pass that in instead. This option may be useful for parallel processing across strata. +#' @inheritParams .nll +#' @inheritParams stats::nlm +#' @inheritDotParams .nll +#' @inheritDotParams stats::nlm + +#' @returns a [stats::nlm()] fit object +#' @export +.optNll <- function( + data = dataList$data, + curve_params = dataList$curve_params, + noise_params = dataList$noise_params, + dataList = NULL, + antigen_isos = data |> pull("antigen_iso") |> unique(), + lambda.start = 1/365.25, + hessian = TRUE, + # stepmax = 1, + verbose = FALSE, + ...) { - # Any column but "Stratum" incidence can not be calculated if there are zero observations. - if (nrow(stratumData) == 0) { - return(NULL) + + # incidence can not be calculated if there are zero observations. + if (nrow(data) == 0) { + stop("No data provided.") + } + + if(verbose) + { + message("nrow(curve_params) = ", nrow(curve_params)) } + if(nrow(noise_params) != length(antigen_isos)) + stop("too many rows of noise parameters.") + + data = data |> split(~antigen_iso) + curve_params = curve_params |> split(~antigen_iso) + noise_params = noise_params |> split(~antigen_iso) + # First, check if we find numeric results... - res <- .nll(stratumData, antibodies, params, censorLimits, ivc, m, par0, start) + res <- .nll( + data = data, + log.lambda = log(lambda.start), + antigen_isos = antigen_isos, + curve_params = curve_params, + noise_params = noise_params, + verbose = verbose, + ...) + if (is.na(res)) { + warning("Could not calculate the log-likelihood with starting parameter value.") return(NULL) } + if(verbose) + { + message("Initial log-likelihood: ", res) + } + # Estimate log.lambda - fit <- stats::optim(par = start, fn = .nll, - stratumData = stratumData, antibodies = antibodies, params = params, - censorLimits = censorLimits, ivc = ivc, m = 0, par0 = par0, - method = "L-BFGS-B", lower = -13, upper = 0, hessian = TRUE, - control = list(fnscale = 1)) + time = + { + fit = nlm( + f = .nll, + p = log(lambda.start), + data = data, + antigen_isos = antigen_isos, + curve_params = curve_params, + noise_params = noise_params, + hessian = hessian, + # stepmax = stepmax, + verbose = verbose, + ...) + } |> + system.time() + + if(verbose) + { + message('elapsed time: ') + print(time) + } + + fit = fit |> + structure( + class = "seroincidence.est" |> union(class(fit)), + lambda.start = lambda.start) + return(fit) } diff --git a/R/postprocess_fit.R b/R/postprocess_fit.R new file mode 100644 index 00000000..21aa1a94 --- /dev/null +++ b/R/postprocess_fit.R @@ -0,0 +1,37 @@ + +#' postprocess a fitted incidence model +#' +#' @param fit output from [stats::nlm()] +#' @param coverage desired confidence interval coverage probability +#' @param start starting value for incidence rate +#' +#' @return a [tibble::tibble()]; see [stats::nlm()] for details on `code` variable +#' @export +#' +postprocess_fit = function( + fit, + coverage = .95, + start = fit |> attr("lambda.start")) +{ + + + alpha = 1 - coverage + h.alpha = alpha/2 + + log.lambda.est = dplyr::tibble( + est.start = start, + incidence.rate = exp(fit$estimate), + SE = sqrt(1/fit$hessian) |> as.vector(), + CI.lwr = exp(fit$estimate - qnorm(1 - h.alpha) * .data$SE), + CI.upr = exp(fit$estimate + qnorm(1 - h.alpha) * .data$SE), + coverage = coverage, + log.lik = -fit$minimum, + iterations = fit$iterations, + nlm.exit.code = fit$code) + + class(log.lambda.est) = + "summary.seroincidence.est" |> + union(class(log.lambda.est)) + + return(log.lambda.est) +} diff --git a/R/prep_data.R b/R/prep_data.R new file mode 100644 index 00000000..a6170456 --- /dev/null +++ b/R/prep_data.R @@ -0,0 +1,121 @@ +prep_data <- function( + data, + antibodies, + curve_params, + noise_params, + strata_varnames = "", + curve_strata_varnames = NULL, + noise_strata_varnames = NULL) +{ + + if(is.null(strata_varnames) || all(strata_varnames == "")) + { + stratumDataList = + list(# est.incidence.by() expects a list. + `all data` = + list( + data = data |> select("y", "a", "antigen_iso"), + curve_params = curve_params |> select("y1", "alpha", "d", "antigen_iso"), + noise_params = noise_params |> select("nu", "eps", "y.low", "y.high", "antigen_iso") + )) |> + structure( + Antibodies = antibodies, + strata = tibble(Stratum = NA) + ) + + + return(stratumDataList) + + } + + # Make stratum variable (if needed) + + strata = data |> get_strata(strata_varnames) + + strata_vars_curve_params = + warn_missing_strata( + data = curve_params, + strata = strata |> select(curve_strata_varnames), + dataname = "curve_params" + ) + + strata_vars_noise_params = + warn_missing_strata( + data = noise_params, + strata = strata |> select(noise_strata_varnames), + dataname = "noise_params" + ) + + # xs_dataStrata <- data |> .makeStrata(strata_varnames) + # curve_paramsStrata = curve_params |> .makeStrata(strata_varnames) + # noise_params_Strata = noise_params |> .makeStrata(strata_varnames) + # levelsStrata <- levels(xs_dataStrata$Stratum) + + stratumDataList = list() + + for (cur_stratum in strata$Stratum) + { + + cur_stratum_vals = + strata |> dplyr::filter(.data$Stratum == cur_stratum) + + data_and_params_cur_stratum = + list( + data = + data |> + semi_join( + cur_stratum_vals, + by = strata_varnames) |> + select("y", "a", "antigen_iso") + ) + + if(length(strata_vars_curve_params) == 0) + { + data_and_params_cur_stratum$curve_params = + curve_params |> select("y1", "alpha", "d", "antigen_iso") + } else + { + data_and_params_cur_stratum$curve_params = + curve_params |> + semi_join( + cur_stratum_vals, + by = strata_vars_curve_params) |> + select("y1", "alpha", "d", "antigen_iso") + } + + if(length(strata_vars_noise_params) == 0) + { + data_and_params_cur_stratum$noise_params = + noise_params |> select("nu", "eps", "y.low", "y.high", "antigen_iso") + } else + { + data_and_params_cur_stratum$noise_params = + noise_params |> + semi_join( + cur_stratum_vals, + by = strata_vars_noise_params) |> + select("nu", "eps", "y.low", "y.high", "antigen_iso") + } + + stratumDataList[[cur_stratum]] = + data_and_params_cur_stratum |> + structure( + class = union( + "biomarker_data_and_params", + class(data_and_params_cur_stratum)) + ) + + } + + + + return( + structure( + stratumDataList, + Antibodies = antibodies, + strata = strata, + class = c("biomarker_data_and_params.list", "list") + + )) + +} diff --git a/R/print.seroincidence.R b/R/print.seroincidence.R index 72cd0a46..88ee4821 100644 --- a/R/print.seroincidence.R +++ b/R/print.seroincidence.R @@ -2,16 +2,16 @@ #' Print Method for Seroincidence Object #' #' @description -#' Custom [print()] function to show output of the seroincidence calculator [estimateSeroincidence()]. +#' Custom [print()] function to show output of the seroincidence calculator [est.incidence.by()]. #' -#' @param x A list containing output of function [estimateSeroincidence()]. +#' @param x A list containing output of function [est.incidence.by()]. #' @param ... Additional arguments affecting the summary produced. #' #' @examples #' #' \dontrun{ #' # estimate seroincidence -#' seroincidence <- estimateSeroincidence(...) +#' seroincidence <- est.incidence.by(...) #' #' # print the seroincidence object to the console #' print(seroincidence) @@ -21,23 +21,17 @@ #' } #' #' @export -print.seroincidence <- function(x, ...) +print.seroincidence.ests <- function(x, ...) { cat("Seroincidence object estimated given the following setup:\n") - cat(paste("a) Antibodies :", paste(x[["Antibodies"]], collapse = ", ")), "\n") - cat(paste("b) Strata :", paste(x[["Strata"]], collapse = ", ")), "\n") - censorLimits <- x[["CensorLimits"]] - cat(paste("c) Censor limits:", paste(sapply(names(censorLimits), FUN = function(name) { - paste(name, censorLimits[name], sep = " = ") - }), collapse = ", "), "\n")) + cat(paste("a) Antibodies :", paste(attr(x, "Antibodies"), collapse = ", ")), "\n") + cat(paste("b) Strata :", paste(attr(x, "Strata") |> names(), collapse = ", ")), "\n") - cat("\n") + cat("\n") cat("This object is a list containing the following items:\n") - cat("Fits - List of outputs of \"optim\" function per stratum.\n") - cat("Antibodies - Input parameter antibodies of function \"estimateSeroincidence\".\n") - cat("Strata - Input parameter strata of function \"estimateSeroincidence\".\n") - cat("CensorLimits - Input parameter censorLimits of function \"estimateSeroincidence\".\n") - + cat("Fits - List of outputs of `nlm()` function per stratum.\n") + cat("Antibodies - Input parameter antibodies of function \"est.incidence.by\".\n") + cat("Strata - Input parameter strata of function `est.incidence.by()`\n") cat("\n") cat("Call summary function to obtain output results.\n") } diff --git a/R/print.summary.seroincidence.R b/R/print.summary.seroincidence.R index 117a879d..a06838a9 100644 --- a/R/print.summary.seroincidence.R +++ b/R/print.summary.seroincidence.R @@ -2,16 +2,16 @@ #' Print Method for Seroincidence Summary Object #' #' @description -#' Custom [print()] function to show output of the seroincidence summary [summary.seroincidence()]. +#' Custom [print()] function for "summary.seroincidence.ests" objects (constructed by [summary.seroincidence.ests()]) #' -#' @param x A list containing output of function [summary.seroincidence()]. +#' @param x A "summary.seroincidence.ests" object (constructed by [summary.seroincidence.ests()]) #' @param ... Additional arguments affecting the summary produced. #' #' @examples #' #' \dontrun{ #' # estimate seroincidence -#' seroincidence <- estimateSeroincidence(...) +#' seroincidence <- est.incidence.by(...) #' #' # calculate summary statistics for the seroincidence object #' seroincidenceSummary <- summary(seroincidence) @@ -24,17 +24,12 @@ #' } #' #' @export -print.summary.seroincidence <- function(x, ...) +print.summary.seroincidence.ests <- function(x, ...) { cat("Seroincidence estimated given the following setup:\n") - cat(paste("a) Antibodies :", paste(x[["Antibodies"]], collapse = ", ")), "\n") - cat(paste("b) Strata :", paste(x[["Strata"]], collapse = ", ")), "\n") - censorLimits <- x[["CensorLimits"]] - cat(paste("c) Censor limits:", paste(sapply(names(censorLimits), FUN = function(name) { - paste(name, censorLimits[name], sep = " = ") - }), collapse = ", "), "\n")) - cat(paste("d) Quantiles :", paste(x[["Quantiles"]], collapse = ", ")), "\n") - + cat(paste("a) Antibodies :", paste(x |> attr("Antibodies"), collapse = ", ")), "\n") + cat(paste("b) Strata :", paste(x |> attr("Strata"), collapse = ", ")), "\n") cat("\n Seroincidence estimates:\n") - print(x[["Results"]]) + print(as_tibble(x)) + invisible(x) } diff --git a/R/sees_baseline_data.R b/R/sees_baseline_data.R new file mode 100644 index 00000000..90f878da --- /dev/null +++ b/R/sees_baseline_data.R @@ -0,0 +1,14 @@ +#' #' @docType data +#' #' +#' #' @name sees_crossSectional_baseline_allCountries +#' #' +#' #' @title +#' #' Cross-sectional Typhoid data +#' #' +#' #' @description +#' #' A [tibble::tibble()] +#' #' +#' #' @usage +#' #' sees_crossSectional_baseline_allCountries +#' #' +#' NULL diff --git a/R/serocalc.r b/R/serocalc.r index e77a7845..ca6e4238 100644 --- a/R/serocalc.r +++ b/R/serocalc.r @@ -3,26 +3,48 @@ #' Calculate negative log-likelihood (deviance) #' #' more description to be added here -#' @param log.lambda Initial guess of incidence rate -#' @param csdata cross-sectional sample data -#' @param lnpars longitudinal antibody decay model parameters -#' @param cond measurement noise parameters +#' @param log.lambda natural logarithm of incidence parameter, in log(years). Value of -6 corresponds roughly to 1 day (log(1/365.25)), -4 corresponds roughly to 1 week (log(7 / 365.25)). +#' @param csdata cross-sectional sample data containing variables `y` and `a` +#' @param lnpars longitudinal antibody decay model parameters `alpha`, `y1`, and `d` +#' @param cond measurement noise parameters `nu`, `eps`, `y.low`, and `y.high` #' @export -fdev <- function(log.lambda,csdata,lnpars,cond) +fdev <- function( + log.lambda, + csdata, + lnpars, + cond) { - res <- 0; lambda <- as.double(exp(log.lambda)); - y <- as.double(csdata$y); a <- as.double(csdata$a); + res <- 0; + lambda <- as.double(exp(log.lambda)); + y <- as.double(csdata$y); + a <- as.double(csdata$a); nsubj <- as.integer(length(y)); - y1 <- as.double(lnpars$y1); alpha <- as.double(lnpars$alpha); - d <- as.double(lnpars$d); nmc <- as.integer(length(y1)); + y1 <- as.double(lnpars$y1); + alpha <- as.double(lnpars$alpha); + d <- as.double(lnpars$d); + nmc <- as.integer(length(y1)); step <- as.double(max(y1)/100); # hack for numerical integrations - nu <- as.double(cond$nu); eps <- as.double(cond$eps); - y.low <- as.double(cond$y.low); y.high <- as.double(cond$y.high); - llpp <- .C("negloglik",res=as.double(res), - lambda=lambda,y=y,a=a,nsubj=nsubj, - nu=nu,eps=eps,step=step,y.low=y.low,y.high=y.high, - y1=y1,alpha=alpha,d=d,nmc=nmc); + nu <- as.double(cond$nu); + eps <- as.double(cond$eps); + y.low <- as.double(cond$y.low); + y.high <- as.double(cond$y.high); + llpp <- .C( + "negloglik", + res=as.double(res), + lambda=lambda, + y=y, + a=a, + nsubj=nsubj, + nu=nu, + eps=eps, + step=step, + y.low=y.low, + y.high=y.high, + y1=y1, + alpha=alpha, + d=d, + nmc=nmc); return(llpp$res); } diff --git a/R/serocalculator-package.R b/R/serocalculator-package.R index 1c5e8ec0..c7dca037 100644 --- a/R/serocalculator-package.R +++ b/R/serocalculator-package.R @@ -92,13 +92,41 @@ #' Epidemiology and Infection 129, no. 3 (December 10, 2002):479. doi:10.1017/S0950268802007896. #' } #' -#' @importFrom stats dlnorm optim pgamma plnorm -#' @importFrom utils download.file unzip #' ## usethis namespace: start +#' @importFrom dplyr across +#' @importFrom dplyr all_of +#' @importFrom dplyr anti_join +#' @importFrom dplyr any_of +#' @importFrom dplyr bind_rows +#' @importFrom dplyr distinct +#' @importFrom dplyr everything +#' @importFrom dplyr filter +#' @importFrom dplyr inner_join #' @importFrom dplyr mutate +#' @importFrom dplyr pull +#' @importFrom dplyr relocate +#' @importFrom dplyr rename +#' @importFrom dplyr row_number +#' @importFrom dplyr select +#' @importFrom dplyr semi_join +#' @importFrom dplyr tibble +#' @importFrom magrittr %>% +#' @importFrom parallel clusterEvalQ +#' @importFrom parallel clusterExport +#' @importFrom parallel parLapplyLB #' @importFrom Rcpp sourceCpp +#' @importFrom rlang .data +#' @importFrom rlang .env +#' @importFrom stats dlnorm optim pgamma plnorm +#' @importFrom stats nlm +#' @importFrom stats qnorm +#' @importFrom tibble as_tibble +#' @importFrom tibble column_to_rownames +#' @importFrom tibble tibble +#' @importFrom tidyr drop_na +#' @importFrom utils download.file unzip #' @useDynLib serocalculator, .registration = TRUE ## usethis namespace: end NULL diff --git a/R/summary.seroincidence.R b/R/summary.seroincidence.R index 53b50a78..13efadda 100644 --- a/R/summary.seroincidence.R +++ b/R/summary.seroincidence.R @@ -3,17 +3,15 @@ #' #' @description #' Calculate seroincidence from output of the seroincidence calculator -#' [estimateSeroincidence()]. +#' [est.incidence.by()]. #' -#' @param object A dataframe containing output of function [estimateSeroincidence()]. +#' @param object A dataframe containing output of function [est.incidence.by()]. #' @param ... Additional arguments affecting the summary produced. -#' @param quantiles A vector of length 2 specifying quantiles for lower (first element) and upper -#' (second element) bounds of `lambda`. Default = `c(0.025, 0.975)`. #' @param showDeviance Logical flag (`FALSE`/`TRUE`) for reporting deviance #' (-2*log(likelihood) at estimated seroincidence. Default = `TRUE`. #' @param showConvergence Logical flag (`FALSE`/`TRUE`) for reporting convergence (see #' help for [optim()] for details). Default = `TRUE`. -#' +#' @param confidence_level desired confidence interval coverage probability #' @return #' A list with the following items: #' \describe{ @@ -24,30 +22,33 @@ #' `lambda`) and `Covergence` (Convergence indicator returned by [optim()]. #' Value of 0 indicates convergence) columns are included.} #' \item{`Antibodies`}{Character vector with names of input antibodies used in -#' [estimateSeroincidence()].} -#' \item{`Strata`}{Character with names of strata used in [estimateSeroincidence()].} +#' [est.incidence.by()].} +#' \item{`Strata`}{Character with names of strata used in [est.incidence.by()].} #' \item{`CensorLimits`}{List of cutoffs for each of the antibodies used in -#' [estimateSeroincidence()].} +#' [est.incidence.by()].} #' } #' #' @examples #' #' \dontrun{ #' # estimate seroincidence -#' seroincidence <- estimateSeroincidence(...) +#' seroincidence <- est.incidence.by(...) #' #' # calculate summary statistics for the seroincidence object #' seroincidenceSummary <- summary(seroincidence) #' } #' #' @export -summary.seroincidence <- function(object, ..., quantiles = c(0.025, 0.975), showDeviance = TRUE, - showConvergence = TRUE) +summary.seroincidence.ests <- function( + object, + ..., + confidence_level = .95, + showDeviance = TRUE, + showConvergence = TRUE) { - # R CMD check warnings workaround - hessian <- NULL - value <- NULL - convergence <- NULL + + alpha = 1 - confidence_level + quantiles = c(alpha/2, 1 - alpha/2) if (length(quantiles) != 2 || any(quantiles < 0) || any(quantiles > 1)) { stop("Incorrectly specified quantiles") @@ -57,34 +58,41 @@ summary.seroincidence <- function(object, ..., quantiles = c(0.025, 0.975), show stop("Quantile for upper bound of incidence estimate cannot be less than the lower bound.") } - fits <- object[["Fits"]] - results <- as.data.frame(t(sapply(fits, FUN = function(elem) { - with(elem, c( - Lambda.est = 365.25 * exp(par + qnorm(0.5) * sqrt(1 / hessian)), - Lambda.lwr = 365.25 * exp(par + qnorm(quantiles[1]) * sqrt(1 / hessian)), - Lambda.upr = 365.25 * exp(par + qnorm(quantiles[2]) * sqrt(1 / hessian)), - Deviance = 2 * value, - Convergence = convergence)) - }))) + results = + object |> + lapply( + FUN = postprocess_fit, + coverage = confidence_level) |> + bind_rows(.id = "Stratum") + + results = + inner_join( + object |> attr("Strata"), + results, + by = "Stratum", + relationship = "one-to-one" + ) |> + relocate("Stratum", .before = everything()) - results$Stratum <- rownames(results) - rownames(results) <- NULL if (!showDeviance) { - results$Deviance <- NULL + results$log.lik <- NULL } if (!showConvergence) { - results$Convergence <- NULL + results$nlm.exit.code <- NULL } - output <- list(Results = results, - Antibodies = object[["Antibodies"]], - Strata = object[["Strata"]], - CensorLimits = object[["CensorLimits"]], - Quantiles = quantiles) - - class(output) <- c("summary.seroincidence", "list") + output <- + results |> + structure( + Antibodies = attr(object, "Antibodies"), + Strata = attr(object, "Strata") |> names(), + Quantiles = quantiles, + class = + "summary.seroincidence.ests" |> + union(class(results)) + ) return(output) } diff --git a/R/sysdata.rda b/R/sysdata.rda new file mode 100644 index 00000000..13122c41 Binary files /dev/null and b/R/sysdata.rda differ diff --git a/R/typhoid_controls.R b/R/typhoid_controls.R new file mode 100644 index 00000000..318f5ccb --- /dev/null +++ b/R/typhoid_controls.R @@ -0,0 +1,29 @@ +#' @docType data +#' +#' @name typhoid_controls +#' +#' @title +#' Example cross-sectional data for typhoid (`HlyE_IgA` and `HlyE_IgG`) +#' +#' @description +#' Data frame of ELISA assay results, by `pop` (`"CA Facts"`, `"MGH"`), `antigen_iso` (`"HlyE_IgA"`, `"HlyE_IgG"`), and `Age` (in years). +#' +#' @usage +#' typhoid_controls +#' +#' @format +#' The measurements are in the variable `elisa`. Variable `nu` provides an estimate of a conditional noise parameter. +#' +#' @examples +#' +#' # Print the data: +#' typhoid_controls +#' +#' # Plot the data +#' library(ggplot2) +#' typhoid_controls |> +#' ggplot(aes(x = Age, y = elisa, col = antigen_iso)) + +#' geom_point() + +#' geom_smooth() +#' +NULL diff --git a/R/typhoid_noise_params.R b/R/typhoid_noise_params.R new file mode 100644 index 00000000..c66cc9ee --- /dev/null +++ b/R/typhoid_noise_params.R @@ -0,0 +1,27 @@ +#' @docType data +#' +#' @name typhoid_noise_params +#' +#' @title +#' Example noise parameters for HlyE_IgA and HlyE_IgG, by country +#' +#' @description +#' Data frame of example noise parameters, by `Country` (`"MGH"`, `"bangladesh"`, `"nepal"`) +#' and `antigen_iso` (`"HlyE_IgA"`, `"HlyE_IgG"`). +#' +#' @usage +#' typhoid_noise_params +#' +#' @format +#' The parameters are: +#' * `llod` +#' * `nu` +#' * `y.high` +#' * `eps` +#' +#' @examples +#' +#' # Show the data: +#' typhoid_noise_params +#' +NULL diff --git a/R/utils.R b/R/utils.R index 281189ff..8bd7e0dd 100644 --- a/R/utils.R +++ b/R/utils.R @@ -38,12 +38,12 @@ stopifnot(!missing(antibodies)) if (!is.character(antibodies)) { - stop(.pasteN("Argument \"antibodies\" is not a character vector.", + stop(.pasteN("Argument `antibodies` is not a character vector.", "Provide a character vector with at least one antibody name.")) } if (all(antibodies == "")) { - stop(.pasteN("Argument \"antibodies\" is empty.", + stop(.pasteN("Argument `antibodies` is empty.", "Provide a character vector with at least one antibody name.")) } @@ -53,67 +53,43 @@ .checkCsData <- function(data, antibodies) { if (!is.data.frame(data)) { - stop(.pasteN("Argument \"data\" is not a dataframe.", - "Provide a dataframe with cross-sectional serology data per antibody.")) + stop(.pasteN("Argument `data` is not a `data.frame()`.", + "Provide a `data.frame()` with cross-sectional serology data per antibody.")) } - if (!is.element("Age", names(data))) { - stop("Argument \"data\" is missing column \"Age\".") - } - - if (!all(is.element(.checkIvc(data, antibodies)$Antibodies, names(data)))) { - stop("Antibody names in argument \"data\" and argument \"antibodies\" do not match.") + if (!is.element("a", names(data))) { + stop("Argument `data` is missing column `a` (age, in years).") } invisible(NULL) } -.checkIvc <- function(data, antibodies) { - # Assume we are not dealing with interval censored data - ivc <- FALSE - if (length(intersect(names(data), antibodies)) != length(antibodies)) { - # Add .lo and .hi to ab names - antibodies <- .appendNames(antibodies) - # We are dealing with interval censored data - ivc <- TRUE - } - return(list(Ivc = ivc, Antibodies = antibodies)) -} +.checkParams <- function(antibodies, params) +{ -.checkParams <- function(antibodies, params) { - if (!is.list(params)) { - stop(.pasteN("Argument \"params\" is not a list of dataframes.", - "Provide a list of three dataframes with names of the antibodies to be tested.", - "Each of the dataframes should contain a Monte Carlo sample of the longitudinal", - "parameters named y1, alpha, r, y0, mu1 and t1.")) - } + message1 = paste( + "Please provide a `data.frame()` containing Monte Carlo samples of the longitudinal parameters", + "`y1`, `alpha`, and `r`", + "for each value of `antigen_iso` in `data`") - if (!all(sapply(params, is.data.frame))) { - stop(.pasteN("Argument \"params\" is not a list of dataframes.", - "Provide a list of three dataframes with names of the antibodies to be tested.", - "Each of the dataframes should contain a Monte Carlo sample of the longitudinal", - "parameters named y1, alpha, r, y0, mu1 and t1.")) - } - if (!all(is.element(names(params[[1]]), - c("y1", "alpha", "yb", "r", "y0", "mu1", "t1")))) { - stop(.pasteN("The parameter names do not match.", - "Provide a list of three dataframes with names of the antibodies to be tested.", - "Each of the dataframes should contain a Monte Carlo sample of the longitudinal", - "parameters named y1, alpha, r, y0, mu1 and t1.")) + if (!is.data.frame(params)) { + stop( + .pasteN( + "Argument `params` is not a `data.frame()`.", + message1)) } - if (length(params[[1]]$y0) != length(params[[1]]$alpha) | - length(params[[1]]$y0) != length(params[[1]]$yb) | - length(params[[1]]$y0) != length(params[[1]]$r) | - length(params[[1]]$y0) != length(params[[1]]$y1) | - length(params[[1]]$y0) != length(params[[1]]$mu1) | - length(params[[1]]$y0) != length(params[[1]]$t1)) { - stop("The parameter lists \"params\" are of different length.") + if (!all(c("y1", "alpha", "r") %in% names(params))) + { + stop( + .pasteN( + "The parameter names do not match.", + message1)) } - if (!all(is.element(antibodies, names(params)))) { - stop("Antibody names in argument \"antibodies\" and argument \"params\" do not match.") + if (!all(antibodies %in% params$antigen_iso)) { + stop("Some `antigen_iso` values are missing.") } invisible(NULL) @@ -122,7 +98,7 @@ .checkStrata <- function(data, strata) { if (!is.character(strata)) { stop(.pasteN("Argument \"strata\" is not a character vector.", - "Provide a character vector with strata names.")) + "Provide a character vector with names of stratifying variables.")) } if (!all(is.element(strata, union("", names(data))))) { @@ -132,41 +108,6 @@ invisible(NULL) } -.prepData <- function(data, antibodies, strata = "") -{ - ivcAb <- .checkIvc(data, antibodies) - - # Make stratum variable (if needed) - dataStrata <- .makeStrata(data, strata) - levelsStrata <- levels(dataStrata$Stratum) - return(list(Ivc = ivcAb$Ivc, - Antibodies = ivcAb$Antibodies, - Levels = levelsStrata, - Data = dataStrata)) -} -.makeStrata <- function(data, strata = "") -{ - dataStrata <- data - if (all(strata != "")) { - dataStrata$Stratum <- interaction(dataStrata[, strata]) - } else { - dataStrata$Stratum <- factor(1) - } - return(dataStrata) -} -.selectModel <- function(param) -{ - model1 <- any(param$r == 1 & param$yb == 0 & param$t1 == 0) - model2 <- any(param$r != 1 & param$yb == 0 & param$t1 == 0) - model3 <- any(param$r == 1 & !is.na(param$y0)) - model4 <- any(param$r != 1 & !is.na(param$y0)) - model5 <- any(param$r == 1 & param$yb != 0 & param$t1 == 0) - res <- which(c(model1, model2, model3, model4, model5)) - if (length(res) == 0) { - res <- 0 - } - return(res) -} diff --git a/R/warn_missing_strata.R b/R/warn_missing_strata.R new file mode 100644 index 00000000..56251633 --- /dev/null +++ b/R/warn_missing_strata.R @@ -0,0 +1,49 @@ +warn_missing_strata = function( + data, + strata, + dataname) +{ + present_strata_vars = intersect( + names(strata), + names(data)) + + missing_strata_vars = setdiff( + names(strata), + names(data)) + + + + if(length(missing_strata_vars) > 0) + { + warning( + dataname, + " is missing some strata variables: ", + missing_strata_vars |> paste(collapse = ", "), + "\n", dataname, " will only be stratified by: ", + present_strata_vars |> paste(collapse = ",")) + } + + if(length(present_strata_vars) > 0) + { + strata2 = data |> get_strata(present_strata_vars) + + missing_strata = + anti_join( + strata, + strata2, + by = present_strata_vars + ) |> + distinct(across(all_of(present_strata_vars))) + + if(nrow(missing_strata) > 0) + { + message("The following strata are missing in ", dataname, ":") + print(missing_strata) + stop("Missing strata in `", dataname, "`") + } + } + + return(present_strata_vars) + + +} diff --git a/README.html b/README.html deleted file mode 100644 index a458f929..00000000 --- a/README.html +++ /dev/null @@ -1,453 +0,0 @@ - - - - - - - - - - - - - -README - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
-

serocalculator package

-
- -

R-CMD-check

-

Antibody levels measured in a (cross–sectional) population sample can -be translated into an estimate of the frequency with which -seroconversions (infections) occur in the sampled population. Formulated -simply: the presence of many high titres indicates that many subjects -likely experienced infection recently, while low titres indicate a low -frequency of infections in the sampled population.

-

The serocalculator script was designed to use the longitudinal -response characteristics by means of a set of parameters characterizing -the longitudinal response of the selected serum antibodies.

-
-

Installation

-

You can install the development version from GitHub with the following code:

-
install.packages("devtools")
-devtools::install_github("ucd-serg/serocalculator")
-

A Note for Windows Users

-

Windows users will need to install Rtools, which contains a -collection of tools for building and employing R packages that are still -in development. This can be done either during the devtools -package installation, or independently if devtools is already -installed.

-
 During devtools installation:
-   When prompted to install additional build tools, select “Yes” and -Rtools will be installed. |
-

!(Click Yes to install Rtools along with the devtools -package)[1.png] |

-
 Independently:
-
    -
  1. Download Rtools from https://cran.r-project.org/bin/windows/Rtools/

  2. -
  3. Run the installer

    -
      -
    • During the Rtools installation you may see a window asking you to -“Select Additional Tasks”.
    • -
    • Do not select the box for “Edit the system PATH”. -devtools and RStudio should put Rtools on the PATH automatically when it -is needed.
    • -
    • Do select the box for “Save version information to -registry”. It should be selected by default. | ## Getting Help
    • -
  4. -
-

If you need assistance or encounter a clear bug, please file an issue -with a minimal reproducible example on GitHub.

-

Another great resource is The Epidemiologist R -Handbook, which includes an introductory page on asking for -help with R packages via GitHub: https://epirhandbook.com/en/getting-help.html

-
-
- - - - -
- - - - - - - - - - - - - - - diff --git a/README.md b/README.md index cc433ed3..6c924c55 100644 --- a/README.md +++ b/README.md @@ -30,13 +30,17 @@ devtools::install_github("ucd-serg/serocalculator") **A Note for Windows Users** + Windows users will need to install Rtools, which contains a collection of tools for building and employing R packages that are still in development. This can be done either during the *devtools* package installation, or independently if *devtools* is already installed. | *During devtools installation:* -| When prompted to install additional build tools, select "Yes" and Rtools will be installed. | +| When prompted to install additional build tools, select "Yes" and Rtools will be installed. + +![Click Yes to install Rtools along with the *devtools* package][id] + +[id]: vignettes/fig/Rtools1.png -!(Click Yes to install Rtools along with the *devtools* package)[\vignettes\fig\Rtools1.png] | | *Independently:* diff --git a/data-raw/sees_datacleaning.R b/data-raw/sees_datacleaning.R new file mode 100644 index 00000000..ab692569 --- /dev/null +++ b/data-raw/sees_datacleaning.R @@ -0,0 +1,52 @@ +#Elisa data +library(dplyr) +library(forcats) +library(readr) +d0 <- read.csv( + "inst/extdata/SEES_2022-10-24_redacted_2023-10-12.csv", + header=T) %>% + #filter(antigen != "CdtB" | antigen != "YncE") %>% + filter(studyarm!= "highE_hh", + studyarm!= "lowE_hh", + studyarm!="ae control") %>% + mutate( + antigen_iso = + paste(elisa_antigen, "_", elisa_antbdy_iso, sep="") |> + factor(), + ageCat = cut( + Age, + breaks= c(0, 4.99, 15.99, 99), + right=FALSE, labels = c("<5", "5-15", "16+")), + TimePeriod = + TimePeriod |> + factor(levels = c("Baseline","28 days","3 months","6 months", "12 months", "18 months", "First visit")), + Arm2 = + Arm |> + fct_collapse(Cases = c("Prospective Cases", "Retrospective Cases")) |> + factor( + levels = c("Cases", "Population-based"), + labels = c("Cases", "Population sample")), + sex = sex |> as.factor() |> fct_collapse(NULL = c("97"))) %>% + mutate(Gender = factor(sex, labels = c("Male", "Female"))) %>% + filter(Age<=25) %>% + filter(catchment!="matiari") %>% + filter(catchment!="mirzapur") %>% + mutate(cluster = areaunit3) %>% + droplevels() %>% + filter(Arm2 == "Population sample" & TimePeriod == "Baseline") %>% + select(Country, cluster, catchment, Age, ageCat, antigen_iso, result) %>% + mutate(cluster = factor(cluster)) %>% + filter(antigen_iso %in% c("HlyE_IgG", "HlyE_IgA")) |> + as_tibble() |> + select(-cluster) + + sees_crossSectional_baseline_allCountries = d0 +use_data(sees_crossSectional_baseline_allCountries, overwrite = TRUE) +write_csv( + d0, + fs::path( + "inst/extdata", + paste0( + "sees_crossSectional_baseline_allCountries", + ".102523.csv"))) + diff --git a/data-raw/typhoid-controls.R b/data-raw/typhoid-controls.R new file mode 100644 index 00000000..993d971e --- /dev/null +++ b/data-raw/typhoid-controls.R @@ -0,0 +1,21 @@ +library(readr) + +tc = read_csv("inst/extdata/typhoidcontrols.csv") +tc |> + summarize( + .by = c(, antigen_iso), + nu = quantile( + elisa, + p = .95, + + ) + ) + +library(ggplot2) +ggplot(tc, aes(x = Age, y = elisa, col = antigen_iso)) + + geom_point() + + geom_smooth() + +typhoid_controls = tc + +usethis::use_data(typhoid_controls, overwrite = TRUE) diff --git a/data-raw/typhoid_noise_params.R b/data-raw/typhoid_noise_params.R new file mode 100644 index 00000000..6b5e6829 --- /dev/null +++ b/data-raw/typhoid_noise_params.R @@ -0,0 +1,14 @@ +typhoid_noise_params = + tibble::tribble( + ~Country, ~antigen_iso, ~llod, ~nu, ~y.high, ~eps, + "MGH", "HlyE_IgA", 0.17922, 2.86983, 5e+06, 0.23961, + "bangladesh", "HlyE_IgA", 0.17922, 2.86983, 5e+06, 0.2805, + "nepal", "HlyE_IgA", 0.17922, 2.86983, 5e+06, 0.23835, + "pakistan", "HlyE_IgA", 0.17922, 2.86983, 5e+06, 0.27932, + "MGH", "HlyE_IgG", 0.645, 3.0252, 5e+06, 0.16392, + "bangladesh", "HlyE_IgG", 0.645, 3.0252, 5e+06, 0.30608, + "nepal", "HlyE_IgG", 0.645, 3.0252, 5e+06, 0.12821, + "pakistan", "HlyE_IgG", 0.645, 3.0252, 5e+06, 0.14564 + ) + +usethis::use_data(typhoid_noise_params, overwrite = TRUE) diff --git a/data-raw/typhoid_results.qmd b/data-raw/typhoid_results.qmd new file mode 100644 index 00000000..4909bad3 --- /dev/null +++ b/data-raw/typhoid_results.qmd @@ -0,0 +1,91 @@ +--- +title: "typhoid_results" +format: html +--- + + + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} + +#library(devtools) +#install_github("UCD-SERG/serocalculator") +library(serocalculator) +library(tidyverse) +``` + +```{r longdata} +c.hlye.IgG <- + fs::path_package( + "extdata", + "dmcmc_hlyeigg_09.30.rds", + package = "serocalculator") |> #Load longitudinal parameters dataset + readRDS()%>% + mutate(alpha = alpha*365.25, #Create alpha and d + d = r-1) %>% + select(y1, alpha, d) #Select only the variables needed for analysis +``` + +``` {r simdata} +library(fs) # filesystem utility functions +p.hlye.IgG <- + fs::path_package( + package = "serocalculator", + "extdata/simpophlyeigg.2.csv") %>% #Load simulated cross-sectional dataset + read_csv() %>% + rename( #rename variables + y = y.smpl, + a = a.smpl) %>% + select(y, a) #Select only the variables needed for analysis +``` + +``` {r conditions} +cond.hlye.IgG <- data.frame( + nu = 1.027239, # B noise + eps = 0.2, # M noise + y.low = 0.0, # low cutoff + y.high = 5e4, + antigen_iso = "HlyE_IgG"); +``` + +```{r seroinc} +start <- .05 + +lambda = start # initial estimate: starting value +log.lambda = log(lambda) +log.lmin=log(lambda/10) +log.lmax=log(10*lambda) + + + +objfunc <- function(llam){ + return(res <- fdev(llam, p.hlye.IgG, c.hlye.IgG, cond.hlye.IgG)) +} + + +fit <- nlm( + objfunc, + p=log.lambda, + hessian=TRUE, + print.level=0, + stepmax=1, + iterlim = 100) + +typhoid_results = fit |> + postprocess_fit( + coverage = .95, + start = start + ) |> + mutate( + ageCat = NULL, + antigen.iso = paste(collapse = "+", "HlyE_IgG")) %>% + structure(noise.parameters = cond.hlye.IgG) + +usethis::use_data(typhoid_results, internal = TRUE, overwrite = TRUE) +``` diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 00000000..3982aa57 --- /dev/null +++ b/data/.gitignore @@ -0,0 +1 @@ +sees_crossSectional_baseline_allCountries.rda diff --git a/data/typhoid_controls.rda b/data/typhoid_controls.rda new file mode 100644 index 00000000..e076b9f7 Binary files /dev/null and b/data/typhoid_controls.rda differ diff --git a/data/typhoid_noise_params.rda b/data/typhoid_noise_params.rda new file mode 100644 index 00000000..3b4571ab Binary files /dev/null and b/data/typhoid_noise_params.rda differ diff --git a/inst/extdata/.gitignore b/inst/extdata/.gitignore new file mode 100644 index 00000000..51369d22 --- /dev/null +++ b/inst/extdata/.gitignore @@ -0,0 +1,10 @@ +SEES_2022-10-24_redacted_2023-10-12.csv +SEES_NoiseParam.rds +inc_est_2023-10-16.csv +llod_bgmghpknp.csv +northAmerican_typhoidcontrols.csv +sample_cvs_2021-10-13.csv +sees_crossSectionalPopulation_baseline_allCountries.102523.csv +sees_crossSectional_baseline_allCountries.102523.csv +sees_dmcmc_09.30.2021.rds +allpopsamples_hlye.csv diff --git a/inst/extdata/dmcmc_hlyeigg_09.30.rds b/inst/extdata/dmcmc_hlyeigg_09.30.rds new file mode 100644 index 00000000..f5e81c2b Binary files /dev/null and b/inst/extdata/dmcmc_hlyeigg_09.30.rds differ diff --git a/inst/extdata/simpophlyeigg.2.csv b/inst/extdata/simpophlyeigg.2.csv new file mode 100644 index 00000000..98646db3 --- /dev/null +++ b/inst/extdata/simpophlyeigg.2.csv @@ -0,0 +1,501 @@ +a.smpl,y.smpl,i,t +22.925656523690556,10.088593902118793,1,0 +23.891269684017168,0.676364226928609,1,0 +6.030421345506329,0.39894735506634116,1,0 +19.78965313954046,0.6291083896473504,1,0 +9.090025365254842,11.361959623212012,1,0 +17.271839995146728,8.400308025531567,1,0 +23.76020460242638,12.73540536944525,1,0 +16.131577445436267,93.34860846005688,1,0 +18.248825606592,6.633294392265636,1,0 +20.02410902442876,2.1617888005546675,1,0 +22.04276160324458,60.37184538485429,1,0 +11.77530041304184,12.001584451811286,1,0 +17.03995998216327,0.6938945260296263,1,0 +6.121164712279569,4.233963613759292,1,0 +20.039948704417327,16.047973146955176,1,0 +19.909064539521932,3.0812679340971605,1,0 +7.459994014436379,16.928101556789812,1,0 +22.160140914658548,4.194586386875255,1,0 +9.791304893766064,0.6368506891575065,1,0 +13.446984254992566,4.8537443724778155,1,0 +14.488301769369281,45.0805432516028,1,0 +12.443505510974209,10.39074393421835,1,0 +19.377566600523423,2.44031251330012,1,0 +22.552892745740245,9.022693870924636,1,0 +18.874737458035817,22.50089714510804,1,0 +10.299335390082561,45.265260041465474,1,0 +22.597583144260568,28.506178978386657,1,0 +12.925443836678749,0.2432983362049576,1,0 +19.812708394126965,22.48287688981252,1,0 +20.376554923371877,24.078811305372838,1,0 +12.502184324525295,3.7092441962333464,1,0 +16.589363273622002,147.54302367563838,1,0 +16.838299214928412,5.468988676724285,1,0 +18.322083631439597,1.7698816662347197,1,0 +5.151018497536424,1.577373806944717,1,0 +15.663405665017198,302.3539304517082,1,0 +8.163587960416915,12.042989422310246,1,0 +16.67740189600503,8.994614564266772,1,0 +21.9769491677382,0.7973266193942066,1,0 +19.221291004791855,105.1151625621975,1,0 +18.968324653184972,46.87583970362304,1,0 +11.469961077403276,11.64685373505734,1,0 +12.599604620889295,5.299356105845451,1,0 +14.089045426668598,66.39788962440888,1,0 +12.32726667614188,0.78048833863237,1,0 +14.349719245592132,12.620650211728464,1,0 +12.313053398660848,28.864212059153886,1,0 +13.812819166928529,1.8018253823778414,1,0 +16.33632398937596,0.6697483252755183,1,0 +14.342885438685771,5.396547079129008,1,0 +5.466372019774281,0.48405315208345256,1,0 +6.666789801223203,9.778037202588047,1,0 +7.047081675017252,8.244235712866812,1,0 +19.435125714219176,12.014045455279604,1,0 +6.0828570134425535,0.6897476029364217,1,0 +23.42743480319157,2.404218077004231,1,0 +11.915573624304962,4.025093819142054,1,0 +18.88006895962404,1.559640685515237,1,0 +20.735022200578822,76.14354429813085,1,0 +20.58473121426301,0.772678343908586,1,0 +8.621847524957266,0.36996859673523874,1,0 +17.90235290475888,10.53964892438101,1,0 +5.2068286427948625,182.96948734706822,1,0 +11.838894984212239,6.688269181607881,1,0 +23.918911731389816,13.206977513581062,1,0 +5.391325157887768,4.531435400623727,1,0 +18.21921215321403,8.03545850761315,1,0 +5.467781020649709,0.3374150407014904,1,0 +8.623869550961535,1.05831453311799,1,0 +15.354298397456295,5.178802312327238,1,0 +10.85596624233527,5.6917950193720905,1,0 +24.384879200749563,18.485507430745706,1,0 +18.46492998719681,4.195256908347683,1,0 +20.22289879622869,40.481381623340724,1,0 +21.09293504079105,3.0325646387281218,1,0 +18.025830045714976,13.024445019493193,1,0 +24.042630853254813,10.378212182951446,1,0 +9.704373986455611,3.1979921157602105,1,0 +15.074790220151188,15.371468516292543,1,0 +18.087448826543984,1.389638899152946,1,0 +14.035860353757162,2.368837367763009,1,0 +13.438022048408165,3.7698610795121734,1,0 +22.162947085218036,22.719626770992086,1,0 +6.121171298092231,7.6380132328104136,1,0 +14.024447033365721,6.22709450677378,1,0 +10.05848192576319,9.923907023147821,1,0 +21.237068110750986,13.44321106119088,1,0 +6.456678226229269,3.4869416476920088,1,0 +7.909830124448053,4.27310121061671,1,0 +5.5707812736206685,38.66242330745997,1,0 +13.808646349483169,1.4762901047404906,1,0 +8.689373258464038,14.351922083059774,1,0 +13.544922615117393,18.89270329759982,1,0 +12.378510139777791,3.5877555080772625,1,0 +20.99663786052726,25.573244072698838,1,0 +17.584594657968264,10.711496461247306,1,0 +12.681968483543024,8.342051973686656,1,0 +9.818357168815563,4.02074542519349,1,0 +15.842162744442465,1.6948954453724734,1,0 +12.07122869685525,22.913825679306143,1,0 +15.610617695664986,11.642776667509683,1,0 +18.239543888026382,6.0766180867060715,1,0 +19.798100945285988,16.265964324656988,1,0 +15.758067157475743,9.628034456931486,1,0 +9.88549832344288,52.86328671477575,1,0 +19.461621532314457,8.855103659425987,1,0 +9.411764528683852,14.214318027300225,1,0 +17.20828478526091,3.015135793957903,1,0 +5.968518197198864,0.5097024852245491,1,0 +16.692411037529816,20.881049649831223,1,0 +15.611538154906592,11.587847039900927,1,0 +14.608512938339262,18.170671561362887,1,0 +20.869295303658582,14.556598143466449,1,0 +7.093478892773856,5.4495725390230705,1,0 +7.661371023904066,11.496504235128365,1,0 +8.539806795318146,26.21711912024034,1,0 +18.99611318951007,0.7343160819180115,1,0 +21.60838914891705,9.4515808818334,1,0 +20.0825964444899,3.1934010718640056,1,0 +5.544492934222799,1.0220591130811196,1,0 +12.17204485232476,2.857731073160992,1,0 +17.733964747539723,2.9737335987086824,1,0 +17.965816253030205,2.3009904011929914,1,0 +18.236977441047785,104.07000151037722,1,0 +5.122347704337444,127.63134361557398,1,0 +24.416116757418493,2.576347306950208,1,0 +23.31115830588853,11.947787494241922,1,0 +9.645637436504476,12.394682838156966,1,0 +22.520385141861624,0.8089682008073562,1,0 +7.394640230748337,15.248132906523033,1,0 +15.802766287433913,49.52937269313648,1,0 +10.20626902799355,46.874293940099584,1,0 +9.735928430089261,2.064523544800318,1,0 +22.510622016680426,10.378090503819218,1,0 +11.140248095914721,0.3864441083649919,1,0 +11.072231982331722,22.627405952993378,1,0 +13.26870454691816,8.034403716547184,1,0 +13.398587961508891,30.842697109246256,1,0 +10.492286939024925,4.912412766114776,1,0 +7.167665526515338,0.9366798934296122,1,0 +14.323157187718897,7.172126681614276,1,0 +8.93026903023012,27.535927193997463,1,0 +23.815852317807728,3.152737397998056,1,0 +10.594633176582864,10.099330349516155,1,0 +18.421183189020958,34.6141271077283,1,0 +7.810161380444187,15.540810884996143,1,0 +7.211044706024695,7.882611188793602,1,0 +20.17693314700853,4.710827754425337,1,0 +9.651028429158032,0.1813398967503499,1,0 +9.611786820197011,54.05153877063491,1,0 +21.503611941295674,0.6984497016938667,1,0 +17.9020938472799,1.483881309293941,1,0 +23.88603643903043,3.759218408711209,1,0 +21.818797695192043,25.223948283353113,1,0 +16.30296636419836,13.243536730506118,1,0 +13.416540253842248,7.457290295946404,1,0 +23.819765347051433,7.459589088934734,1,0 +12.183895331048406,8.087399318984522,1,0 +9.196166157242843,2.1516515863745,1,0 +6.538229520611931,0.46839683932824616,1,0 +19.687850229199974,77.09331325968473,1,0 +6.973917745840735,7.148349575279893,1,0 +7.490377626244444,8.163493597100087,1,0 +19.29767868693918,30.206155272100204,1,0 +22.434182569580152,2.0302721080753234,1,0 +5.318327633347362,194.36452337757612,1,0 +17.357656075637784,44.01895629422102,1,0 +19.867465977584942,0.8844653308275012,1,0 +12.39953458572505,7.237981702979904,1,0 +18.66180099760415,3.6188323023376214,1,0 +20.13069856391754,188.3418959947462,1,0 +12.054277750574983,109.6230274921499,1,0 +6.214665928829927,0.30242000090481097,1,0 +6.947874864102341,2.35184487215146,1,0 +10.530624108791816,0.6630175494110502,1,0 +8.692757705263793,8.376978677493579,1,0 +5.646530583405402,0.5432084571494213,1,0 +6.070121596977114,11.590350178728752,1,0 +15.628345805073621,14.876532398574938,1,0 +16.55123460184084,10.237995525441907,1,0 +19.50404283213429,3.065699264451066,1,0 +16.71311121016275,8.367113669175385,1,0 +13.532307651536538,42.271592770745684,1,0 +5.804817867975216,0.21034197222624693,1,0 +9.914977649648208,0.4146232640151793,1,0 +13.964740060428158,1.022580304125698,1,0 +18.122010761816053,1.6316746059843306,1,0 +21.595123790956567,41.57160041593666,1,0 +9.130071834991686,20.451336353021546,1,0 +17.883641517229844,6.70882447910594,1,0 +8.86125030462863,55.256552519454516,1,0 +23.71192755636759,14.891665515120028,1,0 +21.0864116095053,2.602807642821931,1,0 +5.234433223176747,51.80873421391114,1,0 +12.355004513345193,8.062881362297237,1,0 +16.32400466129649,104.74246474326041,1,0 +15.199989451051223,13.420605821704063,1,0 +5.400283715513069,0.1068007320733198,1,0 +18.14935071819462,57.86990543274337,1,0 +9.5240080884099,5.202694183273143,1,0 +14.32969111907063,0.33513415009633807,1,0 +6.008001209937501,4.253457682070324,1,0 +11.14910464093089,20.25550200201564,1,0 +13.556746559764724,1.2435302503768515,1,0 +10.236793390021194,5.213260482985253,1,0 +11.322802466489374,119.60174680914633,1,0 +14.530812603661325,1.0667000426048996,1,0 +5.1020982340048064,3.4245333163942804,1,0 +7.314199327651877,0.328654059116923,1,0 +19.4196066399687,16.01234343811714,1,0 +14.381803398006594,42.466470255194935,1,0 +12.074857014203443,0.9193428978723392,1,0 +20.405224888108204,45.02975714014151,1,0 +6.226607059054077,16.744643482839557,1,0 +21.448629611744543,13.877128227665889,1,0 +20.498714459638578,9.45360329108919,1,0 +12.330324494559317,11.83982152459994,1,0 +24.8866971301008,6.083719760276822,1,0 +19.372733866032213,4.975035366122659,1,0 +15.272626491943374,3.571305689011856,1,0 +14.022001518663018,148.51836357778757,1,0 +9.898853895401116,13.414624203362388,1,0 +23.420706969690507,1.1696801312693905,1,0 +5.878173451281619,21.871380043098252,1,0 +8.271477013390976,12.537952528645716,1,0 +5.3620031790807845,4.13003089846204,1,0 +24.675452525380532,1.2989572347101652,1,0 +19.139979191967285,3.650184400769608,1,0 +16.828588343400043,9.045227324522026,1,0 +6.1322660373593685,5.6686121041537145,1,0 +7.46597571492428,0.29227237598004685,1,0 +22.877460276011842,7.895071187686354,1,0 +15.47123688296182,11.712728682443833,1,0 +14.618926662688608,7.39879618502388,1,0 +23.591257470285054,0.3957712953309772,1,0 +22.170592850684187,9.160589091901896,1,0 +15.171947125897276,0.9813049184729703,1,0 +23.294820878091265,13.023131238953818,1,0 +7.603521641097031,64.67419662611809,1,0 +17.742809400858825,3.8362135985847514,1,0 +12.97260534381261,13.731640005783678,1,0 +22.386485991929657,16.122372673241486,1,0 +17.767701184938197,8.502546872385196,1,0 +14.09396992968861,3.424687289643619,1,0 +22.886829602175858,13.849075420526427,1,0 +22.219204186077693,0.6199201636963677,1,0 +6.4140649045910685,48.842335731928436,1,0 +16.4297570858174,1.9676577094694774,1,0 +19.548539984759408,4.527445235339861,1,0 +12.0971921578818,3.305790908412635,1,0 +18.132632230157032,6.975496645841378,1,0 +8.20139095328981,16.462593935154327,1,0 +6.525190193327144,13.887489437542769,1,0 +8.95666595408693,8.248347315447893,1,0 +13.164745990717783,17.352544734633533,1,0 +13.276265818502287,4.789920423903067,1,0 +7.63377467695158,9.236545700948609,1,0 +16.031944786100645,5.825786304779309,1,0 +22.211904978640376,19.264730026412938,1,0 +19.8235831067455,7.1876338705643725,1,0 +11.029779852530918,3.3130998580105433,1,0 +7.833583118051756,46.25121112408265,1,0 +16.877484013692012,7.20566711242011,1,0 +9.7542557041673,60.45389027232578,1,0 +21.913753361706622,17.971121548211293,1,0 +11.545350033859723,4.823478566876325,1,0 +8.742028622594662,22.659675391732687,1,0 +22.352864785308483,2.6027545181255265,1,0 +10.012164268346968,20.603663502863423,1,0 +8.684702753715683,20.548530110686198,1,0 +21.40950594700873,2.256843216865951,1,0 +11.435012589835097,34.54541069409913,1,0 +24.01739023054717,0.2516763204050028,1,0 +19.88843441852601,0.2192223568869294,1,0 +7.452256880709902,0.5406861497243327,1,0 +20.01313282513525,0.7138478091273556,1,0 +6.46088475000346,6.452981958122354,1,0 +12.100939345657824,1.3491717314608196,1,0 +5.660066318064928,116.80059064911802,1,0 +6.319223044642713,0.3938430021744164,1,0 +15.469034843193366,3.3012583974347605,1,0 +12.710496124911586,138.5057482227488,1,0 +24.658955325302667,2.353207183688853,1,0 +16.46928218259709,11.045654860621308,1,0 +11.741614707345143,1.7632980658386144,1,0 +9.689651590748689,4.763234657834274,1,0 +17.12848792809993,12.805249004560327,1,0 +5.2688705399795435,8.224969274575887,1,0 +8.491262332685292,4.401220979422432,1,0 +16.59234692601487,11.193561617441004,1,0 +23.239628705466163,5.67907432975904,1,0 +24.21112713415874,33.89149060694316,1,0 +9.143864248790777,31.000960129215116,1,0 +18.62005860896548,10.967321476505209,1,0 +6.6946408120100385,0.4415554396065113,1,0 +21.342589496586005,19.82743526120609,1,0 +6.9124642200395465,0.10746347379202753,1,0 +22.27231394801056,28.949368342688,1,0 +13.312418267093598,0.9229181455987752,1,0 +16.7249852395663,1.1613285697633318,1,0 +17.501915630435104,7.695924810529727,1,0 +18.259261345707344,11.644176460675283,1,0 +11.160432918234727,145.03504585592034,1,0 +17.118957782441285,109.8817229471618,1,0 +8.47241006927099,0.9378783284099254,1,0 +19.945285196653565,3.440824411485631,1,0 +21.16822144939564,33.66307377314436,1,0 +7.517739229700528,30.911800445960633,1,0 +12.282072195331565,2.7537300617849563,1,0 +16.878785826393866,0.5684120787394953,1,0 +15.304765136721544,1.3344215189715252,1,0 +11.487453549692873,0.38751393055204947,1,0 +6.618186843541917,0.5439328060033373,1,0 +8.225977774681523,0.3861067317433062,1,0 +16.669419109139127,2.9790282637905072,1,0 +5.840324585780036,88.05435696157441,1,0 +16.263561883203216,40.64022627335391,1,0 +22.662839108849873,10.469115264931466,1,0 +17.14350036485819,57.450520038917176,1,0 +21.594036219627593,2.138483924937148,1,0 +22.375780253112314,3.8779827715843016,1,0 +24.972427948752884,240.94152711235702,1,0 +24.439436375368384,4.24821367995347,1,0 +8.858424581419676,11.061253725975043,1,0 +14.763361553694121,62.80066029493909,1,0 +22.93601788733853,10.308812976459368,1,0 +17.937910493894016,107.54405157961195,1,0 +10.512343577693681,0.49380681433569906,1,0 +23.552692319697233,8.272246239513672,1,0 +9.871258032494225,62.47367031257801,1,0 +23.434049025606363,9.842580386345913,1,0 +9.972805697214788,0.5443071138542216,1,0 +14.4099062009342,16.25537809402589,1,0 +18.301731050086673,125.2374202058087,1,0 +10.59850838511018,6.9647323603460025,1,0 +5.12000476075802,6.803643406001717,1,0 +14.033608434021007,20.85783664043738,1,0 +22.260595427562947,77.10464694940632,1,0 +19.02213867353275,6.5569292492640185,1,0 +22.436637644183357,1.0547387334508542,1,0 +24.594106075370217,8.085052810223987,1,0 +18.7209564890177,1.0066109624230886,1,0 +20.398048241946377,72.54629069258907,1,0 +9.570277746189385,8.352430818100325,1,0 +6.291652868732344,0.5263481352408378,1,0 +5.422257440031972,22.452043680880333,1,0 +24.292468939193057,7.641537234577375,1,0 +16.641546223214824,122.29361699698815,1,0 +20.79252287973184,1.818971839191018,1,0 +11.91883332696976,18.89973172751371,1,0 +19.817167943427336,108.6399678314898,1,0 +12.618197580147534,7.046752130209921,1,0 +13.234577908264473,6.488345995367068,1,0 +5.302135647288524,0.46262697512944384,1,0 +15.417222518934867,3.4440825663271717,1,0 +8.243256987652275,0.2469591193773287,1,0 +8.358538757294882,16.28374564970406,1,0 +13.131155088143423,2.683890573386235,1,0 +18.65096349133644,18.93268640181452,1,0 +14.111395589723251,8.053535843937587,1,0 +8.226636951696127,3.522963141337888,1,0 +17.11987400162965,88.19942908227847,1,0 +20.246657615741714,5.395786416050076,1,0 +6.981238814452663,0.21417784652198313,1,0 +13.426858937700745,2.6871172292043575,1,0 +8.671863556012976,0.4202748485791038,1,0 +10.189818296292795,9.255719531947252,1,0 +24.91500423284946,3.3490492976803377,1,0 +11.296950261481106,4.9446172226103124,1,0 +9.094418260545936,2.236259020176363,1,0 +24.447839216070715,105.1919285368162,1,0 +7.044594187976326,133.897798911843,1,0 +17.905657404912635,61.07365114044352,1,0 +6.4459468609211035,3.891867950903443,1,0 +7.140811635691207,2.2462164658715005,1,0 +24.835039067449976,1.318394650524733,1,0 +12.11352084027836,7.1619394687741105,1,0 +24.663870682653503,4.485220545542707,1,0 +18.805381185100412,10.846201478336077,1,0 +18.103933567102068,55.88909654807718,1,0 +16.40219703763025,5.710778046851075,1,0 +19.10294913147809,8.663125958899826,1,0 +8.153471444717143,11.907084578109485,1,0 +23.19250596386846,11.226855395465268,1,0 +9.794805060043,20.377323689411824,1,0 +18.577059037559664,7.876111184063263,1,0 +9.929961979181972,0.21808574007539205,1,0 +17.907606488969176,46.84313067247106,1,0 +7.512574235142674,1.2410892270317544,1,0 +18.564713431389535,2.7939756718499926,1,0 +16.243804919954854,9.827553876791853,1,0 +9.734705721607897,29.552745887399343,1,0 +17.00735207845224,3.1602010515290733,1,0 +16.498937073070557,2.393567993161047,1,0 +8.474229699056595,339.2439631570457,1,0 +7.911759055452421,20.745180660642514,1,0 +5.650105139112566,2.2269015276214117,1,0 +16.682997709759512,2.2854253922873333,1,0 +10.040948300289456,3.769238605820583,1,0 +11.751362915544306,2.5721588835520763,1,0 +16.698139302914498,362.31089340871006,1,0 +23.60314934886992,1.5697263636920842,1,0 +18.505440982459113,5.50569708709474,1,0 +10.345065695403608,4.279931988659079,1,0 +13.241195197852793,5.745475153783466,1,0 +5.839734264251311,0.2794844095295774,1,0 +24.421932653672993,68.4812974514429,1,0 +22.119193473169577,131.44614861632078,1,0 +22.439062414739745,4.139797320116404,1,0 +20.387857541604898,4.254342211076884,1,0 +19.92975823339075,3.646733833673261,1,0 +20.73744781356072,6.055440883904513,1,0 +13.879481800596695,2.251044010833685,1,0 +22.69943269053241,19.149669764823027,1,0 +13.047072956713382,2.568307781561121,1,0 +8.523686322341673,66.12028807917824,1,0 +9.975190766723827,0.28790407565273357,1,0 +8.027909575235098,7.35500579237199,1,0 +24.655366015513426,211.5072448486257,1,0 +11.20307204788085,4.964232879651448,1,0 +24.190164362136272,9.822881946767458,1,0 +6.1922796624898915,14.247590259785603,1,0 +15.669752577906474,15.618640578784472,1,0 +22.382196282127406,0.7859075601950598,1,0 +16.052690761548,4.8296750376422874,1,0 +5.915860147546045,48.139918113281574,1,0 +11.81061854854459,7.1281769629209935,1,0 +14.015828219896648,0.13573998880281524,1,0 +7.431495992934797,0.37450843910013004,1,0 +19.923467897984665,2.440832996427016,1,0 +12.44953237198526,8.514859411732703,1,0 +22.428595045106483,9.261422943511345,1,0 +16.778118212416302,5.835487608621614,1,0 +6.7553538876795205,6.535618439472757,1,0 +5.0543314511259085,58.329261327697,1,0 +19.43324172498658,4.237097478936809,1,0 +20.204852687481324,123.75122256146936,1,0 +20.101731674443,0.8541755463621377,1,0 +22.16961159717757,17.36123999906768,1,0 +23.97771324119065,2.685811640658291,1,0 +20.131111203478646,13.782789773628837,1,0 +19.364293539721984,20.730328060584736,1,0 +8.433435830341185,20.569649750167557,1,0 +13.154174597824458,5.0048793843328925,1,0 +20.58528368714964,37.42447437671203,1,0 +16.676828767403492,2.7176864279107784,1,0 +20.40311110753799,1.5125321969147605,1,0 +24.438707370122426,11.871977395955971,1,0 +24.499177343200426,1.5853488345014415,1,0 +17.619299126050898,2.160653698482232,1,0 +18.967017157601656,3.2374255118545636,1,0 +10.367844299315475,14.406805403973548,1,0 +19.962527324284892,15.310513160256331,1,0 +9.596984715212603,10.766880305087257,1,0 +7.65009101618547,35.08011691700428,1,0 +19.12402804651763,11.245023984069409,1,0 +16.247352499428672,10.542595990875977,1,0 +7.703943117889576,11.12352422804777,1,0 +22.356990454851182,96.03600290126133,1,0 +5.007991187849548,0.2010806182473784,1,0 +22.82140493838815,1.0459034957897746,1,0 +16.23182717447402,2.99259378346059,1,0 +18.736492407124025,2.5915769826763735,1,0 +10.910937108383514,4.395020318112908,1,0 +13.125181132385041,40.182192742926475,1,0 +22.04591965168016,5.443096914089298,1,0 +10.746898463869002,7.264709592107561,1,0 +23.39727642617654,0.9134858169008289,1,0 +23.82180951814167,8.345746201910687,1,0 +20.294164107756224,74.33267750731812,1,0 +7.580912369366269,0.8148531682486984,1,0 +22.425089465896598,12.591426332874253,1,0 +15.768704459692817,16.11025929404548,1,0 +6.190363130499609,5.467662341820384,1,0 +6.568506926300469,3.118361150747353,1,0 +6.930673103081062,21.536361211756756,1,0 +7.997625206736847,0.4237399932364485,1,0 +7.989061863031238,0.13966866814590087,1,0 +15.964435310009867,24.288809722014175,1,0 +20.517173463932703,18.789169629394845,1,0 +21.3190089920233,33.754128570432506,1,0 +22.04383672901662,13.117345414180015,1,0 +18.52815235057613,2.403431593325305,1,0 +8.564683620526921,0.4521597663765857,1,0 +5.618131912262179,14.61285823017511,1,0 +16.645846898511515,1.3509187686305328,1,0 +14.481577743072993,6.2361359034504975,1,0 +20.601615106265527,4.0788895486509285,1,0 +11.461415182610509,15.448324675690252,1,0 +7.458448670948855,46.13711804394988,1,0 +17.53186665907269,11.5716407261537,1,0 +12.13459018145455,22.805226164830014,1,0 +11.981919827128294,1.8859293339586443,1,0 +5.115686897188425,7.970592829575984,1,0 +23.277650994264985,1.9412806136864829,1,0 +14.422504162413533,11.218574831836476,1,0 +12.974873013647738,2.611829555049219,1,0 +12.638759864945897,70.12567400469509,1,0 +13.439484345496165,2.153842016196436,1,0 +24.720311208867933,7.405978197946909,1,0 diff --git a/inst/extdata/typhoidcontrols.csv b/inst/extdata/typhoidcontrols.csv new file mode 100644 index 00000000..1a99c2b8 --- /dev/null +++ b/inst/extdata/typhoidcontrols.csv @@ -0,0 +1,273 @@ +antigen_iso,elisa,Age,pop,nu +HlyE_IgG,0.504284062,19,CA Facts,3.4164005844 +HlyE_IgG,0.896588964,19,CA Facts,3.4164005844 +HlyE_IgG,0.151240564,12,CA Facts,3.4164005844 +HlyE_IgG,0.72769279,21,CA Facts,3.4164005844 +HlyE_IgG,1.097996878,24,CA Facts,3.4164005844 +HlyE_IgG,1.687330142,23,CA Facts,3.4164005844 +HlyE_IgG,1.532087869,12,CA Facts,3.4164005844 +HlyE_IgG,2.175263872,21,CA Facts,3.4164005844 +HlyE_IgG,0.434726455,3,CA Facts,3.4164005844 +HlyE_IgG,0.0730269,5,CA Facts,3.4164005844 +HlyE_IgG,0.188131858,16,CA Facts,3.4164005844 +HlyE_IgG,0.787666904,24,CA Facts,3.4164005844 +HlyE_IgG,0.796838203,22,CA Facts,3.4164005844 +HlyE_IgG,0.967074005,15,CA Facts,3.4164005844 +HlyE_IgG,1.042711462,13,CA Facts,3.4164005844 +HlyE_IgG,1.603139676,12,CA Facts,3.4164005844 +HlyE_IgG,0.930491856,15,CA Facts,3.4164005844 +HlyE_IgG,0.617688723,16,CA Facts,3.4164005844 +HlyE_IgG,0.954399063,24,CA Facts,3.4164005844 +HlyE_IgG,2.117556821,24,CA Facts,3.4164005844 +HlyE_IgG,1.495969437,13,CA Facts,3.4164005844 +HlyE_IgG,0.759637765,24,CA Facts,3.4164005844 +HlyE_IgG,2.264194561,16,CA Facts,3.4164005844 +HlyE_IgG,2.132756446,13,CA Facts,3.4164005844 +HlyE_IgG,0,20,CA Facts,3.4164005844 +HlyE_IgG,1.158383186,17,CA Facts,3.4164005844 +HlyE_IgG,1.73035281,13,CA Facts,3.4164005844 +HlyE_IgG,1.513590698,23,CA Facts,3.4164005844 +HlyE_IgG,0.434726455,3,CA Facts,3.4164005844 +HlyE_IgG,1.264640688,20,CA Facts,3.4164005844 +HlyE_IgG,2.184069357,20,CA Facts,3.4164005844 +HlyE_IgG,1.021260968,20,CA Facts,3.4164005844 +HlyE_IgG,0.001337828,21,CA Facts,3.4164005844 +HlyE_IgG,2.148184096,21,CA Facts,3.4164005844 +HlyE_IgG,2.982778747,20,CA Facts,3.4164005844 +HlyE_IgG,1.424865234,20,CA Facts,3.4164005844 +HlyE_IgG,3.39320331,15,CA Facts,3.4164005844 +HlyE_IgG,0.912555907,15,CA Facts,3.4164005844 +HlyE_IgG,1.262489671,17,CA Facts,3.4164005844 +HlyE_IgG,1.397111866,23,CA Facts,3.4164005844 +HlyE_IgG,0.273939903,18,CA Facts,3.4164005844 +HlyE_IgG,2.554201697,16,CA Facts,3.4164005844 +HlyE_IgG,2.374460606,17,CA Facts,3.4164005844 +HlyE_IgG,1.826003699,23,CA Facts,3.4164005844 +HlyE_IgG,2.673347061,24,CA Facts,3.4164005844 +HlyE_IgG,2.800519392,3,CA Facts,3.4164005844 +HlyE_IgG,1.261335467,19,CA Facts,3.4164005844 +HlyE_IgG,0.881969492,22,CA Facts,3.4164005844 +HlyE_IgG,1.316160172,20,CA Facts,3.4164005844 +HlyE_IgG,1.633408969,16,CA Facts,3.4164005844 +HlyE_IgG,1.797778157,22,CA Facts,3.4164005844 +HlyE_IgG,1.456186142,19,CA Facts,3.4164005844 +HlyE_IgG,1.874899991,21,CA Facts,3.4164005844 +HlyE_IgG,1.696208176,20,CA Facts,3.4164005844 +HlyE_IgG,2.278399328,17,CA Facts,3.4164005844 +HlyE_IgG,2.045512375,11,CA Facts,3.4164005844 +HlyE_IgG,1.408024343,18,CA Facts,3.4164005844 +HlyE_IgG,1.106042522,15,CA Facts,3.4164005844 +HlyE_IgA,0.276242749,19,CA Facts,2.5923024875499996 +HlyE_IgA,1.937127722,19,CA Facts,2.5923024875499996 +HlyE_IgA,0.562306668,12,CA Facts,2.5923024875499996 +HlyE_IgA,0.379365042,21,CA Facts,2.5923024875499996 +HlyE_IgA,1.513495985,24,CA Facts,2.5923024875499996 +HlyE_IgA,1.799881325,23,CA Facts,2.5923024875499996 +HlyE_IgA,1.059382905,12,CA Facts,2.5923024875499996 +HlyE_IgA,1.1683490450563947,21,CA Facts,2.5923024875499996 +HlyE_IgA,0.592305881,5,CA Facts,2.5923024875499996 +HlyE_IgA,0.919350867,16,CA Facts,2.5923024875499996 +HlyE_IgA,2.185531916,24,CA Facts,2.5923024875499996 +HlyE_IgA,1.412570063,22,CA Facts,2.5923024875499996 +HlyE_IgA,0.697410264,15,CA Facts,2.5923024875499996 +HlyE_IgA,1.135184487,13,CA Facts,2.5923024875499996 +HlyE_IgA,0.564128049,12,CA Facts,2.5923024875499996 +HlyE_IgA,1.252074276,15,CA Facts,2.5923024875499996 +HlyE_IgA,1.217414471,24,CA Facts,2.5923024875499996 +HlyE_IgA,0.731641509,13,CA Facts,2.5923024875499996 +HlyE_IgA,0.5945541577062996,24,CA Facts,2.5923024875499996 +HlyE_IgA,0.723338155,16,CA Facts,2.5923024875499996 +HlyE_IgA,0.809746601,13,CA Facts,2.5923024875499996 +HlyE_IgA,2.0283502017645163,17,CA Facts,2.5923024875499996 +HlyE_IgA,0.7396406621645746,13,CA Facts,2.5923024875499996 +HlyE_IgA,0.5610772799170483,23,CA Facts,2.5923024875499996 +HlyE_IgA,0.19968326529087227,3,CA Facts,2.5923024875499996 +HlyE_IgA,1.370303315,20,CA Facts,2.5923024875499996 +HlyE_IgA,2.917084141,20,CA Facts,2.5923024875499996 +HlyE_IgA,0.71165989,20,CA Facts,2.5923024875499996 +HlyE_IgA,0.958671263,21,CA Facts,2.5923024875499996 +HlyE_IgA,1.120881291,21,CA Facts,2.5923024875499996 +HlyE_IgA,0.531503905,20,CA Facts,2.5923024875499996 +HlyE_IgA,0.563270928,20,CA Facts,2.5923024875499996 +HlyE_IgA,0.958403413,15,CA Facts,2.5923024875499996 +HlyE_IgA,0.251171978,15,CA Facts,2.5923024875499996 +HlyE_IgA,0.288938844,17,CA Facts,2.5923024875499996 +HlyE_IgA,0.850727668,23,CA Facts,2.5923024875499996 +HlyE_IgA,1.080596634,18,CA Facts,2.5923024875499996 +HlyE_IgA,1.138505829,16,CA Facts,2.5923024875499996 +HlyE_IgA,1.350857397,17,CA Facts,2.5923024875499996 +HlyE_IgA,0.561717398,23,CA Facts,2.5923024875499996 +HlyE_IgA,0.681928528,24,CA Facts,2.5923024875499996 +HlyE_IgA,0.511950847,3,CA Facts,2.5923024875499996 +HlyE_IgA,2.582539351,19,CA Facts,2.5923024875499996 +HlyE_IgA,0.513075817,22,CA Facts,2.5923024875499996 +HlyE_IgA,0.383168513,20,CA Facts,2.5923024875499996 +HlyE_IgA,0.819067785,16,CA Facts,2.5923024875499996 +HlyE_IgA,1.147184172,22,CA Facts,2.5923024875499996 +HlyE_IgA,0.772247586,19,CA Facts,2.5923024875499996 +HlyE_IgA,1.748507673,21,CA Facts,2.5923024875499996 +HlyE_IgA,0.818639225,20,CA Facts,2.5923024875499996 +HlyE_IgA,0.916190236,17,CA Facts,2.5923024875499996 +HlyE_IgA,0.089336941,11,CA Facts,2.5923024875499996 +HlyE_IgA,1.28630552,18,CA Facts,2.5923024875499996 +HlyE_IgA,1.5566087048743056,15,CA Facts,2.5923024875499996 +HlyE_IgA,0.1683,1,MGH,2.8698349999999992 +HlyE_IgA,0.2021,1,MGH,2.8698349999999992 +HlyE_IgA,0.3021,1,MGH,2.8698349999999992 +HlyE_IgA,0.9178,1,MGH,2.8698349999999992 +HlyE_IgA,1.3399,1,MGH,2.8698349999999992 +HlyE_IgA,0.3404,1,MGH,2.8698349999999992 +HlyE_IgA,0.204,1,MGH,2.8698349999999992 +HlyE_IgA,0.8418,1,MGH,2.8698349999999992 +HlyE_IgA,0.0014,1,MGH,2.8698349999999992 +HlyE_IgA,0.0014,1,MGH,2.8698349999999992 +HlyE_IgA,0.0014,1,MGH,2.8698349999999992 +HlyE_IgA,0.0014,1.5,MGH,2.8698349999999992 +HlyE_IgA,0.0014,1.5,MGH,2.8698349999999992 +HlyE_IgA,0.0326,1.5,MGH,2.8698349999999992 +HlyE_IgA,0.2651,1.5,MGH,2.8698349999999992 +HlyE_IgA,0.9438,1.5,MGH,2.8698349999999992 +HlyE_IgA,0.2911,2,MGH,2.8698349999999992 +HlyE_IgA,0.0014,2,MGH,2.8698349999999992 +HlyE_IgA,0.0014,2,MGH,2.8698349999999992 +HlyE_IgA,1.1828,2,MGH,2.8698349999999992 +HlyE_IgA,0.0014,2,MGH,2.8698349999999992 +HlyE_IgA,0.0014,2,MGH,2.8698349999999992 +HlyE_IgA,2.5064,2,MGH,2.8698349999999992 +HlyE_IgA,1.3734,2,MGH,2.8698349999999992 +HlyE_IgA,0.0014,2,MGH,2.8698349999999992 +HlyE_IgA,0.0014,2.5,MGH,2.8698349999999992 +HlyE_IgA,0.0014,2.5,MGH,2.8698349999999992 +HlyE_IgA,0.4684,2.5,MGH,2.8698349999999992 +HlyE_IgA,5.0821,2.5,MGH,2.8698349999999992 +HlyE_IgA,1.0545,2.5,MGH,2.8698349999999992 +HlyE_IgA,0.2768,2.5,MGH,2.8698349999999992 +HlyE_IgA,0.5833,3,MGH,2.8698349999999992 +HlyE_IgA,0.0014,3,MGH,2.8698349999999992 +HlyE_IgA,0.0014,3,MGH,2.8698349999999992 +HlyE_IgA,0.0014,3,MGH,2.8698349999999992 +HlyE_IgA,0.8376,3,MGH,2.8698349999999992 +HlyE_IgA,0.0014,3,MGH,2.8698349999999992 +HlyE_IgA,0.0014,3,MGH,2.8698349999999992 +HlyE_IgA,0.2274,3,MGH,2.8698349999999992 +HlyE_IgA,0.8899,3,MGH,2.8698349999999992 +HlyE_IgA,0.557,3,MGH,2.8698349999999992 +HlyE_IgA,0.0014,4,MGH,2.8698349999999992 +HlyE_IgA,0.0014,4,MGH,2.8698349999999992 +HlyE_IgA,0.8632,4,MGH,2.8698349999999992 +HlyE_IgA,0.1381,4,MGH,2.8698349999999992 +HlyE_IgA,0.1391,4,MGH,2.8698349999999992 +HlyE_IgA,0.6911,4,MGH,2.8698349999999992 +HlyE_IgA,0.7057,5,MGH,2.8698349999999992 +HlyE_IgA,0.0014,2,MGH,2.8698349999999992 +HlyE_IgA,0.0014,3,MGH,2.8698349999999992 +HlyE_IgA,0.1992,3,MGH,2.8698349999999992 +HlyE_IgA,0.5021,3,MGH,2.8698349999999992 +HlyE_IgA,0.0014,4,MGH,2.8698349999999992 +HlyE_IgA,0.6346,4,MGH,2.8698349999999992 +HlyE_IgA,0.0014,4,MGH,2.8698349999999992 +HlyE_IgA,1.1055,5,MGH,2.8698349999999992 +HlyE_IgA,0.9074,5,MGH,2.8698349999999992 +HlyE_IgA,0.0014,5,MGH,2.8698349999999992 +HlyE_IgA,0.0014,5,MGH,2.8698349999999992 +HlyE_IgA,0.0014,5,MGH,2.8698349999999992 +HlyE_IgA,0.4206,5,MGH,2.8698349999999992 +HlyE_IgA,1.5539,5,MGH,2.8698349999999992 +HlyE_IgA,0.0014,6,MGH,2.8698349999999992 +HlyE_IgA,1.3351,8,MGH,2.8698349999999992 +HlyE_IgA,0.4021,8,MGH,2.8698349999999992 +HlyE_IgA,2.1605,9,MGH,2.8698349999999992 +HlyE_IgA,0.3284,10,MGH,2.8698349999999992 +HlyE_IgA,1.8111,12,MGH,2.8698349999999992 +HlyE_IgA,2.8561,12,MGH,2.8698349999999992 +HlyE_IgA,4.1355,12,MGH,2.8698349999999992 +HlyE_IgA,0.7522,14,MGH,2.8698349999999992 +HlyE_IgA,1.7748,14,MGH,2.8698349999999992 +HlyE_IgA,0.0014,14,MGH,2.8698349999999992 +HlyE_IgA,0.3076,15,MGH,2.8698349999999992 +HlyE_IgA,2.4901,16,MGH,2.8698349999999992 +HlyE_IgA,4.1349,16,MGH,2.8698349999999992 +HlyE_IgA,0.9068,16,MGH,2.8698349999999992 +HlyE_IgA,1.1584,17,MGH,2.8698349999999992 +HlyE_IgA,3.1308,18,MGH,2.8698349999999992 +HlyE_IgA,1.9397,18,MGH,2.8698349999999992 +HlyE_IgG,0.0397,1,MGH,1.0753849999999998 +HlyE_IgG,0.5542,1,MGH,1.0753849999999998 +HlyE_IgG,0.1087,1,MGH,1.0753849999999998 +HlyE_IgG,0.3668,1,MGH,1.0753849999999998 +HlyE_IgG,0.1377,1,MGH,1.0753849999999998 +HlyE_IgG,0.132,1,MGH,1.0753849999999998 +HlyE_IgG,0.2084,1,MGH,1.0753849999999998 +HlyE_IgG,0.6085,1,MGH,1.0753849999999998 +HlyE_IgG,0.005,1,MGH,1.0753849999999998 +HlyE_IgG,0.2843,1,MGH,1.0753849999999998 +HlyE_IgG,0.1733,1,MGH,1.0753849999999998 +HlyE_IgG,0.1422,1.5,MGH,1.0753849999999998 +HlyE_IgG,0.1528,1.5,MGH,1.0753849999999998 +HlyE_IgG,0.0014,1.5,MGH,1.0753849999999998 +HlyE_IgG,0.0014,1.5,MGH,1.0753849999999998 +HlyE_IgG,0.2614,1.5,MGH,1.0753849999999998 +HlyE_IgG,0.3541,2,MGH,1.0753849999999998 +HlyE_IgG,0.0838,2,MGH,1.0753849999999998 +HlyE_IgG,0.0879,2,MGH,1.0753849999999998 +HlyE_IgG,0.0014,2,MGH,1.0753849999999998 +HlyE_IgG,0.0169,2,MGH,1.0753849999999998 +HlyE_IgG,0.1969,2,MGH,1.0753849999999998 +HlyE_IgG,0.2206,2,MGH,1.0753849999999998 +HlyE_IgG,0.1577,2,MGH,1.0753849999999998 +HlyE_IgG,0.7192,2,MGH,1.0753849999999998 +HlyE_IgG,0.1782,2.5,MGH,1.0753849999999998 +HlyE_IgG,0.192,2.5,MGH,1.0753849999999998 +HlyE_IgG,0.0014,2.5,MGH,1.0753849999999998 +HlyE_IgG,1.2961,2.5,MGH,1.0753849999999998 +HlyE_IgG,0.0014,2.5,MGH,1.0753849999999998 +HlyE_IgG,0.0014,2.5,MGH,1.0753849999999998 +HlyE_IgG,3.1216,3,MGH,1.0753849999999998 +HlyE_IgG,0.0014,3,MGH,1.0753849999999998 +HlyE_IgG,0.0014,3,MGH,1.0753849999999998 +HlyE_IgG,0.0565,3,MGH,1.0753849999999998 +HlyE_IgG,0.0014,3,MGH,1.0753849999999998 +HlyE_IgG,0.0687,3,MGH,1.0753849999999998 +HlyE_IgG,0.0348,3,MGH,1.0753849999999998 +HlyE_IgG,0.1206,3,MGH,1.0753849999999998 +HlyE_IgG,0.1422,3,MGH,1.0753849999999998 +HlyE_IgG,0.3431,3,MGH,1.0753849999999998 +HlyE_IgG,0.3999,4,MGH,1.0753849999999998 +HlyE_IgG,0.4093,4,MGH,1.0753849999999998 +HlyE_IgG,0.3133,4,MGH,1.0753849999999998 +HlyE_IgG,0.1206,4,MGH,1.0753849999999998 +HlyE_IgG,0.1226,4,MGH,1.0753849999999998 +HlyE_IgG,1.1568,4,MGH,1.0753849999999998 +HlyE_IgG,0.1998,5,MGH,1.0753849999999998 +HlyE_IgG,0.3223,2,MGH,1.0753849999999998 +HlyE_IgG,0.1545,3,MGH,1.0753849999999998 +HlyE_IgG,0.0785,3,MGH,1.0753849999999998 +HlyE_IgG,0.1161,3,MGH,1.0753849999999998 +HlyE_IgG,0.0471,4,MGH,1.0753849999999998 +HlyE_IgG,0.0014,4,MGH,1.0753849999999998 +HlyE_IgG,0.0414,4,MGH,1.0753849999999998 +HlyE_IgG,0.3137,5,MGH,1.0753849999999998 +HlyE_IgG,0.2925,5,MGH,1.0753849999999998 +HlyE_IgG,0.1218,5,MGH,1.0753849999999998 +HlyE_IgG,0.0508,5,MGH,1.0753849999999998 +HlyE_IgG,0.4076,5,MGH,1.0753849999999998 +HlyE_IgG,0.1243,5,MGH,1.0753849999999998 +HlyE_IgG,0.927,5,MGH,1.0753849999999998 +HlyE_IgG,0.3476,6,MGH,1.0753849999999998 +HlyE_IgG,0.2929,8,MGH,1.0753849999999998 +HlyE_IgG,0.4044,8,MGH,1.0753849999999998 +HlyE_IgG,0.3513,9,MGH,1.0753849999999998 +HlyE_IgG,0.4513,10,MGH,1.0753849999999998 +HlyE_IgG,0.3435,12,MGH,1.0753849999999998 +HlyE_IgG,0.0822,12,MGH,1.0753849999999998 +HlyE_IgG,1.3079,12,MGH,1.0753849999999998 +HlyE_IgG,0.0626,14,MGH,1.0753849999999998 +HlyE_IgG,0.5591,14,MGH,1.0753849999999998 +HlyE_IgG,0.3619,14,MGH,1.0753849999999998 +HlyE_IgG,0.1096,15,MGH,1.0753849999999998 +HlyE_IgG,0.0736,16,MGH,1.0753849999999998 +HlyE_IgG,1.0711,16,MGH,1.0753849999999998 +HlyE_IgG,0.3043,16,MGH,1.0753849999999998 +HlyE_IgG,0.0597,17,MGH,1.0753849999999998 +HlyE_IgG,0.3819,18,MGH,1.0753849999999998 +HlyE_IgG,0.5264,18,MGH,1.0753849999999998 diff --git a/man/dot-nll.Rd b/man/dot-nll.Rd index 253cce61..3d709752 100644 --- a/man/dot-nll.Rd +++ b/man/dot-nll.Rd @@ -5,38 +5,30 @@ \title{Calculate log-likelihood} \usage{ .nll( - stratumData, - antibodies, - params, - censorLimits, - ivc = FALSE, - m = 0, - par0, - start + log.lambda, + data, + antigen_isos, + curve_params, + noise_params, + verbose = FALSE, + ... ) } \arguments{ -\item{stratumData}{Data frame with cross-sectional serology data per antibody and age, and additional -columns, for one stratum} +\item{log.lambda}{natural logarithm of incidence parameter, in log(years). Value of -6 corresponds roughly to 1 day (log(1/365.25)), -4 corresponds roughly to 1 week (log(7 / 365.25)).} -\item{antibodies}{Character vector with one or more antibody names. Values must match \code{data}.} +\item{data}{Data frame with cross-sectional serology data per antibody and age, and additional columns} -\item{params}{List of data frames of all longitudinal parameters. Each data frame contains -Monte Carlo samples for each antibody type.} - -\item{censorLimits}{List of cutoffs for one or more named antibody types (corresponding to -\code{stratumData}).} +\item{antigen_isos}{Character vector with one or more antibody names. Values must match \code{data}.} -\item{ivc}{If \code{ivc = TRUE}, the biomarker data are interval-censored.} +\item{curve_params}{List of data frames of all longitudinal parameters. Each data frame contains +Monte Carlo samples for each antibody type.} -\item{m}{this parameter's meaning is uncertain} +\item{noise_params}{a \code{\link[=list]{list()}} (or \code{\link[=data.frame]{data.frame()}}, or \code{\link[=tibble]{tibble()}}) containing noise parameters} -\item{par0}{List of parameters for the (lognormal) distribution of antibody concentrations -for true seronegatives (i.e. those who never seroconverted), by named antibody type -(corresponding to \code{data}).} +\item{verbose}{logical: if TRUE, print verbose log information to console} -\item{start}{starting value for \code{log(lambda)}. Value of -6 corresponds roughly to 1 day -(log(1/365.25)), -4 corresponds roughly to 1 week (log(7 / 365.25)). Default = -6.} +\item{...}{additional arguments passed to other functions (not currently used).} } \value{ the log-likelihood of the data with the current parameter values diff --git a/man/dot-optNll.Rd b/man/dot-optNll.Rd new file mode 100644 index 00000000..4de18b09 --- /dev/null +++ b/man/dot-optNll.Rd @@ -0,0 +1,91 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/optNll.R +\name{.optNll} +\alias{.optNll} +\title{Find the maximum likelihood estimate of the incidence rate parameter} +\usage{ +.optNll( + data = dataList$data, + curve_params = dataList$curve_params, + noise_params = dataList$noise_params, + dataList = NULL, + antigen_isos = unique(pull(data, "antigen_iso")), + lambda.start = 1/365.25, + hessian = TRUE, + verbose = FALSE, + ... +) +} +\arguments{ +\item{data}{Data frame with cross-sectional serology data per antibody and age, and additional columns} + +\item{curve_params}{List of data frames of all longitudinal parameters. Each data frame contains +Monte Carlo samples for each antibody type.} + +\item{noise_params}{a \code{\link[=list]{list()}} (or \code{\link[=data.frame]{data.frame()}}, or \code{\link[=tibble]{tibble()}}) containing noise parameters} + +\item{dataList}{Optional argument; as an alternative to passing in \code{data}, \code{curve_params}, and \code{noise_params} individually, you may create a list containing these three elements (with these names) and pass that in instead. This option may be useful for parallel processing across strata.} + +\item{antigen_isos}{Character vector with one or more antibody names. Values must match \code{data}} + +\item{lambda.start}{starting guess for incidence rate, in years/event.} + +\item{hessian}{if \code{TRUE}, the hessian of \code{f} + at the minimum is returned.} + +\item{verbose}{logical: if TRUE, print verbose log information to console} + +\item{...}{ + Arguments passed on to \code{\link[=.nll]{.nll}}, \code{\link[stats:nlm]{stats::nlm}} + \describe{ + \item{\code{log.lambda}}{natural logarithm of incidence parameter, in log(years). Value of -6 corresponds roughly to 1 day (log(1/365.25)), -4 corresponds roughly to 1 week (log(7 / 365.25)).} + \item{\code{f}}{the function to be minimized, returning a single numeric + value. This should be a function with first argument a vector of + the length of \code{p} followed by any other arguments specified by + the \code{\dots} argument. + + If the function value has an attribute called \code{gradient} or + both \code{gradient} and \code{hessian} attributes, these will be + used in the calculation of updated parameter values. Otherwise, + numerical derivatives are used. \code{\link[stats]{deriv}} returns a + function with suitable \code{gradient} attribute and optionally a + \code{hessian} attribute.} + \item{\code{p}}{starting parameter values for the minimization.} + \item{\code{typsize}}{an estimate of the size of each parameter + at the minimum.} + \item{\code{fscale}}{an estimate of the size of \code{f} at the minimum.} + \item{\code{print.level}}{this argument determines the level of printing + which is done during the minimization process. The default + value of \code{0} means that no printing occurs, a value of \code{1} + means that initial and final details are printed and a value + of 2 means that full tracing information is printed.} + \item{\code{ndigit}}{the number of significant digits in the function \code{f}.} + \item{\code{gradtol}}{a positive scalar giving the tolerance at which the + scaled gradient is considered close enough to zero to + terminate the algorithm. The scaled gradient is a + measure of the relative change in \code{f} in each direction + \code{p[i]} divided by the relative change in \code{p[i]}.} + \item{\code{stepmax}}{a positive scalar which gives the maximum allowable + scaled step length. \code{stepmax} is used to prevent steps which + would cause the optimization function to overflow, to prevent the + algorithm from leaving the area of interest in parameter space, or to + detect divergence in the algorithm. \code{stepmax} would be chosen + small enough to prevent the first two of these occurrences, but should + be larger than any anticipated reasonable step.} + \item{\code{steptol}}{A positive scalar providing the minimum allowable + relative step length.} + \item{\code{iterlim}}{a positive integer specifying the maximum number of + iterations to be performed before the program is terminated.} + \item{\code{check.analyticals}}{a logical scalar specifying whether the + analytic gradients and Hessians, if they are supplied, should be + checked against numerical derivatives at the initial parameter + values. This can help detect incorrectly formulated gradients or + Hessians.} + }} +} +\value{ +a \code{\link[stats:nlm]{stats::nlm()}} fit object +} +\description{ +Find the maximum likelihood estimate of the incidence rate parameter +} diff --git a/man/est.incidence.Rd b/man/est.incidence.Rd new file mode 100644 index 00000000..c92f3e8c --- /dev/null +++ b/man/est.incidence.Rd @@ -0,0 +1,89 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/est.incidence.R +\name{est.incidence} +\alias{est.incidence} +\title{Age specific seroincidence function +add some details here} +\usage{ +est.incidence( + dpop, + dmcmc, + noise_params, + c.age = NULL, + antigen_isos = unique(dpop$antigen_iso), + start = 0.1, + iterlim = 100, + coverage = 0.95, + verbose = FALSE, + ... +) +} +\arguments{ +\item{dpop}{cross-sectional population data} + +\item{dmcmc}{mcmc samples from distribution of longitudinal decay curve parameters} + +\item{noise_params}{a \code{\link[=data.frame]{data.frame()}} containing columns \code{nu}, etc. specifying conditional noise parameters} + +\item{c.age}{age category} + +\item{antigen_isos}{antigen-isotype(s) (a \code{\link[=character]{character()}} vector of one or more antigen names)} + +\item{start}{starting value for incidence rate} + +\item{iterlim}{a positive integer specifying the maximum number of iterations to be performed before the program is terminated.} + +\item{coverage}{desired confidence interval coverage probability} + +\item{verbose}{logical: if TRUE, print verbose log information to console} + +\item{...}{ + Arguments passed on to \code{\link[stats:nlm]{stats::nlm}} + \describe{ + \item{\code{typsize}}{an estimate of the size of each parameter + at the minimum.} + \item{\code{fscale}}{an estimate of the size of \code{f} at the minimum.} + \item{\code{print.level}}{this argument determines the level of printing + which is done during the minimization process. The default + value of \code{0} means that no printing occurs, a value of \code{1} + means that initial and final details are printed and a value + of 2 means that full tracing information is printed.} + \item{\code{ndigit}}{the number of significant digits in the function \code{f}.} + \item{\code{gradtol}}{a positive scalar giving the tolerance at which the + scaled gradient is considered close enough to zero to + terminate the algorithm. The scaled gradient is a + measure of the relative change in \code{f} in each direction + \code{p[i]} divided by the relative change in \code{p[i]}.} + \item{\code{stepmax}}{a positive scalar which gives the maximum allowable + scaled step length. \code{stepmax} is used to prevent steps which + would cause the optimization function to overflow, to prevent the + algorithm from leaving the area of interest in parameter space, or to + detect divergence in the algorithm. \code{stepmax} would be chosen + small enough to prevent the first two of these occurrences, but should + be larger than any anticipated reasonable step.} + \item{\code{steptol}}{A positive scalar providing the minimum allowable + relative step length.} + \item{\code{check.analyticals}}{a logical scalar specifying whether the + analytic gradients and Hessians, if they are supplied, should be + checked against numerical derivatives at the initial parameter + values. This can help detect incorrectly formulated gradients or + Hessians.} + }} +} +\value{ +A \code{\link[=data.frame]{data.frame()}} containing the following: +\itemize{ +\item \code{est.start}: the starting guess for incidence rate +\item \code{ageCat}: the age category we are analyzing +\item \code{incidence.rate}: the estimated incidence rate, per person year +\item \code{CI.lwr}: lower limit of confidence interval for incidence rate +\item \code{CI.upr}: upper limit of confidence interval for incidence rate +\item \code{coverage}: coverage probability +\item \code{neg.llik}: negative log-likelihood +\item \code{iterations}: the number of iterations used +} +} +\description{ +Age specific seroincidence function +add some details here +} diff --git a/man/est.incidence.by.Rd b/man/est.incidence.by.Rd new file mode 100644 index 00000000..94588bf9 --- /dev/null +++ b/man/est.incidence.by.Rd @@ -0,0 +1,55 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/est.incidence.by.R +\name{est.incidence.by} +\alias{est.incidence.by} +\title{Estimate Seroincidence} +\usage{ +est.incidence.by( + data, + curve_params, + noise_params, + strata = "", + curve_strata_varnames = strata, + noise_strata_varnames = strata, + numCores = 1L, + antigen_isos = unique(pull(data, "antigen_iso")), + verbose = FALSE, + ... +) +} +\arguments{ +\item{data}{Data frame with cross-sectional serology data per antibody and age, and additional columns to identify possible \code{strata}.} + +\item{curve_params}{List of data frames of all longitudinal parameters. Each data frame contains +Monte Carlo samples for each antibody type.} + +\item{noise_params}{a \code{\link[=list]{list()}} (or \code{\link[=data.frame]{data.frame()}}, or \code{\link[=tibble]{tibble()}}) containing noise parameters} + +\item{strata}{Character vector of stratum-defining variables. Values must be variable names in \code{data}. Default = "".} + +\item{curve_strata_varnames}{A subset of \code{strata}. Values must be variable names in \code{curve_params}. Default = "".} + +\item{noise_strata_varnames}{A subset of \code{strata}. Values must be variable names in \code{noise_params}. Default = "".} + +\item{numCores}{Number of processor cores to use for calculations when computing by strata. If set to more than 1 and package \pkg{parallel} is available, then the computations are executed in parallel. Default = 1L.} + +\item{antigen_isos}{Character vector with one or more antibody names. Values must match \code{data}} + +\item{verbose}{logical: if TRUE, print verbose log information to console} + +\item{...}{ + Arguments passed on to \code{\link[=.optNll]{.optNll}} + \describe{ + \item{\code{lambda.start}}{starting guess for incidence rate, in years/event.} + \item{\code{dataList}}{Optional argument; as an alternative to passing in \code{data}, \code{curve_params}, and \code{noise_params} individually, you may create a list containing these three elements (with these names) and pass that in instead. This option may be useful for parallel processing across strata.} + \item{\code{hessian}}{if \code{TRUE}, the hessian of \code{f} + at the minimum is returned.} + }} +} +\value{ +A set of lambda estimates for each strata. +} +\description{ +Function to estimate seroincidences based on cross-section serology data and longitudinal +response model. +} diff --git a/man/estimateSeroincidence.Rd b/man/estimateSeroincidence.Rd deleted file mode 100644 index 72d14039..00000000 --- a/man/estimateSeroincidence.Rd +++ /dev/null @@ -1,71 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/estimateSeroincidence.R -\name{estimateSeroincidence} -\alias{estimateSeroincidence} -\title{Estimate Seroincidence} -\usage{ -estimateSeroincidence( - data, - antibodies, - strata = "", - params, - censorLimits, - par0, - start = -6, - numCores = 1L -) -} -\arguments{ -\item{data}{Data frame with cross-sectional serology data per antibody and age, and additional -columns to identify possible \code{strata}.} - -\item{antibodies}{Character vector with one or more antibody names. Values must match \code{data}.} - -\item{strata}{Character vector of strata. Values must match with \code{data}. Default = "".} - -\item{params}{List of data frames of all longitudinal parameters. Each data frame contains -Monte Carlo samples for each antibody type.} - -\item{censorLimits}{List of cutoffs for one or more named antibody types (corresponding to -\code{data}).} - -\item{par0}{List of parameters for the (lognormal) distribution of antibody concentrations -for true seronegatives (i.e. those who never seroconverted), by named antibody type -(corresponding to \code{data}).} - -\item{start}{A starting value for \code{log(lambda)}. Value of -6 corresponds roughly to 1 day -(log(1/365.25)), -4 corresponds roughly to 1 week (log(7 / 365.25)). Default = -6.} - -\item{numCores}{Number of processor cores to use for calculations when computing by strata. If -set to more than 1 and package \pkg{parallel} is available, then the computations are -executed in parallel. Default = 1L.} -} -\value{ -A set of lambda estimates for each strata. -} -\description{ -Function to estimate seroincidences based on cross-section serology data and longitudinal -response model. -} -\examples{ - -\dontrun{ -estimateSeroincidence(data = csData, - antibodies = c("IgG", "IgM", "IgA"), - strata = "", - params = campylobacterDelftParams4, - censorLimits = cutOffs, - par0 = baseLn, - start = -4) - -estimateSeroincidence(data = csData, - antibodies = c("IgG", "IgM", "IgA"), - strata = "", - params = campylobacterDelftParams4, - censorLimits = cutOffs, - par0 = baseLn, - start = -4, - numCores = parallel::detectCores()) -} - -} diff --git a/man/fdev.Rd b/man/fdev.Rd index aae82337..1e631579 100644 --- a/man/fdev.Rd +++ b/man/fdev.Rd @@ -7,13 +7,13 @@ fdev(log.lambda, csdata, lnpars, cond) } \arguments{ -\item{log.lambda}{Initial guess of incidence rate} +\item{log.lambda}{natural logarithm of incidence parameter, in log(years). Value of -6 corresponds roughly to 1 day (log(1/365.25)), -4 corresponds roughly to 1 week (log(7 / 365.25)).} -\item{csdata}{cross-sectional sample data} +\item{csdata}{cross-sectional sample data containing variables \code{y} and \code{a}} -\item{lnpars}{longitudinal antibody decay model parameters} +\item{lnpars}{longitudinal antibody decay model parameters \code{alpha}, \code{y1}, and \code{d}} -\item{cond}{measurement noise parameters} +\item{cond}{measurement noise parameters \code{nu}, \code{eps}, \code{y.low}, and \code{y.high}} } \description{ more description to be added here diff --git a/man/postprocess_fit.Rd b/man/postprocess_fit.Rd new file mode 100644 index 00000000..478a1f2d --- /dev/null +++ b/man/postprocess_fit.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/postprocess_fit.R +\name{postprocess_fit} +\alias{postprocess_fit} +\title{postprocess a fitted incidence model} +\usage{ +postprocess_fit(fit, coverage = 0.95, start = attr(fit, "lambda.start")) +} +\arguments{ +\item{fit}{output from \code{\link[stats:nlm]{stats::nlm()}}} + +\item{coverage}{desired confidence interval coverage probability} + +\item{start}{starting value for incidence rate} +} +\value{ +a \code{\link[tibble:tibble]{tibble::tibble()}}; see \code{\link[stats:nlm]{stats::nlm()}} for details on \code{code} variable +} +\description{ +postprocess a fitted incidence model +} diff --git a/man/print.seroincidence.Rd b/man/print.seroincidence.ests.Rd similarity index 58% rename from man/print.seroincidence.Rd rename to man/print.seroincidence.ests.Rd index 80d1f260..5bf18a1b 100644 --- a/man/print.seroincidence.Rd +++ b/man/print.seroincidence.ests.Rd @@ -1,30 +1,30 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/print.seroincidence.R -\name{print.seroincidence} -\alias{print.seroincidence} -\title{Print Method for Seroincidence Object} -\usage{ -\method{print}{seroincidence}(x, ...) -} -\arguments{ -\item{x}{A list containing output of function \code{\link[=estimateSeroincidence]{estimateSeroincidence()}}.} - -\item{...}{Additional arguments affecting the summary produced.} -} -\description{ -Custom \code{\link[=print]{print()}} function to show output of the seroincidence calculator \code{\link[=estimateSeroincidence]{estimateSeroincidence()}}. -} -\examples{ - -\dontrun{ -# estimate seroincidence -seroincidence <- estimateSeroincidence(...) - -# print the seroincidence object to the console -print(seroincidence) - -# or simply type (appropriate print method will be invoked automatically) -seroincidence -} - -} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/print.seroincidence.R +\name{print.seroincidence.ests} +\alias{print.seroincidence.ests} +\title{Print Method for Seroincidence Object} +\usage{ +\method{print}{seroincidence.ests}(x, ...) +} +\arguments{ +\item{x}{A list containing output of function \code{\link[=est.incidence.by]{est.incidence.by()}}.} + +\item{...}{Additional arguments affecting the summary produced.} +} +\description{ +Custom \code{\link[=print]{print()}} function to show output of the seroincidence calculator \code{\link[=est.incidence.by]{est.incidence.by()}}. +} +\examples{ + +\dontrun{ +# estimate seroincidence +seroincidence <- est.incidence.by(...) + +# print the seroincidence object to the console +print(seroincidence) + +# or simply type (appropriate print method will be invoked automatically) +seroincidence +} + +} diff --git a/man/print.summary.seroincidence.Rd b/man/print.summary.seroincidence.ests.Rd similarity index 55% rename from man/print.summary.seroincidence.Rd rename to man/print.summary.seroincidence.ests.Rd index ec84366c..fcd6450f 100644 --- a/man/print.summary.seroincidence.Rd +++ b/man/print.summary.seroincidence.ests.Rd @@ -1,33 +1,33 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/print.summary.seroincidence.R -\name{print.summary.seroincidence} -\alias{print.summary.seroincidence} -\title{Print Method for Seroincidence Summary Object} -\usage{ -\method{print}{summary.seroincidence}(x, ...) -} -\arguments{ -\item{x}{A list containing output of function \code{\link[=summary.seroincidence]{summary.seroincidence()}}.} - -\item{...}{Additional arguments affecting the summary produced.} -} -\description{ -Custom \code{\link[=print]{print()}} function to show output of the seroincidence summary \code{\link[=summary.seroincidence]{summary.seroincidence()}}. -} -\examples{ - -\dontrun{ -# estimate seroincidence -seroincidence <- estimateSeroincidence(...) - -# calculate summary statistics for the seroincidence object -seroincidenceSummary <- summary(seroincidence) - -# print the summary of seroincidence object to the console -print(seroincidenceSummary) - -# or simply type (appropriate print method will be invoked automatically) -seroincidenceSummary -} - -} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/print.summary.seroincidence.R +\name{print.summary.seroincidence.ests} +\alias{print.summary.seroincidence.ests} +\title{Print Method for Seroincidence Summary Object} +\usage{ +\method{print}{summary.seroincidence.ests}(x, ...) +} +\arguments{ +\item{x}{A "summary.seroincidence.ests" object (constructed by \code{\link[=summary.seroincidence.ests]{summary.seroincidence.ests()}})} + +\item{...}{Additional arguments affecting the summary produced.} +} +\description{ +Custom \code{\link[=print]{print()}} function for "summary.seroincidence.ests" objects (constructed by \code{\link[=summary.seroincidence.ests]{summary.seroincidence.ests()}}) +} +\examples{ + +\dontrun{ +# estimate seroincidence +seroincidence <- est.incidence.by(...) + +# calculate summary statistics for the seroincidence object +seroincidenceSummary <- summary(seroincidence) + +# print the summary of seroincidence object to the console +print(seroincidenceSummary) + +# or simply type (appropriate print method will be invoked automatically) +seroincidenceSummary +} + +} diff --git a/man/summary.seroincidence.Rd b/man/summary.seroincidence.ests.Rd similarity index 70% rename from man/summary.seroincidence.Rd rename to man/summary.seroincidence.ests.Rd index 8cef7393..0965e3e0 100644 --- a/man/summary.seroincidence.Rd +++ b/man/summary.seroincidence.ests.Rd @@ -1,59 +1,58 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/summary.seroincidence.R -\name{summary.seroincidence} -\alias{summary.seroincidence} -\title{Summary Method for Seroincidence Object} -\usage{ -\method{summary}{seroincidence}( - object, - ..., - quantiles = c(0.025, 0.975), - showDeviance = TRUE, - showConvergence = TRUE -) -} -\arguments{ -\item{object}{A dataframe containing output of function \code{\link[=estimateSeroincidence]{estimateSeroincidence()}}.} - -\item{...}{Additional arguments affecting the summary produced.} - -\item{quantiles}{A vector of length 2 specifying quantiles for lower (first element) and upper -(second element) bounds of \code{lambda}. Default = \code{c(0.025, 0.975)}.} - -\item{showDeviance}{Logical flag (\code{FALSE}/\code{TRUE}) for reporting deviance -(-2*log(likelihood) at estimated seroincidence. Default = \code{TRUE}.} - -\item{showConvergence}{Logical flag (\code{FALSE}/\code{TRUE}) for reporting convergence (see -help for \code{\link[=optim]{optim()}} for details). Default = \code{TRUE}.} -} -\value{ -A list with the following items: -\describe{ -\item{\code{Results}}{Dataframe with maximum likelihood estimate of \code{lambda} (the -seroincidence) (column \code{Lambda}) and corresponding lower (\code{Lambda.lwr}) and upper -(\code{Lambda.upr} bounds.\cr -Optionally \code{Deviance} (Negative log likelihood (NLL) at estimated (maximum likelihood) -\code{lambda}) and \code{Covergence} (Convergence indicator returned by \code{\link[=optim]{optim()}}. -Value of 0 indicates convergence) columns are included.} -\item{\code{Antibodies}}{Character vector with names of input antibodies used in -\code{\link[=estimateSeroincidence]{estimateSeroincidence()}}.} -\item{\code{Strata}}{Character with names of strata used in \code{\link[=estimateSeroincidence]{estimateSeroincidence()}}.} -\item{\code{CensorLimits}}{List of cutoffs for each of the antibodies used in -\code{\link[=estimateSeroincidence]{estimateSeroincidence()}}.} -} -} -\description{ -Calculate seroincidence from output of the seroincidence calculator -\code{\link[=estimateSeroincidence]{estimateSeroincidence()}}. -} -\examples{ - -\dontrun{ -# estimate seroincidence -seroincidence <- estimateSeroincidence(...) - -# calculate summary statistics for the seroincidence object -seroincidenceSummary <- summary(seroincidence) -} - -} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/summary.seroincidence.R +\name{summary.seroincidence.ests} +\alias{summary.seroincidence.ests} +\title{Summary Method for Seroincidence Object} +\usage{ +\method{summary}{seroincidence.ests}( + object, + ..., + confidence_level = 0.95, + showDeviance = TRUE, + showConvergence = TRUE +) +} +\arguments{ +\item{object}{A dataframe containing output of function \code{\link[=est.incidence.by]{est.incidence.by()}}.} + +\item{...}{Additional arguments affecting the summary produced.} + +\item{confidence_level}{desired confidence interval coverage probability} + +\item{showDeviance}{Logical flag (\code{FALSE}/\code{TRUE}) for reporting deviance +(-2*log(likelihood) at estimated seroincidence. Default = \code{TRUE}.} + +\item{showConvergence}{Logical flag (\code{FALSE}/\code{TRUE}) for reporting convergence (see +help for \code{\link[=optim]{optim()}} for details). Default = \code{TRUE}.} +} +\value{ +A list with the following items: +\describe{ +\item{\code{Results}}{Dataframe with maximum likelihood estimate of \code{lambda} (the +seroincidence) (column \code{Lambda}) and corresponding lower (\code{Lambda.lwr}) and upper +(\code{Lambda.upr} bounds.\cr +Optionally \code{Deviance} (Negative log likelihood (NLL) at estimated (maximum likelihood) +\code{lambda}) and \code{Covergence} (Convergence indicator returned by \code{\link[=optim]{optim()}}. +Value of 0 indicates convergence) columns are included.} +\item{\code{Antibodies}}{Character vector with names of input antibodies used in +\code{\link[=est.incidence.by]{est.incidence.by()}}.} +\item{\code{Strata}}{Character with names of strata used in \code{\link[=est.incidence.by]{est.incidence.by()}}.} +\item{\code{CensorLimits}}{List of cutoffs for each of the antibodies used in +\code{\link[=est.incidence.by]{est.incidence.by()}}.} +} +} +\description{ +Calculate seroincidence from output of the seroincidence calculator +\code{\link[=est.incidence.by]{est.incidence.by()}}. +} +\examples{ + +\dontrun{ +# estimate seroincidence +seroincidence <- est.incidence.by(...) + +# calculate summary statistics for the seroincidence object +seroincidenceSummary <- summary(seroincidence) +} + +} diff --git a/man/typhoid_controls.Rd b/man/typhoid_controls.Rd new file mode 100644 index 00000000..3e7056fb --- /dev/null +++ b/man/typhoid_controls.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/typhoid_controls.R +\docType{data} +\name{typhoid_controls} +\alias{typhoid_controls} +\title{Example cross-sectional data for typhoid (\code{HlyE_IgA} and \code{HlyE_IgG})} +\format{ +The measurements are in the variable \code{elisa}. Variable \code{nu} provides an estimate of a conditional noise parameter. +} +\usage{ +typhoid_controls +} +\description{ +Data frame of ELISA assay results, by \code{pop} (\code{"CA Facts"}, \code{"MGH"}), \code{antigen_iso} (\code{"HlyE_IgA"}, \code{"HlyE_IgG"}), and \code{Age} (in years). +} +\examples{ + +# Print the data: +typhoid_controls + +# Plot the data +library(ggplot2) +typhoid_controls |> + ggplot(aes(x = Age, y = elisa, col = antigen_iso)) + + geom_point() + + geom_smooth() + +} diff --git a/man/typhoid_noise_params.Rd b/man/typhoid_noise_params.Rd new file mode 100644 index 00000000..90652a77 --- /dev/null +++ b/man/typhoid_noise_params.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/typhoid_noise_params.R +\docType{data} +\name{typhoid_noise_params} +\alias{typhoid_noise_params} +\title{Example noise parameters for HlyE_IgA and HlyE_IgG, by country} +\format{ +The parameters are: +\itemize{ +\item \code{llod} +\item \code{nu} +\item \code{y.high} +\item \code{eps} +} +} +\usage{ +typhoid_noise_params +} +\description{ +Data frame of example noise parameters, by \code{Country} (\code{"MGH"}, \code{"bangladesh"}, \code{"nepal"}) +and \code{antigen_iso} (\code{"HlyE_IgA"}, \code{"HlyE_IgG"}). +} +\examples{ + +# Show the data: +typhoid_noise_params + +} diff --git a/serocalculator.Rproj b/serocalculator.Rproj index 398aa143..88ff2b5d 100644 --- a/serocalculator.Rproj +++ b/serocalculator.Rproj @@ -18,3 +18,4 @@ StripTrailingWhitespace: Yes BuildType: Package PackageUseDevtools: Yes PackageInstallArgs: --no-multiarch --with-keep.source +PackageRoxygenize: rd,collate,namespace diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 00000000..72e01a52 --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(serocalculator) + +test_check("serocalculator") diff --git a/tests/testthat/test-est.incidence.R b/tests/testthat/test-est.incidence.R new file mode 100644 index 00000000..beda82c0 --- /dev/null +++ b/tests/testthat/test-est.incidence.R @@ -0,0 +1,60 @@ +test_that( + "est.incidence() produces expected results for typhoid data", + { + + skip(message = "Skipping test of `est.incidence()` for now, because github was producing miniscule differences in SE (and thus CIs) for some reason that I don't have time to hunt down.") + + library(readr) + library(dplyr) + c.hlye.IgG <- + fs::path_package( + "extdata", + "dmcmc_hlyeigg_09.30.rds", + package = "serocalculator") |> #Load longitudinal parameters dataset + readRDS()%>% + select(y1, alpha, r, antigen_iso) + + p.hlye.IgG <- + fs::path_package( + package = "serocalculator", + "extdata/simpophlyeigg.2.csv") %>% #Load simulated cross-sectional dataset + read_csv( + col_types = cols( + a.smpl = col_double(), + y.smpl = col_double(), + i = col_double(), + t = col_double() + ) + ) %>% + rename( #rename variables + y = y.smpl, + a = a.smpl) %>% + select(y, a) |> + mutate(antigen_iso = "HlyE_IgG") + + cond.hlye.IgG <- data.frame( + nu = 1.027239, # B noise + eps = 0.2, # M noise + y.low = 0.0, # low cutoff + y.high = 5e4, + antigen_iso = "HlyE_IgG"); + + start <- .05 + + fit = est.incidence( + dpop = p.hlye.IgG, + dmcmc = c.hlye.IgG, + c.age = NULL, + antigen_isos = "HlyE_IgG", + noise_params = cond.hlye.IgG, + start = start, + print.level = 2, + iterlim = 100, + stepmax = 1) + + # compare with `typhoid_results` from data-raw/typhoid_results.qmd + + expect_equal( + object = fit, + expected = typhoid_results) + }) diff --git a/tests/testthat/test-nll.R b/tests/testthat/test-nll.R new file mode 100644 index 00000000..ebf11eb7 --- /dev/null +++ b/tests/testthat/test-nll.R @@ -0,0 +1,3 @@ +# test_that("multiplication works", { +# expect_equal(2 * 2, 4) +# }) diff --git a/vignettes/.gitignore b/vignettes/.gitignore index 097b2416..01b6080a 100644 --- a/vignettes/.gitignore +++ b/vignettes/.gitignore @@ -1,2 +1,3 @@ *.html *.R +methodology.log diff --git a/vignettes/articles/sees_analysis.Rmd b/vignettes/articles/sees_analysis.Rmd new file mode 100644 index 00000000..7d04da1e --- /dev/null +++ b/vignettes/articles/sees_analysis.Rmd @@ -0,0 +1,168 @@ +--- +title: "sees-analysis" +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + eval = FALSE +) +``` + +```{r setup} +library(serocalculator) +library(fs) +``` + +```{r} + +library(readr) +xs_sample = + "extdata/sees_crossSectional_baseline_allCountries.102523.csv" |> + path_package(package = "serocalculator") |> + read_csv() + +curve_params = + path_package( + package = "serocalculator", + "extdata/sees_dmcmc_09.30.2021.rds") |> + readRDS() + +noise_params = + path_package( + package = "serocalculator", + "extdata/SEES_NoiseParam.rds") |> + readRDS() |> + rename(y.low = llod) + +full_data = path_package( + package = "serocalculator", + "extdata/SEES_2022-10-24_redacted_2023-10-12.csv") |> + read_csv( + col_types = cols(ae_diagnosis_other = col_character()) + ) + +``` + +```{r} +library(ggplot2) +library(dplyr) +full_data |> + dplyr::filter( + dag == "bangladesh", + studyarm %in% c("pros case", "retro case"), + # timesince0 < 60, + antigen != "LPS" + ) |> + mutate( + .by = pid, + n_obs = n()) |> + arrange(desc(n_obs), pid, timesince0) |> + dplyr::filter( + pid %in% unique(pid)[1:10] + ) |> + mutate( + antigen_iso = paste(antigen, isotype, sep = "_") + ) |> + ggplot( + aes( + x = timesince0, + y = result, + col = antigen_iso + ) + ) + + geom_point() + + geom_smooth() + + # geom_line() + + scale_y_log10() + + facet_wrap(vars(pid)) +``` + + +```{r} +library(ggplot2) +xs_sample |> + dplyr::filter(Country == "Bangladesh") |> + ggplot(aes(x = Age, y = result, col = antigen_iso)) + + geom_point() + + geom_smooth() + + scale_y_log10() +``` + +Here we do one stratum at a time: + +```{r} +library(dplyr) +est1 = est.incidence( + print.level = 2, + start = 0.3, + verbose = TRUE, + dpop = + xs_sample |> + rename( + a = Age, + y = result) %>% + dplyr::filter(Country == "Bangladesh"), + + dmcmc = + curve_params |> + dplyr::filter(Country == "Bangladesh"), + + noise_params = + noise_params |> + dplyr::filter(Country == "Bangladesh"), + + c.age = "<5", + + antigen_isos = xs_sample$antigen_iso |> unique() +) |> print() + + +``` + +Now we will try the loop function: + +```{r} + +est2 = est.incidence.by( + stepmax = 1, + verbose = TRUE, + strata = c("ageCat", "Country"), + lambda.start = .3, + print.level = 2, + numCores = 1, + data = + xs_sample |> + rename( + a = Age, + y = result) |> + dplyr::filter( + ageCat != "16+", # missing from curve_params... + Country != "Nepal" + ), + + curve_params = + curve_params |> + dplyr::filter( + Country != "Nepal" + ), + + noise_params = + noise_params |> + dplyr::filter( + Country != "Nepal" + ) +) + +``` + +```{r} +print(est2) + +``` + +```{r} +a = summary(est2) |> print() +``` + diff --git a/vignettes/cover.Rmd b/vignettes/cover.Rmd deleted file mode 100644 index 1f5bc6d1..00000000 --- a/vignettes/cover.Rmd +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: "R Package - serocalculator" -author: "UC Davis SeroEpidemiology Group" -output: - rmarkdown::html_vignette: - toc: yes -vignette: > - %\VignetteIndexEntry{R Package - serocalculator} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r, echo = FALSE} -pkgName = "serocalculator" -pkgVersion <- packageDescription(pkgName)$Version -pkgLicense <- packageDescription(pkgName)$License -pkgDate <- packageDescription(pkgName)$Date -authorsString <- gsub("^ *|(?<= ) |\n| *$", "", packageDescription(pkgName)$Authors, perl = TRUE) -authorList <- eval(parse(text = authorsString)) -pkgAuthors <- paste(format(authorList, - include = c("given", "family", "email", "comment"), - braces = list(family = c("", ",
"), - email = c("<", ">,
"), - comment = c("", ""))), - collapse = "

") -pkgMaintainer <- packageDescription(pkgName)$Maintainer -pkgBaseFileName <- paste(pkgName, pkgVersion, sep = "_") -pkgUrl <- packageDescription(pkgName)$URL -``` - -R package **serocalculator** allows translation of antibody levels measured in a (cross-sectional) -population sample into an estimate of the frequency with which seroconversions (infections) occur in the sampled population. - -Item | Data ------ | ------ -Version | `r pkgVersion` -Published | `r pkgDate` -Authors | `r pkgAuthors` -Maintainer | `r pkgMaintainer` -License | `r pkgLicense` -Installation manual | [installation.html](installation.html) -Tutorial | [tutorial.html](tutorial.html) -Appendix | [methodology.html](methodology.html) -ECDC web site | `r pkgUrl` diff --git a/vignettes/example-analysis.Rmd b/vignettes/example-analysis.Rmd index fde4156a..5b29d02e 100644 --- a/vignettes/example-analysis.Rmd +++ b/vignettes/example-analysis.Rmd @@ -19,6 +19,7 @@ knitr::opts_chunk$set( ```{r setup} library(serocalculator) library(Hmisc) +library(dplyr) ``` ```{r "load data"} @@ -37,12 +38,14 @@ ln.pars <- data.frame( alpha = day2yr * lp$alpha, # decay rate (per year) d = lp$r -1); # shape (r-1 offset from exp) +library(readr) #read simulated data raw.data = fs::path_package( "extdata", "SimulDat.txt", package = "serocalculator") |> - read.table(head=TRUE) + readr::read_table() |> + rename(AGE = '"AGE"', IgG = '"IgG"') ``` diff --git a/references.bib b/vignettes/references.bib similarity index 100% rename from references.bib rename to vignettes/references.bib diff --git a/vignettes/tutorial.Rmd b/vignettes/tutorial.Rmd index 1faeb8d3..32ba774c 100644 --- a/vignettes/tutorial.Rmd +++ b/vignettes/tutorial.Rmd @@ -7,7 +7,7 @@ output: base_format: rmarkdown::html_vignette toc: true header-includes: "\\DeclareUnicodeCharacter{2010}{-}" -bibliography: ../references.bib +bibliography: references.bib fontsize: 11pt vignette: > %\VignetteIndexEntry{Serocalculator package tutorial} @@ -214,7 +214,7 @@ and 1.15 ("High") (1/yr). Object class: `data.frame`. c) `getAdditionalData`: Utility function for downloading additional longitudinal response parameters from an online repository. Files available for download are `coxiellaIFAParams4.zip` and `yersiniaSSIParams4.zip`. Object class: `function`. -d) `estimateSeroincidence`: Main function of the package. Estimates seroincidence based on supplied +d) `est.incidence.by`: Main function of the package. Estimates seroincidence based on supplied cross-section antibody levels data and longitudinal response parameters. Object class: `function`. ## Specifying input data @@ -371,7 +371,7 @@ Internet connection is needed for this function to work. ## Estimating seroincidence -Main calculation function provided by package *serocalculator* is called `estimateSeroincidence`. +Main calculation function provided by package *serocalculator* is called `est.incidence.by`. It takes several arguments: - `data`: A data frame with the cross-sectional data (see variable `serologyData` above). This may @@ -393,7 +393,7 @@ It takes several arguments: - `par0`: List of parameters for the (lognormal) distribution of antibody concentrations for true seronegatives (i.e. those who never seroconverted), by named antibody type (corresponding to `data`). -- `start` A starting value for `log(lambda)`. Value of -6 corresponds roughly to 1 day +- `start` A starting value for `log.lambda`. Value of -6 corresponds roughly to 1 day (`log(1/365.25)`), value of -4 corresponds roughly to 1 week (`log(7/365.25)`). Users are adivised to experiment with this value to confirm that convergence to the same estimate is obtained. Default is -6. @@ -420,9 +420,9 @@ baseLine <- list(IgG = c(log(0.05), 1), IgM = c(log(0.005), 1), IgA = c(log(0.005), 1)) -# Assign output of function "estimateSeroincidence" to object named +# Assign output of function "est.incidence.by" to object named # "seroincidenceData". Use all available processor cores. -seroincidenceData <- estimateSeroincidence( +seroincidenceData <- est.incidence.by( data = serologyData, antibodies = c("IgG", "IgM", "IgA"), strata = "AgeCat", @@ -447,9 +447,9 @@ The following text should be printed. ## ## This object is a list containing the following items: ## Fits - List of outputs of "optim" function per stratum. - ## Antibodies - Input parameter antibodies of function "estimateSeroincidence". - ## Strata - Input parameter strata of function "estimateSeroincidence". - ## CensorLimits - Input parameter censorLimits of function "estimateSeroincidence". + ## Antibodies - Input parameter antibodies of function "est.incidence.by". + ## Strata - Input parameter strata of function "est.incidence.by". + ## CensorLimits - Input parameter censorLimits of function "est.incidence.by". ## ## Call summary function to obtain output results. @@ -458,7 +458,7 @@ Translation of these raw results is provided by a custom function `summary` expl following section. The cutoff argument is based on censoring of the observed serum antibody measurements [@Strid_2001]. Cut-off -levels must always be specified when calling function `estimateSeroincidence` (argument +levels must always be specified when calling function `est.incidence.by` (argument `censorLimits`). Value `0` should be set for antibody measurements where no censoring is needed, for instance @@ -569,7 +569,7 @@ baseLine <- list(IgG = c(log(0.05), 1), IgA = c(log(0.005), 1)) # 4a. Calculate a single seroincidence rate for all serum samples... -seroincidenceData <- estimateSeroincidence( +seroincidenceData <- est.incidence.by( data = serologyData, antibodies = c("IgG", "IgM", "IgA"), strata = "", @@ -579,7 +579,7 @@ seroincidenceData <- estimateSeroincidence( # 4b. ...or calculate a single seroincidence rate for a single serum sample # (triplet of titres)... -seroincidenceData <- estimateSeroincidence( +seroincidenceData <- est.incidence.by( data = serologyData[1, ], antibodies = c("IgG", "IgM", "IgA"), strata = "", @@ -588,7 +588,7 @@ seroincidenceData <- estimateSeroincidence( par0 = baseLine) # 4c. ...or calculate a single seroincidence rate for all serum samples (only IgG) -seroincidenceData <- estimateSeroincidence( +seroincidenceData <- est.incidence.by( data = serologyData, antibodies = c("IgG"), strata = "", diff --git a/vignettes/typhoid-controls.Rmd b/vignettes/typhoid-controls.Rmd new file mode 100644 index 00000000..5edf4d37 --- /dev/null +++ b/vignettes/typhoid-controls.Rmd @@ -0,0 +1,29 @@ +--- +title: "typhoid-controls" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{typhoid-controls} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} +library(serocalculator) +``` + +```{r} + +library(ggplot2) +typhoid_controls |> + ggplot(aes(x = Age, y = elisa, col = antigen_iso)) + + geom_point() + + geom_smooth() +``` + diff --git a/vignettes/typhoid-seroincidence.Rmd b/vignettes/typhoid-seroincidence.Rmd new file mode 100644 index 00000000..d78fbe32 --- /dev/null +++ b/vignettes/typhoid-seroincidence.Rmd @@ -0,0 +1,135 @@ +--- +title: "Typhoid Seroincidence" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Typhoid Seroincidence} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- +# Introduction + +This vignette provides users with an example analysis using the *serocalculator* package. Users will be able to determine the seroincidence of typhoid fever in the sample population using existing longitudinal antibody dynamics collected from Bangladesh, Ghana, Nepal, and Pakistan, plus a simulated cross-sectional serosurvey. + +## References +Aiemjoy, K., Seidman, J. C., Saha, S., Munira, S. J., Islam Sajib, M. S., Sium, S. M. al, Sarkar, A., Alam, N., Zahan, F. N., Kabir, M. S., Tamrakar, D., Vaidya, K., Shrestha, R., Shakya, J., Katuwal, N., Shrestha, S., Yousafzai, M. T., Iqbal, J., Dehraj, I. F., … Andrews, J. R. (2022). Estimating typhoid incidence from community-based serosurveys: a multicohort study. The Lancet. Microbe, 3(8), e578–e587. https://doi.org/10.1016/S2666-5247(22)00114-8 + + + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` +# Sample Analysis +## 1. Load packages +The first step in conducting this analysis is to load our necessary packages. Follow the [installation instructions] https://ucd-serg.github.io/serocalculator/ if you have not already installed *serocalculator*. (Still in development as of 10/17/2023) + +```{r setup} + +#library(devtools) +#install_github("UCD-SERG/serocalculator") +library(serocalculator) +library(tidyverse) +``` + +## 2. Load data +### a. Load and prepare longitudinal parameter data +The next step is to load the longitudinal data to set the antibody decay parameters. In this example, these parameters were modeled with Bayesian hierarchical models to fit two-phase power-function decay models to the longitudinal antibody responses among confirmed enteric fever cases. + +These parameters include the following: +* y0 = baseline +* y1 = peak antibody responses +* t1 = time to peak +* α = decay rate +* r = decay shape + +We also create two additional variables, *alpha* and *d*. *Alpha* is the annual decay rate, which is calculated from the daily decay rate in this example. *d* is 1-r, the decay shape. _______ + +Finally, we select only the variables needed for the analysis. + +```{r longdata} +c.hlye.IgG <- + fs::path_package( + "extdata", + "dmcmc_hlyeigg_09.30.rds", + package = "serocalculator") |> #Load longitudinal parameters dataset + readRDS()%>% + mutate(alpha = alpha*365.25, #Create alpha and d + d = r-1) %>% + select(y1, alpha, d) #Select only the variables needed for analysis +``` + +### b. Load and prepare simulated data +The simulated data represent a cross-sectional serosurvey conducted in a representative sample of the general population without regard to disease status. Here, we are assuming a force of infection (FOI, *lambda*) of 0.2. This means that we assume that there will be 0.2 cases per person in the general population during the time period of interest. + +In this scenario, we have selected hlye and IgG as our target measures. Users may select different serologic markers depending on what is available. From the original dataset, we rename our variables to *y* and *a*. Finally, we once again limit the dataset to only the variables needed for the analysis. + +``` {r simdata} +library(fs) # filesystem utility functions +p.hlye.IgG <- + fs::path_package( + package = "serocalculator", + "extdata/simpophlyeigg.2.csv") %>% #Load simulated cross-sectional dataset + read_csv() %>% + rename( #rename variables + y = y.smpl, + a = a.smpl) %>% + select(y, a) #Select only the variables needed for analysis +``` + + +### c. Set conditions for simulated data +Next, we must set conditions based on some assumptions about the simulated data. This will differ based on background knowledge of the cross-sectional data. + +[Need more here, plus simplify variable names] + +``` {r conditions} +cond.hlye.IgG <- data.frame( + nu = 1.027239, # B noise + eps = 0.2, # M noise + y.low = 0.0, # low cutoff + y.high = 5e4); +``` + + +## 3. Estimate Seroincidence +Finally, we are ready to begin seroincidence estimation. We define our starting value as 0.5, which will also define our initial estimate for lambda (FOI). Then we set up values for the confidence interval. + +(Add explanation for each section below) +[Need more information on starting estimate vs estimate mentioned for simulated data] + + +```{r seroinc} +start <- .05 + +lambda = start # initial estimate: starting value +log.lambda = log(lambda) +log.lmin=log(lambda/10) +log.lmax=log(10*lambda) + + + +objfunc <- function(llam){ + return(res <- fdev(llam, p.hlye.IgG, c.hlye.IgG, cond.hlye.IgG)) +} + + +fit <- nlm(objfunc,log.lambda, + hessian=TRUE,print.level=0,stepmax=(log.lmax-log.lmin)/4) + + +#lambda, lower, upper, LF min +log.lambda.est <- c(exp(fit$estimate), + exp(fit$estimate + qnorm(c(0.025))*sqrt(1/fit$hessian)), + exp(fit$estimate + qnorm(c(0.975))*sqrt(1/fit$hessian)), + fit$minimum) + + +log.lambda.est +``` + +## Conclusions +In our simulated data, we found that the estimated seroincidence of typhoid is ______. + +