Skip to contents
library(serocalculator)
library(Hmisc)
#> 
#> Attaching package: 'Hmisc'
#> The following objects are masked from 'package:base':
#> 
#>     format.pval, units
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:Hmisc':
#> 
#>     src, summarize
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

# load longitudinal parameter MC sample
fs::path_package(
  "extdata", 
  "pertussis-iggpt2.rda", 
  package = "serocalculator") |> 
  load() # output: longpar.mc

lp = longpar.mc$IgG
day2yr <- 365.25;
ln.pars <- data.frame(
  y1 = lp$y1,                 # peak levels
  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") |> 
  readr::read_table() |> 
  rename(AGE = '"AGE"', IgG = '"IgG"')
#> 
#> ── Column specification ────────────────────────────────────────────────────────
#> cols(
#>   `"AGE"` = col_double(),
#>   `"IgG"` = col_double()
#> )

cat.bnd = seq(0,80,by=5); 
n.cats = length(cat.bnd)-1; # define age categories
age.cat = cut(raw.data$AGE, breaks = cat.bnd, right = FALSE) |>  as.numeric()

clean.data = data.frame(
  age = floor(raw.data$AGE) + 0.5,
  IgG = raw.data$IgG,
  cat = age.cat)

# define global parameters
cond <- data.frame(
  nu=2.5,                    # B noise
  eps=0.3,                   # M noise
  y.low=2.5,                 # low cutoff
  y.high=5e4);               # high cutoff

lambda = 0.015 # initial estimate: starting value
log.lambda = log(lambda)
log.lmin = log(lambda/10);
log.lmax=log(10*lambda)   # seroincidence rate interval
log.lambda.est = matrix(0, nrow=n.cats, ncol=6,
  dimnames = list(
    rep("",n.cats),
    c("","ml.est", "lwr0.05", "upr0.95",
      "LLF","N iter.")))
# loop over age categories
system.time(
  for (k.cat in 1:n.cats)                       # per age category
  { 
    cat(k.cat,"\n")
    y.cat = as.vector(subset(clean.data,subset=clean.data$cat==as.character(k.cat),
      select="IgG"))$IgG;
    a.cat = as.vector(subset(clean.data,subset=clean.data$cat==as.character(k.cat),
      select="age"))$age;
    cs.data <- data.frame(y=y.cat, a=a.cat);
    objfunc <- function(llam){
      # add terms, e.g. for other antibodies
      # res < fdev(llam,cs1,ln1,cond1) + fdev(llam,cs2,ln2,cond2) + ...
      # return(res)
      return(fdev(llam,cs.data,ln.pars,cond));
    }
    # seroincidence estimation
    
    fit = nlm(objfunc,log.lambda,
      hessian=TRUE,print.level=0,stepmax=(log.lmax-log.lmin)/4);
    
    log.lambda.est[k.cat,] = c(k.cat,
      fit$estimate,
      fit$estimate + qnorm(c(0.05))*sqrt(1/fit$hessian),
      fit$estimate + qnorm(c(0.95))*sqrt(1/fit$hessian),
      fit$minimum,
      fit$iterations)
    
    log.lambda=log.lambda.est[k.cat,2]
  })
#> 1 
#> 2 
#> 3 
#> 4 
#> 5 
#> 6 
#> 7 
#> 8 
#> 9 
#> 10 
#> 11 
#> 12 
#> 13 
#> 14 
#> 15 
#> 16
#>    user  system elapsed 
#>  33.838   0.011  33.850
# check results in log.lambda.est:
pander::pander(log.lambda.est)
  ml.est lwr0.05 upr0.95 LLF N iter.
1 -4.111 -4.782 -3.439 89.69 3
2 -4.495 -4.97 -4.02 123.6 5
3 -4.358 -4.71 -4.007 202.7 4
4 -4.116 -4.386 -3.845 262.9 4
5 -4.194 -4.451 -3.937 332.3 4
6 -3.983 -4.205 -3.761 395.4 4
7 -4.082 -4.3 -3.865 413.7 4
8 -4.449 -4.683 -4.216 330.1 5
9 -4.347 -4.566 -4.129 379.4 4
10 -4.376 -4.592 -4.161 406.5 3
11 -4.148 -4.34 -3.956 462.8 4
12 -4.273 -4.472 -4.074 455.5 4
13 -4.092 -4.278 -3.906 508.8 4
14 -4.128 -4.314 -3.942 508.6 3
15 -4.342 -4.531 -4.152 440.1 4
16 -4.27 -4.458 -4.082 518.1 4