Dosage Regimens, Subjects, and Populations

In Pumas, subjects are represented by the Subject type and collections of subjects are represented as Vectors of Subjects aliased Population. Subjects are defined by their identifier, observations, covariates, and events. In this section we will specify the methods used for defining Subjects programmatically or using the read_pumas function that reads in data that follows the Pumas NLME Data Format (PumasNDF) data format. Before we look at Subjects, we will take a look at how to define events as represented by the DosageRegimen type.

Dosage Regimen Terminology

When subjects are subjected to treatment it is represented by an event in Pumas. Administration of a drug is represented by a DosageRegimen that describes the amount, type, frequency and route. DosageRegimens can either be constructed programmatically using the DosageRegimen constructor or from a data source in the PumasNDF format using read_pumas. The names of the inputs are the same independent of how the DosageRegimen is constructed. The definition of the values are as follows:

  • amt: the amount of the dose. This is the only required value.
  • time: the time at which the dose is given. Defaults to 0.
  • evid: the event id. 1 specifies a normal event. 3 means it's a reset event, meaning that the value of the dynamical variable is reset to the amt at the dosing event. If 4, then the dynamical value and time are reset, and then a final dose is given. Defaults to 1.
  • ii: the inter-dose interval. For steady state events, this is the length of time between successive doses. When addl is specified, this is the length of time to the next dose. Defaults to 0.
  • addl: the number of additional events of the same types, spaced by ii. Defaults to 0.
  • rate: the rate of administration. If 0, then the dose is instantaneous. Otherwise the dose is administrated at a constant rate for a duration equal to amt/rate.
  • ss: an indicator for whether the dose is a steady state dose. A steady state dose is defined as the result of having applied the dose with the interval ii infinitely many successive times. 0 indicates that the dose is not a steady state dose. 1 indicates that the dose is a steady state dose. 2 indicates that it is a steady state dose that is added to the previous amount. The default is 0.
  • route: route of administration to be used in NCA analysis if it is carried out with the integrated interface inside @model. Defaults to NullRoute which is basically no route specified.

This specification leads to the following default constructor for the DosageRegimen type:

Pumas.DosageRegimenType
DosageRegimen

Lazy representation of a series of Events.

Fields

  • data::DataFrame: The tabular representation of a series of Events.

  • Signature

evts = DosageRegimen(amt::Numeric;
                     time::Numeric = 0,
                     cmt::Union{Numeric,Symbol} = 1,
                     evid::Numeric = 1,
                     ii::Numeric = zero.(time),
                     addl::Numeric = 0,
                     rate::Numeric = zero.(amt)./oneunit.(time),
                     duration::Numeric = zero(amt)./oneunit.(time),
                     ss::Numeric = 0,
                     route::NCA.Route)
  • Examples
julia> DosageRegimen(100, ii = 24, addl = 6)
DosageRegimen
 Row │ time     cmt    amt      evid  ii       addl   rate     duration  ss    route
     │ Float64  Int64  Float64  Int8  Float64  Int64  Float64  Float64   Int8  NCA.Route
─────┼───────────────────────────────────────────────────────────────────────────────────
   1 │     0.0      1    100.0     1     24.0      6      0.0       0.0     0  NullRoute

julia> DosageRegimen(50,  ii = 12, addl = 13)
DosageRegimen
 Row │ time     cmt    amt      evid  ii       addl   rate     duration  ss    route
     │ Float64  Int64  Float64  Int8  Float64  Int64  Float64  Float64   Int8  NCA.Route
─────┼───────────────────────────────────────────────────────────────────────────────────
   1 │     0.0      1     50.0     1     12.0     13      0.0       0.0     0  NullRoute

julia> DosageRegimen(200, ii = 24, addl = 2)
DosageRegimen
 Row │ time     cmt    amt      evid  ii       addl   rate     duration  ss    route
     │ Float64  Int64  Float64  Int8  Float64  Int64  Float64  Float64   Int8  NCA.Route
─────┼───────────────────────────────────────────────────────────────────────────────────
   1 │     0.0      1    200.0     1     24.0      2      0.0       0.0     0  NullRoute

julia> DosageRegimen(200, ii = 24, addl = 2, route = NCA.IVBolus)
DosageRegimen
 Row │ time     cmt    amt      evid  ii       addl   rate     duration  ss    route
     │ Float64  Int64  Float64  Int8  Float64  Int64  Float64  Float64   Int8  NCA.Route
─────┼───────────────────────────────────────────────────────────────────────────────────
   1 │     0.0      1    200.0     1     24.0      2      0.0       0.0     0  IVBolus

From various DosageRegimens

  • Signature

evs = DosageRegimen(regimen1::DosageRegimen, regimen2::DosageRegimen; offset = nothing)

offset specifies if regimen2 should start after an offset following the end of the last event in regimen1.

  • Examples
julia> e1 = DosageRegimen(100, ii = 24, addl = 6)
DosageRegimen
 Row │ time     cmt    amt      evid  ii       addl   rate     duration  ss    route
     │ Float64  Int64  Float64  Int8  Float64  Int64  Float64  Float64   Int8  NCA.Route
─────┼───────────────────────────────────────────────────────────────────────────────────
   1 │     0.0      1    100.0     1     24.0      6      0.0       0.0     0  NullRoute

julia> e2 = DosageRegimen(50, ii = 12, addl = 13)
DosageRegimen
 Row │ time     cmt    amt      evid  ii       addl   rate     duration  ss    route
     │ Float64  Int64  Float64  Int8  Float64  Int64  Float64  Float64   Int8  NCA.Route
─────┼───────────────────────────────────────────────────────────────────────────────────
   1 │     0.0      1     50.0     1     12.0     13      0.0       0.0     0  NullRoute

julia> evs = DosageRegimen(e1, e2)
DosageRegimen
 Row │ time     cmt    amt      evid  ii       addl   rate     duration  ss    route
     │ Float64  Int64  Float64  Int8  Float64  Int64  Float64  Float64   Int8  NCA.Route
─────┼───────────────────────────────────────────────────────────────────────────────────
   1 │     0.0      1    100.0     1     24.0      6      0.0       0.0     0  NullRoute
   2 │     0.0      1     50.0     1     12.0     13      0.0       0.0     0  NullRoute

julia> DosageRegimen(e1, e2, offset = 10)
DosageRegimen
 Row │ time     cmt    amt      evid  ii       addl   rate     duration  ss    route
     │ Float64  Int64  Float64  Int8  Float64  Int64  Float64  Float64   Int8  NCA.Route
─────┼───────────────────────────────────────────────────────────────────────────────────
   1 │     0.0      1    100.0     1     24.0      6      0.0       0.0     0  NullRoute
   2 │   178.0      1     50.0     1     12.0     13      0.0       0.0     0  NullRoute

The Subject Constructor

The dosage regimen is only a subset of what we need to fully specify a subject. As mentioned above, we use the Subject type to represent individuals in Pumas. They can be constructed using the Subject constructor programmatically:

Pumas.SubjectType
Subject

The data corresponding to a single subject:

Fields:

  • id: identifier
  • observations: a named tuple of the dependent variables
  • covariates: a named tuple containing the covariates, or nothing.
  • events: a vector of Events.
  • time: a vector of time stamps for the observations

When there are time varying covariates, each covariate is interpolated with a common covariate time support. The interpolated values are then used to build a multi-valued interpolant for the complete time support.

From the multi-valued interpolant, certain discontinuities are flagged in order to use that information for the differential equation solvers and to correctly apply the analytical solution per region as applicable.

Constructor

Subject(;id = "1",
         observations = NamedTuple(),
         events = Event[],
         time = observations isa AbstractDataFrame ? observations.time : nothing,
         event_data = true,
         covariates::Union{Nothing, NamedTuple} = nothing,
         covariates_time = observations isa AbstractDataFrame ? observations.time : nothing,
         covariates_direction = :left)

Subject may be constructed from an <:AbstractDataFrame with the appropriate schema or by providing the arguments directly through separate DataFrames / structures.

Examples:

julia> Subject()
Subject
  ID: 1

julia> Subject(id = 20, events = DosageRegimen(200, ii = 24, addl = 2), covariates = (WT = 14.2, HT = 5.2))
Subject
  ID: 20
  Events: 3
  Covariates: WT, HT

julia> Subject(covariates = (WT = [14.2, 14.7], HT = fill(5.2, 2)), covariates_time = [0, 3])
Subject
  ID: 1
  Covariates: WT, HT

or using read_pumas from tabular data:

Pumas.read_pumasFunction
read_pumas(filepath::String; missingstring = ["", ".", "NA"], kwargs...)
read_pumas(
  df::AbstractDataFrame;
  observations=Symbol[:dv],
  covariates=Symbol[],
  id::Symbol=:id,
  time::Symbol=:time,
  evid::Union{Nothing,Symbol}=nothing,
  amt::Symbol=:amt,
  addl::Symbol=:addl,
  ii::Symbol=:ii,
  cmt::Symbol=:cmt,
  rate::Symbol=:rate,
  ss::Symbol=:ss,
  route::Symbol=:route,
  mdv::Symbol=nothing,
  event_data::Bool=true,
  covariates_direction::Symbol=:left,
  check::Bool=event_data,
  adjust_evid34::Bool=true
)

Import NMTRAN-formatted data. You can either pass a CSV file path as a String or a DataFrame as the first and only positional argument.

  • df: DataFrame contaning the data to be converted to a Vector{<:Subject}.

  • observations: dependent variables specified by a vector of column names.

  • covariates: covariates specified by a vector of column names.

  • id: specifies the ID column of the DataFrame.

  • time: specifies the time column of the DataFrame.

  • evid: specifies the event ID column of the DataFrame. See ?Pumas.Event for more details.

  • amt: specifies the dose amount column of the DataFrame. See ?Pumas.Event for more details.

  • addl: specifies the column of the DataFrame that indicated the number of repeated dose events. If not specified then the value is zero.

  • ii: specifies the dose interval column of the DataFrame. See ?Pumas.Event for more details.

  • cmt: specifies the compartment column of the DataFrame. See ?Pumas.Event for more details.

  • rate: specifies the infusion rate column of the DataFrame. See ?Pumas.Event for more details.

  • ss: specifies the steady state column of the DataFrame. See ?Pumas.Event for more details.

  • route: specifies the route of administration column of the DataFrame. See ?Pumas.Event for more details.

  • mdv: specifies the the column of the DataFrame indicating if observations are missing.

  • event_data: toggles assertions applicable to event data. More specifically, checks if the following columns are present in the DataFrame, either as the default values or as user-defined values: :id, :time, and :amt. If no :evid column is present, then a warning will be thrown, and :evid is set to 1 when :amt values are >0 or not missing, or :evid is set to 0 when :amt values are missing and observations are not missing. Otherwise, read_pumas will throw an error.

  • covariates_direction: specifies direction of covariate interpolation. Either :left (Last Observation Carried Forward, LOCF) (default), or :right (Next Observation Carried Backward, NOCB). Notice, that for model with occasion variables it is important to use :left for the correct behavior of the interpolation.

  • check: toggles NMTRAN compliance check of the input data. More specifically, checks if the following columns are present in the DataFrame, either as the default values or as user-defined values: :id, :time, :amt, :cmt, :evid, :addl, :ii, :ss, and :route. Additional checks are:

    • all variables in observations are numeric, i.e. Integer or AbstractFloat.
    • :amt column is numeric, i.e. Integer or AbstractFloat.
    • :cmt column is either a positive Integer, an AbstractString, or a Symbol.
    • :amt values must be missing or 0 when evid = 0; or >=0 otherwise.
    • all variables in observation are missing when evid = 1.
    • :ii column must be present if :ss is specified or present.
    • :ii values must be missing or 0 when evid = 0.
    • :ii column must be >0 if :addl values are >0, and vice-versa.
    • :addl column, if present, must be >=0 when evid = 1.
    • :evid values must be !=0 when :amt values are >0, or :addl and :ii values are >0.
  • adjust_evid34: toggles adjustment of time vector for reset events (evid = 3 and evid = 4). If true (the default) then the time of the previous event is added to the time on record to ensure that the time vector is monotonically increasing.

You can also create Subjects from an existing Subject:

Pumas.SubjectMethod

Subject(subject::Subject; id::AbstractString, events)

Construct a Subject from an existing subject while replacing information according to the keyword arguments. The possible keyword arguments are

  • id, sets the subject identifier to the string id. Defaults to the identifier already in subject.
  • events, sets the subject events to the input DosageRegimen. Defaults to the events already present in subject.
  • covariates and covariates_times, used as input to add covariate information

Examples:

```jldoctest julia> s1 = Subject(; id = "AKJ491", events = DosageRegimen(1.0; time = 1.0), ) Subject ID: AKJ491 Events: 1

julia> Subject( s1; id = "AKJ492", ) Subject ID: AKJ492 Events: 1

The simulated output of a PumasModel as a result of simobs is Pumas.SimulatedObservations. Passing this simobs output into a vectorized Subject will result in a Population that is equivalent to the output of read_pumas. This is a convenient feature that allows one to simulate data and turn it back into a Population that can then be passed into a fit function:

Pumas.SubjectMethod

Subject

Constructor

Subject(simsubject::SimulatedObservations)

Roundtrip the result of simobs, i.e. SimulatedObservations to a Subject/Population

Example:

sims = simobs(model, pop, params)

To convert sims to a Population, broadcast as below

Subject.(sims)

PumasNDF

The PumasNDF is a specification for building a Population (an alias for a vector of Subject's') from tabular data. Generally this tabular data is given by a database like a CSV. The CSV has columns described as follows:

  • id: the ID of the individual. Each individual should have a unique integer, or string.
  • time: the time corresponding to the row. Should be unique per id, i.e. no duplicate time values for a given subject.
  • evid: the event id. 1 specifies a normal event. 3 means it's a reset event, meaning that the value of the dynamical variable is reset to the amt at the dosing event. If 4, then the dynamical value and time are reset, and then a final dose is given. Defaults to 0 if amt is 0 or missing, and 1 otherwise.
  • amt: the amount of the dose. If the evid column exists and is non-zero, this value should be non-zero. Defaults to 0.
  • ii: the inter-dose interval. When addl is specified, this is the length of time to the next dose. For steady state events, this is the length of time between successive doses. Defaults to 0, and is required to be non-zero on rows where a steady-state event is specified.
  • addl: the number of additional doses of the same time to give. Defaults to 0.
  • rate: the rate of administration. If 0, then the dose is instantaneous. Otherwise, the dose is administrated at a constant rate for a duration equal to amt/rate. A rate=-2 allows the rate to be determined by Dose Control Parameters (DCP). Defaults to 0.
  • ss: an indicator for whether the dose is a steady state dose. A steady state dose is defined as the result of having applied the dose with the interval ii infinitely many successive times. 0 indicates that the dose is not a steady state dose. 1 indicates that the dose is a steady state dose. 2 indicates that it is a steady state dose that is added to the previous amount. The default is 0.
  • cmt: the compartment being dosed. Defaults to 1.
  • duration: the duration of administration. If 0, then the dose is instantaneous. Otherwise, the dose is administered at a constant rate equal to amt/duration. Defaults to 0.
  • Observation and covariate columns should be given as a time series of values of matching type. Constant covariates should be constant through the full column. Time points without a measurement should be denoted by a dot (.).

If a column does not exist, its values are imputed to be the defaults. Special notes:

  • If rate and duration exist, then it is enforced that amt=rate*duration.
  • All values and header names are interpreted as lower case.
Tip

Given the information above, it is important to understand how to read a dataset using the CSV package. We recommend that all blanks (""), .'s, NA's and any other character elements in your dataset be passed to the missingstring keyword argument when reading the file as below:

using CSV
data = CSV.read(
    joinpath("pathtomyfile", "mydata.csv"),
    DataFrame;
    missingstring = ["", ".", "NA", "BQL"],
)

For more information check out the CSV documentation.