Skip to content

io

Exchange formats of pharmacokinetic data.

Readers and writers for the table formats the field exchanges timecourses and dosing protocols in. Every reader takes a pandas DataFrame (the caller reads the csv, sas or xpt file) and returns a pkpdutils.timecourse.Timecourses batch with one sample dimension, the times as given (a reader never shifts the time axis), one route and the dosing protocol of every subject; analytes reads several analytes of a table into one batch with a second sample dimension:

  • event records (read_events, write_events): the one row per event format of NONMEM and Monolix, a row being a dose (EVID 1) or an observation (EVID 0). Repeated doses are given explicitly, as ADDL additional doses at the interdose interval II, or as a steady state dose (SS 1); see Bauer (2019) and the Monolix data format documentation.
  • PKNCA tables (read_pknca): the two table layout of the R package PKNCA, the concentrations and the doses, joined on the subject and the grouping columns; see Denney et al. (2015).
  • CDISC ADNCA (read_adnca): the analysis dataset of a non-compartmental analysis of the ADaM standard, one row per concentration record with the time since the first dose (AFRLT) and since the reference dose (ARRLT), see the CDISC ADaM ADNCA implementation guide (2021).

Every format is written back as well (write_events, write_pknca, write_adnca), so a study round trips through any of them. The readers are also reachable as the constructors Timecourses.from_events, Timecourses.from_pknca and Timecourses.from_adnca, the writers as Timecourses.to_events, to_pknca and to_adnca; the parameters of an analysis are written as the CDISC PP domain by pkpdutils.cdisc.

import pandas as pd

from pkpdutils import Route, Timecourses

df = pd.read_csv("study.csv", na_values=".")
batch = Timecourses.from_events(
    df, time_unit="hr", unit="ng/ml", dose_unit="mg", route=Route.ORAL
)

Columns are looked up case-insensitively, a column which is not in the table is treated as absent (a missing required column raises). Compartment columns (CMT, ADM) are not interpreted and modelled rates (RATE -1, RATE -2) are not data: both are out of scope. A reader reads one route; a study of several routes is read into one batch per route, which Timecourses.from_timecourses combines into one multi-route batch.

The references of the formats are the "Data formats" section of docs/references.md.

read_events

read_events(
    df,
    *,
    time_unit,
    unit,
    dose_unit,
    route,
    id_col="ID",
    time_col="TIME",
    dv_col="DV",
    amt_col="AMT",
    evid_col="EVID",
    mdv_col="MDV",
    rate_col="RATE",
    tinf_col="TINF",
    addl_col="ADDL",
    ii_col="II",
    ss_col="SS",
    sd_col="SD",
    se_col="SE",
    n_col="N",
    ss_doses=5,
    keep_missing=True,
    dim="individual",
    analyte_col=None,
    analytes=None,
    analyte_dim=ANALYTE_DIM,
    substance="substance",
    covariates=None,
)

Read a batch from event records, the NONMEM and Monolix format.

A row of the table is one event of one subject: a dose when EVID is 1, an observation when EVID is 0. An observation whose DV is missing or whose MDV is 1 is a missing value: with keep_missing it keeps its time and is read as NaN (the sampling grid of the table is the grid of the batch, which is what a table of values below the limit of quantification needs), without it the row is dropped. Rows with EVID 2 (other type event) or 3 (reset) are dropped and counted in a warning; EVID 4 (reset and dose) raises, since a reset starts a new period which the reader would silently merge into the protocol of the subject (Bauer 2019). A row with EVID 1 and a value in DV is a dose and an observation, which is how a table records a dose and a sample at the same time.

Without an EVID column a row with AMT > 0 is a dose and nothing else, the NM-TRAN semantics of a table without event identifiers; every other row with a value in DV is an observation. A DV on such a dose row is ignored and counted in a warning: a table which records a dose and a sample in one row needs an EVID column.

The duration of an infusion is TINF (Monolix) when it is positive, else AMT / RATE for a positive RATE; modelled rates (RATE -1, RATE -2) are not data and raise. A dose record with ADDL and II stands for ADDL further doses at the interdose interval, a record with SS == 1 for a dosing history of ss_doses preceding doses at the interdose interval, and the batch is marked with attrs["steady_state_marker"]; ADDL > 0 or SS == 1 without a positive II is an incomplete table and raises.

The Monolix column names AMOUNT, OBSERVATION, INFUSION DURATION, INFUSION RATE, ADDITIONAL DOSES, INTERDOSE INTERVAL and STEADY STATE are recognized as aliases (Monolix data format); the lookup of every column is case-insensitive.

Parameters:

Name Type Description Default
df DataFrame

the event table, one row per dose or observation

required
time_unit str

unit of the TIME column

required
unit str

unit of the DV column

required
dose_unit str

unit of the AMT column

required
route Route | str

route of the doses, a Route or a string it coerces ("oral", "IV_BOLUS"); the event format has no route column (CMT/ADM are compartments, not routes) and a batch has one route, so a table of several routes is filtered by the caller

required
id_col str

name of the subject column

'ID'
time_col str

name of the time column

'TIME'
dv_col str

name of the observation column

'DV'
amt_col str

name of the dose amount column

'AMT'
evid_col str

name of the event identifier column

'EVID'
mdv_col str

name of the missing dependent value column

'MDV'
rate_col str

name of the infusion rate column

'RATE'
tinf_col str

name of the infusion duration column (Monolix)

'TINF'
addl_col str

name of the additional doses column

'ADDL'
ii_col str

name of the interdose interval column

'II'
ss_col str

name of the steady state column

'SS'
sd_col str

name of the standard deviation column of a group curve

'SD'
se_col str

name of the standard error column of a group curve

'SE'
n_col str

name of the column with the number of subjects of a group curve (constant within a subject)

'N'
ss_doses int

number of preceding doses a steady state record stands for

5
keep_missing bool

whether a missing observation (MDV 1 or no DV) is read as a NaN value at its time instead of being dropped

True
dim str

name of the sample dimension of the batch

'individual'
analyte_col str | None

name of the column which names the analyte of an observation (DVID, YTYPE, CMT or a column of the study), required with analytes

None
analytes Sequence[str] | None

the analytes to read into one batch, which gives the sample dimension analyte_dim and the coordinate substance along it; a row which names no analyte (a dose record) belongs to every one of them

None
analyte_dim str

name of the sample dimension of analytes

ANALYTE_DIM
substance str

name of the substance or effect

'substance'
covariates Sequence[str] | None

columns to keep as coordinates along dim; by default every column which is neither an event column nor a compartment or occasion column (EVENT_IGNORED) and which is constant within every subject, the columns which vary within a subject being logged and skipped (a column named here raises instead)

None

Returns:

Type Description
Timecourses

The batch, the subjects in the order of their first appearance and

Timecourses

their ID as the coordinate of dim.

Raises:

Type Description
ValueError

if a required column (id_col, time_col, dv_col) is missing, if a row carries EVID 4, if a row carries an SS value other than 0 or 1, if a rate is negative (a modelled rate), if a dose record asks for repeated doses without a positive II, if a subject has fewer than two observations, duplicate sampling times or a dosing protocol which is not valid (named with the subject), if a requested covariate is not a column or not constant within a subject, or if the doses of the subjects do not share one unit.

write_events

write_events(
    timecourses,
    *,
    id_col="ID",
    time_col="TIME",
    dv_col="DV",
    amt_col="AMT",
    evid_col="EVID",
    mdv_col="MDV",
    rate_col="RATE",
    sd_col="SD",
    se_col="SE",
    n_col="N",
)

Write a batch as event records, the inverse of read_events.

Every sample contributes one row per dose of its protocol (EVID 1, MDV 1, no DV, the amount in AMT and, for an infusion, the rate AMT / duration in RATE) and one row per observation (EVID 0, AMT 0, RATE 0, MDV 0, or MDV 1 for a missing value). The rows of a sample are sorted by time, the doses before the observations at the same time; the samples keep the order of the batch. Repeated doses are written out (no ADDL/II/SS), so the table is read back by read_events without the expansion rules. The covariate coordinates along the sample dimension become columns after the event columns.

A missing value is written as a row with MDV 1 and no DV, which read_events reads back as a missing value at its time: the round trip keeps the sampling grid, the observed points and the protocol.

A group curve carries its uncertainty in the columns sd_col, se_col and n_col, written only when the batch has them: sd and se on the observation rows, the number of subjects n on every row of the sample.

Parameters:

Name Type Description Default
timecourses Timecourses

the batch, with exactly one sample dimension

required
id_col str

name of the subject column

'ID'
time_col str

name of the time column

'TIME'
dv_col str

name of the observation column

'DV'
amt_col str

name of the dose amount column

'AMT'
evid_col str

name of the event identifier column

'EVID'
mdv_col str

name of the missing dependent value column

'MDV'
rate_col str

name of the infusion rate column

'RATE'
sd_col str

name of the standard deviation column of a group curve

'SD'
se_col str

name of the standard error column of a group curve

'SE'
n_col str

name of the column with the number of subjects of a group curve

'N'

Returns:

Type Description
DataFrame

The event table with the subject, time, observation, amount, event

DataFrame

identifier, missing value and rate columns, the uncertainty columns of

DataFrame

a group curve and one column per covariate coordinate.

Raises:

Type Description
ValueError

if the batch does not have exactly one sample dimension.

read_pknca

read_pknca(
    conc,
    dose,
    *,
    time_unit,
    unit,
    dose_unit,
    route,
    conc_col="conc",
    time_col="time",
    dose_col="dose",
    dose_time_col="time",
    subject_col="subject",
    duration_col="duration",
    covariates=(),
    dim="individual",
    analyte_col=None,
    analytes=None,
    analyte_dim=ANALYTE_DIM,
    substance="substance",
)

Read a batch from the two tables of the R package PKNCA.

The concentration table holds one row per subject and sampling time, the dose table one row per subject and dose; both are joined on the subject column (Denney et al. 2015). A subject without a row in the dose table gets no protocol. PKNCA codes a value below the limit of quantification as 0 and a missing value as NA: both are kept as given (NaN for NA), the lloq and blq options of the NCA handle them.

Parameters:

Name Type Description Default
conc DataFrame

the concentration table

required
dose DataFrame

the dose table

required
time_unit str

unit of the time columns

required
unit str

unit of the concentration column

required
dose_unit str

unit of the dose column

required
route Route | str

route of the doses, a Route or a string it coerces ("oral", "IV_BOLUS")

required
conc_col str

name of the concentration column

'conc'
time_col str

name of the time column of conc

'time'
dose_col str

name of the dose amount column

'dose'
dose_time_col str

name of the time column of dose, 0 when it is absent

'time'
subject_col str

name of the subject column of both tables

'subject'
duration_col str | None

name of the infusion duration column of dose, absent allowed (a table of another format carries none); None reads no duration. write_pknca writes it under this name

'duration'
covariates Sequence[str]

further columns of either table which are constant within a subject; they become coordinates along dim

()
dim str

name of the sample dimension of the batch

'individual'
analyte_col str | None

name of the column which names the analyte of a row of the concentration table (and of the dose table when it has one), required with analytes

None
analytes Sequence[str] | None

the analytes to read into one batch, which gives the sample dimension analyte_dim and the coordinate substance along it

None
analyte_dim str

name of the sample dimension of analytes

ANALYTE_DIM
substance str

name of the substance or effect

'substance'

Returns:

Type Description
Timecourses

The batch, the subjects in the order of their first appearance in

Timecourses

conc and their subject label as the coordinate of dim.

Raises:

Type Description
ValueError

if a required column is missing, if a covariate column is in neither table or is not constant within a subject, if the concentration table holds no subject, if a subject has fewer than two concentrations or duplicate times, or if the dose rows of a subject are not a valid protocol (a dose time which is not a number, a negative amount, a missing infusion duration), named with the subject.

read_adnca

read_adnca(
    df,
    *,
    time_unit="hr",
    unit=None,
    dose_unit=None,
    route=None,
    subject_col="USUBJID",
    analyte=None,
    analytes=None,
    param_col="PARAMCD",
    value_col="AVAL",
    value_unit_col="AVALU",
    time_first_col="AFRLT",
    time_ref_col="ARRLT",
    dose_col="DOSEA",
    dose_unit_col="DOSEU",
    duration_col="ADUR",
    nominal_time_col="NRRLT",
    route_col="ROUTE",
    dtype_col="DTYPE",
    lloq_col="ALLOQ",
    dim="individual",
    analyte_dim=ANALYTE_DIM,
    substance=None,
    covariates=(),
)

Read a batch from a CDISC ADaM ADNCA (ADPC) dataset.

The dataset holds one row per concentration record of one analyte (PARAMCD), with the time since the first dose (AFRLT) and the time since the most recent dose (ARRLT) (CDISC ADNCA). The time of a record is AFRLT, so the dose times of a subject are the distinct values of AFRLT - ARRLT with the amount DOSEA of their records. Derived copies of a record (DTYPE == "COPY", the pre-dose record duplicated into the previous interval) are dropped.

The infusion duration is the ADUR of the records of a dose (duration_col), which not every dataset carries: without the column an infusion protocol cannot be read and a route of Route.IV_INFUSION raises (Dosing requires a positive duration for every dose), and such a study is read from the event records or from the PKNCA tables instead, which carry the duration or the rate.

analytes reads several analytes of the dataset into one batch: every analyte is read on its own and the batches are stacked along the sample dimension analyte_dim, whose coordinate substance names the analyte of every row (_stack_analytes). The analysis then follows the substance of every sample and pkpdutils.nca.analytes.metabolite_ratio divides one by the other.

Parameters:

Name Type Description Default
df DataFrame

the ADNCA dataset

required
time_unit str

unit of the time columns

'hr'
unit str | None

unit of the values, the first AVALU of the analyte by default

None
dose_unit str | None

unit of the doses, the first DOSEU by default

None
route Route | None

route of the doses, a Route or a string it coerces, the first ROUTE by default

None
subject_col str

name of the subject column

'USUBJID'
analyte str | None

the analyte to read, the single analyte of the dataset by default

None
analytes Sequence[str] | None

the analytes to read into one batch, which gives the sample dimension analyte_dim and the coordinate substance along it; None reads the single analyte of analyte

None
param_col str

name of the parameter code column

'PARAMCD'
value_col str

name of the value column

'AVAL'
value_unit_col str

name of the unit column of the values

'AVALU'
time_first_col str

name of the column with the time since the first dose

'AFRLT'
time_ref_col str

name of the column with the time since the reference dose

'ARRLT'
dose_col str

name of the dose amount column

'DOSEA'
dose_unit_col str

name of the unit column of the doses

'DOSEU'
duration_col str | None

name of the infusion duration column, absent in most datasets; the records of one dose must agree on it, None reads no duration

'ADUR'
nominal_time_col str | None

name of the nominal (planned) time column, absent in many datasets; it becomes the variable nominal_time over (dim, time), in the time frame the column itself uses (NRRLT is the nominal time within the dosing interval, NFRLT the one since the first dose, which is the frame of the observation times the reader writes); None reads no nominal time

'NRRLT'
route_col str

name of the route column

'ROUTE'
dtype_col str

name of the derivation type column

'DTYPE'
lloq_col str

name of the column with the lower limit of quantification; it becomes the coordinate lloq along dim

'ALLOQ'
dim str

name of the sample dimension of the batch

'individual'
analyte_dim str

name of the sample dimension of analytes

ANALYTE_DIM
substance str | None

name of the substance, the analyte by default

None
covariates Sequence[str]

further columns which are constant within a subject; they become coordinates along dim

()

Returns:

Type Description
Timecourses

The batch, the subjects in the order of their first appearance and

Timecourses

their USUBJID as the coordinate of dim.

Raises:

Type Description
ValueError

if a required column is missing, if both analyte and analytes are given, if both are None and the dataset holds several analytes, if a unit or a route cannot be read, if the route is Route.IV_INFUSION without a duration column (the error names the subject), if a subject has fewer than two records or duplicate times, if the records of one dose time of a subject disagree on the dose amount or on the duration, or if a covariate column is not in the dataset or not constant within a subject.

write_pknca

write_pknca(
    timecourses,
    conc_path=None,
    dose_path=None,
    *,
    conc_col="conc",
    time_col="time",
    dose_col="dose",
    dose_time_col="time",
    subject_col="subject",
    duration_col="duration",
    analyte_col="analyte",
)

Write a batch as the two tables of PKNCA, the inverse of read_pknca.

The concentration table holds one row per sample and observation (the subject, the time and the value, NaN for a missing one) and the dose table one row per sample and dose of its protocol (the subject, the dose time, the amount and, for an infusion, its duration). The coordinates along the subject dimension become further columns of the concentration table, which read_pknca reads back as covariates; a batch of several analytes (a substance coordinate along a second sample dimension) writes the analyte of every row into analyte_col in both tables, which read_pknca reads back as analytes.

Parameters:

Name Type Description Default
timecourses Timecourses

the batch, with one sample dimension or with an analyte dimension besides it

required
conc_path str | Path | None

file to write the concentration table to, None to write no file

None
dose_path str | Path | None

file to write the dose table to, None to write no file

None

Other Parameters:

Name Type Description
conc_col str

name of the concentration column

time_col str

name of the time column of the concentration table

dose_col str

name of the dose amount column

dose_time_col str

name of the time column of the dose table

subject_col str

name of the subject column of both tables

duration_col str

name of the infusion duration column, written only when the batch carries a duration

analyte_col str

name of the analyte column, written only for a batch of several analytes

Returns:

Type Description
tuple[DataFrame, DataFrame]

The concentration table and the dose table.

Raises:

Type Description
ValueError

if the batch does not have the sample dimensions of a table (_writer_dims).

write_adnca

write_adnca(
    timecourses,
    path=None,
    *,
    subject_col="USUBJID",
    param_col="PARAMCD",
    value_col="AVAL",
    value_unit_col="AVALU",
    time_first_col="AFRLT",
    time_ref_col="ARRLT",
    dose_col="DOSEA",
    dose_unit_col="DOSEU",
    duration_col="ADUR",
    nominal_time_col="NRRLT",
    route_col="ROUTE",
    lloq_col="ALLOQ",
)

Write a batch as a CDISC ADaM ADNCA (ADPC) dataset, the inverse of read_adnca.

One row per sample and observation: AFRLT the time of the record, ARRLT its time since the reference dose (the last dose at or before it, the first dose for a record before it) and DOSEA the amount of that dose, which is how read_adnca recovers the protocol of a subject. ADUR is the duration of the reference dose of an infusion, ALLOQ the limit of quantification of the subject and PARAMCD its analyte. The coordinates along the subject dimension become further columns, which read_adnca reads back as covariates. No row is a DTYPE == "COPY" duplicate.

A dose which is not followed by an observation is not the reference dose of any record and is therefore not in the dataset, which is a property of the format rather than of the writer: the protocol of a subject lives in the concentration records.

Parameters:

Name Type Description Default
timecourses Timecourses

the batch, with one sample dimension or with an analyte dimension besides it

required
path str | Path | None

file to write to, None to write no file

None

Other Parameters:

Name Type Description
subject_col str

name of the subject column

param_col str

name of the analyte column

value_col str

name of the value column

value_unit_col str

name of the unit column of the values

time_first_col str

name of the column with the time since the first dose

time_ref_col str

name of the column with the time since the reference dose

dose_col str

name of the dose amount column

dose_unit_col str

name of the unit column of the doses

duration_col str

name of the infusion duration column, written only when the batch carries a duration

nominal_time_col str

name of the nominal (planned) time column, written only when the batch carries the variable nominal_time

route_col str

name of the route column

lloq_col str

name of the column with the limit of quantification, written only when the batch carries one

Returns:

Type Description
DataFrame

The dataset.

Raises:

Type Description
ValueError

if the batch does not have the sample dimensions of a table (_writer_dims).