Non-Compartmental Analysis (NCA) in Pumas

The NCA analysis itself is documented in the NCA.jl section of this manual: Data Parsing for reading the data, Running NCA for computing and summarizing the endpoints, and Endpoint Reference for the endpoints themselves.

This page covers what surrounds it in Pumas: getting the source data in, plotting the data and the results, and running NCA on a simulation of a Pumas model instead of on a dataset.

Read Source Data

Data Parsing provides the specification requirements of the source data. Currently, several file formats can be read in for analysis:

  • .csv (CSV package)
  • .xlsx (XLSX package)
  • .sas7bdat / .xpt (ReadStatTables package)
  • .arrow (Arrow package)

For this introduction we'll use the PharmaDatasets package and the po_sad_1 dataset:

using PharmaDatasets

pkdata = dataset("po_sad_1")
first(pkdata, 6)
6×14 DataFrame
RowidtimedvamtevidcmtrateagewtdoselevelisPMisfedsexroute
Int64Float64Float64?Float64?Int64Int64?Float64Int64Int64Int64String3String3String7String3
110.0missing30.0110.0517430noyesmaleev
210.2535.7636missing0missing0.0517430noyesmaleev
310.571.9551missing0missing0.0517430noyesmaleev
410.7597.3356missing0missing0.0517430noyesmaleev
511.0128.919missing0missing0.0517430noyesmaleev
612.0155.85missing0missing0.0517430noyesmaleev

In po_sad_1 the dosing events are interleaved with the observations: a dose is its own row, carrying the amount in amt, and the observation rows leave amt empty. That layout is read with read_nca_pumas:

using NCA

ncadata = read_nca_pumas(pkdata; concentration = :dv, dose = :amt, group = [:doselevel])
first(ncadata, 6)
6×13 DataFrame
Rowdoselevelidprofiletimenominal_timedose_timenominal_dose_timeconcentrationdoseroutedurationexclusionexclusion_mask
Int64Int64Int64Float64Float64Float64Float64Float64Float64StringMissingMissingBool
130110.250.250.00.035.763630.0evmissingmissingfalse
230110.50.50.00.071.955130.0evmissingmissingfalse
330110.750.750.00.097.335630.0evmissingmissingfalse
430111.01.00.00.0128.91930.0evmissingmissingfalse
530112.02.00.00.0155.8530.0evmissingmissingfalse
630114.04.00.00.0191.83530.0evmissingmissingfalse

Exploratory Data Analysis

Exploratory analysis of the profiles can be performed using the plotting functions that come with NCA. The NCA plots section provides more details, but here are some example syntax and the corresponding plots.

Observations-time plots

We can produce a plot of the concentration against time using observations_vs_time. Below is the code for generating this plot for the first subject, selected with the usual DataFrame filtering:

using DataFrames

subject1 = filter(:id => ==(1), ncadata)
observations_vs_time(
    subject1;
    axis = (; xlabel = "Time (hours)", ylabel = "CTM Concentration (mg L⁻¹)"),
)
Example block output

We can also use log-scale for the concentrations such that exponential decay shows as a straight line. Below is the code to set the y-scale to use the natural logarithm:

observations_vs_time(
    subject1;
    axis = (; xlabel = "Time (hours)", ylabel = "CTM Concentration (mg L⁻¹)", yscale = log),
)
Example block output

Other options are yscale = log10 and yscale = log2 for a base-10 and base-2 logarithm.

To generate these plots side-by-side we have to create a Figure-object first, and then pass fig[row,column] as the first argument. row specifies which row of the figure the element should be added to and column specifies the column number.

using CairoMakie
fig = Figure()
observations_vs_time(
    fig[1, 1],
    subject1;
    axis = (; xlabel = "Time (hours)", ylabel = "CTM Concentration (mg L⁻¹)"),
)
observations_vs_time(
    fig[1, 2],
    subject1;
    axis = (; xlabel = "Time (hours)", ylabel = "CTM Concentration (mg L⁻¹)", yscale = log),
)
fig
Example block output

Summary plots

We can also group all the subjects into a single summarizing plot of the concentration against time using summary_observations_vs_time:

summary_observations_vs_time(
    ncadata;
    axis = (; xlabel = "Time (hours)", ylabel = "CTM Concentration (mg L⁻¹)"),
)
Example block output

Subject fit plots

We can also check all the subject fits with:

subject_fits(ncadata; axis = (; yscale = log), rows = 3, columns = 3)
Example block output

Plot the results

The endpoints are computed with run_nca, described in Running NCA:

pk_nca = run_nca(ncadata)

Several of the plotting functions take that result rather than the profiles.

Parameter distributions

parameters_dist(pk_nca; parameter = :aucinf_obs, rows = 3, columns = 1)
Example block output

Parameter distribution by groups (ID or covariates)

parameters_vs_group(pk_nca; parameter = :aucinf_obs)
Example block output

Dose linearity

DoseLinearityPowerModel fits a power regression model between dose and one of the endpoints, and power_model visualizes it:

dose_lin = DoseLinearityPowerModel(pk_nca, :aucinf_obs; level = 0.95)
power_model(dose_lin)
Example block output

NCA on a simulation of a model

Pumas also provides a convenient way to perform NCA on the output of a simulation of a Pumas model, rather than on a dataset. This is discussed in the Model integrated NCA section.