Author: Pavel Fiser (MSD), Julie Dudasova (MSD)
Date: 2021-09-20

# PoDBAY population class

#### Pavel Fiser (MSD), Julie Dudasova (MSD)

#### 2021-09-20

This document describes how to create a population class object using PoDBAY package. Population class is used across the vignettes and package functions (see `vignette("efficacyestimation", package = "PoDBAY")` and `vignette("simulation", package = "PoDBAY")`) and it allows the user utilize the different populations, e.g. vaccinated, control, diseased, nondiseased.

For creation of any population class object `generatePopulation` function is used. The goal of this document is to show:

- Creation of empty population class object
- Example on how to create population class object with certain characteristics
- Application of population class methods
- How to convert patient level data from clinical trials into the population class object

## Empty population class object

The easiest application of the population class is to generate an empty population class object i.e. population class object with no characteristics which can later be adjusted.

    populationEmpty <- generatePopulation()
    populationEmpty
    #> Reference class object of class "Population"
    #> Field "N":
    #> [1] 0
    #> Field "mean":
    #> [1] NA
    #> Field "stdDev":
    #> [1] NA
    #> Field "unknownDistribution":
    #> [1] FALSE
    #> Field "UDFunction":
    #> function ()
    #> NULL
    #> <bytecode: 0x24d3840>
    #> Field "titers":
    #> numeric(0)
    #> Field "PoDs":
    #> numeric(0)
    #> Field "diseaseStatus":
    #> logical(0)

## Non-empty population class object

Sometimes we want to generate a population class object based on the summary statistics (N, mean, sd). For example, this approach can be used when creating population class objects in the simulations - see `vignette("simulation", package = "PoDBAY")` for more details.

In this example we create two population class objects - vaccinated and control.

Approach 1 This approach is useful when we don’t necessarily need to generate individual titers.

    vaccinated <- generatePopulation()
    vaccinated$N <- 1000
    vaccinated$mean <- 7
    vaccinated$stdDev <- 2

    str(vaccinated)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 7
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num(0)
    #>  $ PoDs               : num(0)
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX

    control <- generatePopulation()
    control$N <- 1000
    control$mean <- 5
    control$stdDev <- 2

    str(control)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 5
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num(0)
    #>  $ PoDs               : num(0)
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX

Approach 2 If the population summary statistics parameters are used as function input individual titers are generated as well (by sampling from normal distribution). These titers can be later changed if needed.

    vaccinated <- generatePopulation(N = 1000,
                                     mean = 7,
                                     stdDev = 2)
    str(vaccinated)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 7
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num [1:1000] 5.75 7.37 5.33 10.19 7.66 ...
    #>  $ PoDs               : num(0)
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX

    control <- generatePopulation(N = 1000,
                                       mean = 5,
                                       stdDev = 2)

    str(control)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 5
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num [1:1000] 7.27 7.22 3.26 5.42 5.14 ...
    #>  $ PoDs               : num(0)
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX

## Application of population class methods

The advantage of the population class is that we can apply certain predefined class methods/functions. This simplifies working with population data (in the form of population class object) substantially.

list of useful available methods:

- getTiters
- assignPoD
- getDiseasedCount
- getNondiseasedCount
- getDiseasedTiters
- getNondiseasedTiters

### Starting population class object

Let’s start with the two population class objects - vaccinated, control - defined above.

    vaccinated <- generatePopulation()
    vaccinated$N <- 1000
    vaccinated$mean <- 7
    vaccinated$stdDev <- 2

    str(vaccinated)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 7
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num(0)
    #>  $ PoDs               : num(0)
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX

    control <- generatePopulation()
    control$N <- 1000
    control$mean <- 5
    control$stdDev <- 2

    str(control)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 5
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num(0)
    #>  $ PoDs               : num(0)
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX

### getTiters

Generate titers based on the population parameters - N, mean, stdDev - by sampling from the normal distribution.

    vaccinated$getTiters()
    control$getTiters()

    str(vaccinated)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 7
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num [1:1000] 5.23 3.16 10.24 8.04 6.89 ...
    #>  $ PoDs               : num(0)
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX
    str(control)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 5
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num [1:1000] 6.48 5.77 7.59 3.39 1.79 ...
    #>  $ PoDs               : num(0)
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX

### assignPoD

Assign PoD to each subject in the population based on the provided PoD function. We will use example from `vignette("simulation", package = "PoDBAY")`.

    # Define PoD curve parameters
    PoDParams <- data.frame("pmax" = 0.05, "et50" = 5, "slope" = 7)

    # Assign PoD
    vaccinated$assignPoD(
      PoD(titer = vaccinated$titers,
          pmax = PoDParams$pmax,
          et50 = PoDParams$et50,
          slope = PoDParams$slope,
          adjustTiters = FALSE
      ))

    control$assignPoD(
      PoD(titer = control$titers,
          pmax = PoDParams$pmax,
          et50 = PoDParams$et50,
          slope = PoDParams$slope,
          adjustTiters = FALSE
      ))

    str(vaccinated)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 7
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num [1:1000] 5.23 3.16 10.24 8.04 6.89 ...
    #>  $ PoDs               : num [1:1000] 0.021135 0.048083 0.000329 0.001738 0.004799 ...
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX
    str(control)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 5
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num [1:1000] 6.48 5.77 7.59 3.39 1.79 ...
    #>  $ PoDs               : num [1:1000] 0.00701 0.01338 0.00255 0.04689 0.04996 ...
    #>  $ diseaseStatus      : logi(0)
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX

Another way to assign PoD

    vaccinated$assignPoD(
      rep(0.05, vaccinated$N))

    control$assignPoD(
      rep(0.1, control$N))

### getDiseasedCount, getNondiseasedCount, getDiseasedTiters, getNondiseasedTiters

For using these methods, the population class object needs to have disease status assigned.

To assign disease status we will use `ClinicalTrial` function form the PoDBAY package.

    CaseCount <- ClinicalTrial(vaccinated, control, CI = 0.95)

    str(vaccinated)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 7
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num [1:1000] 5.23 3.16 10.24 8.04 6.89 ...
    #>  $ PoDs               : num [1:1000] 0.021135 0.048083 0.000329 0.001738 0.004799 ...
    #>  $ diseaseStatus      : logi [1:1000] FALSE FALSE FALSE FALSE FALSE FALSE ...
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX
    str(control)
    #> Reference class 'Population' [package "PoDBAY"] with 8 fields
    #>  $ N                  : num 1000
    #>  $ mean               : num 5
    #>  $ stdDev             : num 2
    #>  $ unknownDistribution: logi FALSE
    #>  $ UDFunction         :function ()
    #>  $ titers             : num [1:1000] 6.48 5.77 7.59 3.39 1.79 ...
    #>  $ PoDs               : num [1:1000] 0.00701 0.01338 0.00255 0.04689 0.04996 ...
    #>  $ diseaseStatus      : logi [1:1000] FALSE TRUE FALSE FALSE FALSE FALSE ...
    #>  and 24 methods, of which 10 are  possibly relevant:
    #>    assignPoD, getDiseasedCount, getDiseasedTiters, getNondiseasedCount,
    #>    getNondiseasedTiters, getTiters, getUnknown, initialize, popFun, popX

    vaccinated$getDiseasedCount()
    #> [1] 9
    vaccinated$getNondiseasedCount()
    #> [1] 991
    vaccinated$getDiseasedTiters()
    #> [1] 3.291161 5.083290 5.032390 3.605223 7.581768 4.333546 3.962850 5.538260
    #> [9] 4.949354
    as_tibble(vaccinated$getNondiseasedTiters())
    #> # A tibble: 991 x 1
    #>    value
    #>    <dbl>
    #>  1  5.23
    #>  2  3.16
    #>  3 10.2
    #>  4  8.04
    #>  5  6.89
    #>  6  8.39
    #>  7  7.11
    #>  8  4.38
    #>  9  2.75
    #> 10  6.58
    #> # … with 981 more rows

## How to convert subject level data into the population class object

We use mock-up data from a clinical trial and show how to convert them into a population class object so the data can be applied in the PoDBAY package.

### Mock-up data

Assume we have 20 patients from which 10 are vaccinated and 10 are in the control group. For each patient we have measurement of their \(log_2(titer)\) values.

    dataTrial <- data.frame("patno" = 1:20,
                            "treatment" = c(rep(FALSE, 10), rep(TRUE, 10)),
                            "titers" = as.numeric(c(rnorm(10, 5, 2),
                                                    rnorm(10, 7, 2)))
                            )

    dataTrial
    #>    patno treatment   titers
    #> 1      1     FALSE 1.967253
    #> 2      2     FALSE 6.258282
    #> 3      3     FALSE 1.643612
    #> 4      4     FALSE 7.359562
    #> 5      5     FALSE 7.235309
    #> 6      6     FALSE 2.524528
    #> 7      7     FALSE 2.539671
    #> 8      8     FALSE 6.195582
    #> 9      9     FALSE 5.597729
    #> 10    10     FALSE 4.779721
    #> 11    11      TRUE 5.384650
    #> 12    12      TRUE 7.229078
    #> 13    13      TRUE 6.640960
    #> 14    14      TRUE 7.109690
    #> 15    15      TRUE 9.598280
    #> 16    16      TRUE 6.130878
    #> 17    17      TRUE 5.382154
    #> 18    18      TRUE 5.955297
    #> 19    19      TRUE 6.424569
    #> 20    20      TRUE 5.713573

### Conversion to population class object

We use approach from above and convert our mock-up data into the PoDBAY population class object.

    # vaccinated
    vacc <- dataTrial %>% filter(treatment)

    vaccinated <- generatePopulation()
    vaccinated$N <- nrow(vacc)
    vaccinated$mean <- mean(vacc$titers)
    vaccinated$stdDev <- sd(vacc$titers)
    vaccinated$titers <- vacc$titers

    vaccinated
    #> Reference class object of class "Population"
    #> Field "N":
    #> [1] 10
    #> Field "mean":
    #> [1] 6.556913
    #> Field "stdDev":
    #> [1] 1.249035
    #> Field "unknownDistribution":
    #> [1] FALSE
    #> Field "UDFunction":
    #> function ()
    #> NULL
    #> <bytecode: 0x24d3840>
    #> Field "titers":
    #>  [1] 5.384650 7.229078 6.640960 7.109690 9.598280 6.130878 5.382154 5.955297
    #>  [9] 6.424569 5.713573
    #> Field "PoDs":
    #> numeric(0)
    #> Field "diseaseStatus":
    #> logical(0)

    # control
    ctrl <- dataTrial %>% filter(!treatment)

    control <- generatePopulation()
    control$N <- nrow(ctrl)
    control$mean <- mean(ctrl$titers)
    control$stdDev <- sd(ctrl$titers)
    control$titers <- ctrl$titers

    control
    #> Reference class object of class "Population"
    #> Field "N":
    #> [1] 10
    #> Field "mean":
    #> [1] 4.610125
    #> Field "stdDev":
    #> [1] 2.238717
    #> Field "unknownDistribution":
    #> [1] FALSE
    #> Field "UDFunction":
    #> function ()
    #> NULL
    #> <bytecode: 0x24d3840>
    #> Field "titers":
    #>  [1] 1.967253 6.258282 1.643612 7.359562 7.235309 2.524528 2.539671 6.195582
    #>  [9] 5.597729 4.779721
    #> Field "PoDs":
    #> numeric(0)
    #> Field "diseaseStatus":
    #> logical(0)