using Random
using Pumas
using PumasUtilities
using CairoMakie
using AlgebraOfGraphics
using DataFramesMeta
using CSV
using Dates
PK47 - Plasma protein binding modeling
1 Background
- Structural Model - Plasma Protein Binding Model
- Number of Subjects - 4
- Number of Compounds - 2
2 Learning Outcome
- To get an understanding of the determinants of the unbound concentration, free fraction and total concentration.
- How the modeling of plasma protein data is done
- To understand how the binding protein concentration affects the unbound drug concentration
3 Objectives
- To analyze In vitro plasma protein data of two compounds
- To analyze binding data at two different binding concentration
- To show and understand the relationship between Cu and fu
- To understand the properties of binding sites that can be modeled
4 Libraries
Call the necessary libraries to get started
5 Model
= @model begin
pk_47 @metadata begin
= "Plasma Protein Binding Model"
desc end
@param begin
"""
Affinity constant between drug and protein
"""
∈ RealDomain(lower = 0)
tvka """
Number of binding sites per molecule
"""
∈ RealDomain(lower = 0)
tvn ∈ PDiagDomain(2)
Ω """
Additive RUV
"""
∈ RealDomain(lower = 0)
σ_add end
@random begin
~ MvNormal(Ω)
η end
@covariates dose Pt
@pre begin
= tvka * exp(η[1])
Ka = tvn * exp(η[2])
n = dose
_dose = Pt
_Pt end
@vars begin
= (1 - (1 / (1 + (_dose / (n * _Pt)) + (1 / (Ka * n * _Pt))))) * 100
fu end
@derived begin
= @. Normal(fu, σ_add)
dv end
end
PumasModel
Parameters: tvka, tvn, Ω, σ_add
Random effects: η
Covariates: dose, Pt
Dynamical system variables:
Dynamical system type: No dynamical model
Derived: dv, fu
Observed: dv, fu
6 Parameters
The parameters are as given below. Note that tv
represents the typical value for parameters.
tvka
- Affinity constant between drug and proteintvn
- Number of binding sites per molecule
6.1 Compound 1
= (; tvka = 6.09, tvn = 2.833, Ω = Diagonal([0.04, 0.04, 0.04]), σ_add = 2.0398) param1
6.2 Compound 2
= (; tvka = 10.2353, tvn = 1.937, Ω = Diagonal([0.04, 0.04, 0.04]), σ_add = 2.2774) param2
7 Dosage Regimen
Since there is no dosage regimen, we will create a DataFrame
with no events and read the file using read_pumas
, which will be used for simulation.
7.1 Compound 1
= DataFrame(
df_sub1 = "0.3mg Protein Conc",
id = 0:1:9999,
time = missing,
dv = 0.01:0.01:100,
dose = 0.3,
Pt
)= DataFrame(
df_sub2 = "50mg Protein Conc",
id = 0:1:9999,
time = missing,
dv = 0.01:0.01:100,
dose = 50,
Pt
)= vcat(df_sub1, df_sub2)
df1 = read_pumas(df1, observations = [:dv], covariates = [:dose, :Pt], event_data = false) pop1
Population
Subjects: 2
Covariates: dose, Pt
Observations: dv
7.2 Compound 2
= DataFrame(
df_sub3 = "0.3mg Protein Conc",
id = 0:1:9999,
time = missing,
dv = 0.01:0.01:100,
dose = 0.1,
Pt
)= DataFrame(
df_sub4 = "50mg Protein Conc",
id = 0:1:9999,
time = missing,
dv = 0.01:0.01:100,
dose = 10,
Pt
)= vcat(df_sub3, df_sub4)
df2 = read_pumas(df2, observations = [:dv], covariates = [:dose, :Pt], event_data = false) pop2
Population
Subjects: 2
Covariates: dose, Pt
Observations: dv
8 Simulation
We will now simulate the experimental data for Compound 1 at two different levels of protein concentration (Pt) 0.3 and 50.Since we are simulating only a single subject, we can zero out the random effects.
Random.seed!(123)
8.1 Compound 1
= zero_randeffs(pk_47, pop1, param1)
zfx = simobs(pk_47, pop1, param1, zfx)
sim_1
= reduce(
df47_cmp1
vcat,map(sim_1) do subj
= DataFrame(
subdf = subj.subject.id,
id = subj.observations.fu,
fu = subj.covariates.dose,
dose
)end,
)first(df47_cmp1, 5)
5×3 DataFrame
Row | id | fu | dose |
---|---|---|---|
String | Float64 | Float64 | |
1 | 0.3mg Protein Conc | 17.0104 | 0.01 |
2 | 0.3mg Protein Conc | 17.8129 | 0.02 |
3 | 0.3mg Protein Conc | 18.6 | 0.03 |
4 | 0.3mg Protein Conc | 19.3723 | 0.04 |
5 | 0.3mg Protein Conc | 20.13 | 0.05 |
8.2 Compound 2
= zero_randeffs(pk_47, pop2, param2)
zfx = simobs(pk_47, pop2, param2, zfx)
sim_2 = reduce(
df47_cmp2
vcat,map(sim_2) do subj
= DataFrame(
subdf = subj.subject.id,
id = subj.observations.fu,
fu = subj.covariates.dose,
dose
)end,
)first(df47_cmp2, 5)
5×3 DataFrame
Row | id | fu | dose |
---|---|---|---|
String | Float64 | Float64 | |
1 | 0.3mg Protein Conc | 35.7335 | 0.01 |
2 | 0.3mg Protein Conc | 37.7973 | 0.02 |
3 | 0.3mg Protein Conc | 39.7326 | 0.03 |
4 | 0.3mg Protein Conc | 41.5512 | 0.04 |
5 | 0.3mg Protein Conc | 43.2632 | 0.05 |
9 Visualization
9.1 Compound 1
@chain df47_cmp1 begin
@rsubset :dose ∈ [0.01, 0.05, 0.1, 0.5, 1, 5, 10, 50, 100]
data(_) *
mapping(
:dose => "Unbound concentration",
:fu => "Free Fraction (%)",
= :id => "",
color *
) visual(ScatterLines; linewidth = 4, markersize = 12)
draw(;
= (; fontsize = 22),
figure = (;
axis = 0:20:120,
yticks = log10,
xscale = i -> (@. string(round(i; digits = 1))),
xtickformat = "Compound 1 - Free fraction vs Unbound Concentration",
title
),= (; position = :bottom),
legend
)end
9.2 Compound 2
@chain df47_cmp2 begin
@rsubset :dose ∈ [0.01, 0.05, 0.1, 0.5, 1, 5, 10, 50, 100]
data(_) *
mapping(
:dose => "Unbound concentration",
:fu => "Free Fraction (%)",
= :id => "",
color *
) visual(ScatterLines; linewidth = 4, markersize = 12)
draw(;
= (; fontsize = 22),
figure = (;
axis = 0:20:120,
yticks = log10,
xscale = i -> (@. string(round(i; digits = 1))),
xtickformat = "Compound 2 - Free fraction vs Unbound Concentration",
title
),= (; position = :bottom),
legend
)end
10 Simulating Multiple Experiments
## Compound 1
= (; tvka = 6.09, tvn = 2.833, Ω = Diagonal([0.042, 0.0926, 0.0623]), σ_add = 2.0398)
par1
= [0, 1, 2, 3, 4, 5, 6, 7, 8]
time1 = [0.01, 0.05, 0.1, 0.5, 1, 5, 10, 50, 100]
dose
= map(
df1_cmp1 -> DataFrame(
i = i,
id = time1,
time = missing,
dv = dose,
dose = 0.3,
Pt = "A",
Compound
),1:12,
)= map(
df2_cmp1 -> DataFrame(
i = i,
id = time1,
time = missing,
dv = dose,
dose = 50,
Pt = "A",
Compound
),13:24,
)= vcat(df1_cmp1, df2_cmp1)
df12_cmp1 = vcat(DataFrame.(df12_cmp1)...)
df_cmp1 = read_pumas(
pop_cmp1
df_cmp1,= [:dv],
observations = [:dose, :Pt, :Compound],
covariates = false,
event_data
)
= simobs(pk_47, pop_cmp1, par1)
sim_cmp1 = DataFrame(sim_cmp1)
df_sim_cmp1
## Compound 2
=
par2 = 10.2353, tvn = 1.937, Ω = Diagonal([0.0225, 0.0378, 0.0135]), σ_add = 2.2774)
(; tvka
= map(
df1_cmp2 -> DataFrame(
i = i,
id = time1,
time = missing,
dv = dose,
dose = 0.1,
Pt = "B",
Compound
),1:12,
)= map(
df2_cmp2 -> DataFrame(
i = i,
id = time1,
time = missing,
dv = dose,
dose = 10,
Pt = "B",
Compound
),13:24,
)= vcat(df1_cmp2, df2_cmp2)
df12_cmp2 = vcat(DataFrame.(df12_cmp2)...)
df_cmp2 = read_pumas(
pop_cmp2
df_cmp2,= [:dv],
observations = [:dose, :Pt, :Compound],
covariates = false,
event_data
)
= simobs(pk_47, pop_cmp2, par2)
sim_cmp2 = DataFrame(sim_cmp2)
df_sim_cmp2
= vcat(df_sim_cmp1, df_sim_cmp2);
df_sim #CSV.write("pk_47.csv", df_sim)