NONMEM 语法对照#

本节中提供了一些在 NONMEM 中常用的模型与 Maspectra 的对照:

我们将通过三种建模方式,对同一个模型 (血管外给药一室模型, Extravascular One Compartment Model with Linear Elimination) 进行模型拟合。

基础自定义模型#

根据模型中央室的浓度 (Concentration) 公式

\[\begin{split} C_{central}(t) = \begin{cases} 0 & \text{if } t \leq T_{alag} \\ \frac{Dose}{V} \cdot \frac{K_a}{K_a - K} \cdot \left( e^{-K \cdot (t - T_{alag})} - e^{-K_a \cdot (t - T_{alag})} \right) & \text{if } t > T_{alag} \end{cases} \end{split}\]

可定义含吸收延迟的模型为:

from mas.model import *


class Warfarin(Module):
    def __init__(self) -> None:
        super().__init__()

        # 定义 theta 参数及初值
        self.pop_v = theta(7.81, bounds=(0, None))
        self.pop_cl = theta(0.134, bounds=(0, None))
        self.pop_ka = theta(0.571, bounds=(0, None))
        self.pop_alag = theta(0.823, bounds=(0, None))

        # 定义 eta/omega 参数及 omega 的方差初值
        self.eta_v = omega(0.049)
        self.eta_cl = omega(0.0802)
        self.eta_ka = omega(0.47)
        self.eta_alag = omega(0.156)

        # 定义 epsilon/sigma 参数及 sigma 的方差初值
        self.eps_prop = sigma(0.0104)
        self.eps_add = sigma(0.554)

        # 设置模型中需要的数据列 (结构模型所需变量、协变量)
        self.dose = column("DOSE")
        self.time = column("TIME")

        self.wt = column("WT)  # 体重协变量

    def pred(self):
        v = self.pop_v * exp(self.eta_v)
        cl = self.pop_cl * exp(self.eta_cl)
        ka = self.pop_ka * exp(self.eta_ka)
        alag = self.pop_alag * exp(self.eta_alag)
        k = cl / v

        ipred = 0
        if self.time > alag:
            ipred = self.dose / v * ka / (ka - k) * (exp(-k * (self.time - alag)) - exp(-ka * (self.time - alag)))

        y = ipred * (1 + self.eps_prop) + self.eps_add

        return y

model = PopModel(mod=Warfarin, data=warfarin)
fit_res = model.fit(FOCEi(maxiter=9999, print=10), cov=True)
fit_res.summary()
$PROBLEM Warfarin PK Model
$DATA warfarin.csv IGNORE=#
$INPUT ID TIME AMT DV DVID MDV DOSE WT AGE SEX

$PRED
V = THETA(1) * EXP(ETA(1))
CL = THETA(2) * EXP(ETA(2))
KA = THETA(3) * EXP(ETA(3))
ALAG = THETA(4) * EXP(ETA(4))
K = CL / V

IPRED = 0
IF (TIME>ALAG) THEN
IPRED = DOSE / V * KA / (KA - K) * (EXP(-K * (TIME - ALAG)) - EXP(-KA * (TIME - ALAG)))
ENDIF

Y = IPRED * (1 + EPS(1)) + EPS(2)

$THETA
(0.0, 7.81, 1000000.0)   ; pop_v
(0.0, 0.134, 1000000.0)  ; pop_cl
(0.0, 0.571, 1000000.0)  ; pop_ka
(0.0, 0.823, 1000000.0)  ; pop_alag

$OMEGA 0.049
$OMEGA 0.0802
$OMEGA 0.47
$OMEGA 0.156

$SIGMA 0.0104
$SIGMA 0.554

$ESTIMATION METHOD=COND INTER MAXEVAL=9999 PRINT=10
$COVARIANCE

内置药动学房室模型#

因为该模型较常用,在 Maspectra 和 NONMEM 软件中均以内置模型库形式支持,以简化建模、提升拟合速度。

from mas.model import *


class Warfarin(EvOneCmtLinear):
    # EvOneCmtLinear 代表血管外给药一室模型 (Extravascular One Compartment Model with Linear Elimination)
    # 对应 NONMEM 的 ADVAN2
    def __init__(self) -> None:
        super().__init__()

        # 定义 theta 参数及初值
        self.pop_cl = theta(0.134, bounds=(0, None))
        self.pop_v = theta(7.81, bounds=(0, None))
        self.pop_ka = theta(0.571, bounds=(0, None))
        self.pop_alag = theta(0.823, bounds=(0, None))

        # 定义 eta/omega 参数及 omega 的方差初值
        self.eta_cl = omega(0.049)
        self.eta_v = omega(0.0802)
        self.eta_ka = omega(0.047)
        self.eta_alag = omega(0.156)

        # 定义 epsilon/sigma 参数及 sigma 的方差初值
        self.eps_prop = sigma(0.0104)
        self.eps_add = sigma(0.554)

    def pred(self) -> Expression:
        cl = self.pop_cl * exp(self.eta_cl)
        v = self.pop_v * exp(self.eta_v)
        ka = self.pop_ka * exp(self.eta_ka)
        alag = self.pop_alag * exp(self.eta_alag)

        # 使用生理意义参数形式 (Physiological, 即使用 CL/Q 等参数)
        # 对应 NONMEM 中 TRANS2
        pred_res = self.pred_physio(cl=cl, v=v, ka=ka, alag1=alag, s2=v)
        ipred = pred_res.F

        y = ipred * (1 + self.eps_prop) + self.eps_add

        return y


model = PopModel(mod=Warfarin, data=warfarin)
fit_res = model.fit(FOCEi(maxiter=9999, print=10), cov=True)
fit_res.summary()
$PROBLEM Warfarin PK Model
$DATA warfarin.csv IGNORE=#
$INPUT ID TIME AMT DV DVID MDV WT AGE SEX
$SUBROUTINES ADVAN2 TRANS2

$PK
CL = THETA(1) * EXP(ETA(1))
V = THETA(2) * EXP(ETA(2))
KA = THETA(3) * EXP(ETA(3))
ALAG1 = THETA(4) * EXP(ETA(4))
S2 = V

$ERROR
IPRED = F
T = IPRED * (1 + EPS(1)) + EPS(2)

$THETA
(0.0, 7.81, 1000000.0)   ; pop_v
(0.0, 0.134, 1000000.0)  ; pop_cl
(0.0, 0.571, 1000000.0)  ; pop_ka
(0.0, 0.823, 1000000.0)  ; pop_alag

$OMEGA 0.049
$OMEGA 0.0802
$OMEGA 0.47
$OMEGA 0.156

$SIGMA 0.0104
$SIGMA 0.554

$ESTIMATION METHOD=COND INTER MAXEVAL=9999 PRINT=10
$COVARIANCE

ADVAN/TRANS 与 Maspectra 的对照表为:

ADVAN 与 TRANS 编号

Maspectra 模型类名与方法

ADVAN1 TRANS1

IvOneCmtLinear.pred_micro

ADVAN1 TRANS2

IvOneCmtLinear.pred_physio

ADVAN2 TRANS1

EvOneCmtLinear.pred_micro

ADVAN2 TRANS2

EvOneCmtLinear.pred_physio

ADVAN3 TRANS1

IvTwoCmtLinear.pred_micro

ADVAN3 TRANS3

IvTwoCmtLinear.pred_physio_vss

ADVAN3 TRANS4

IvTwoCmtLinear.pred_physio

ADVAN3 TRANS5

IvTwoCmtLinear.pred_macro_aob

ADVAN3 TRANS6

IvTwoCmtLinear.pred_macro_micro

ADVAN4 TRANS1

EvTwoCmtLinear.pred_micro

ADVAN4 TRANS3

EvTwoCmtLinear.pred_physio_vss

ADVAN4 TRANS4

EvTwoCmtLinear.pred_physio

ADVAN4 TRANS5

EvTwoCmtLinear.pred_macro_aob

ADVAN4 TRANS6

EvTwoCmtLinear.pred_macro_micro

微分方程模型#

我们也可以基于该模型各房室药量 (Amount) 的微分方程

\[\begin{split} \begin{align*} \frac{dA_{depot}}{dt} &= -k_a \cdot A_{depot} \\ \frac{dA_{central}}{dt} &= k_a \cdot A_{depot} - k \cdot A_{central} \end{align*} \end{split}\]

定义相同的模型:

from mas.model import *


class Warfarin(OdeModule):
    def __init__(self) -> None:
        # 设置 ODE 算法
        # DVERK 算法对应 ADVAN6, LSODA 算法对应 ADVAN13 , 
        super().__init__(solver=odeint.DVERK(tol=1e-3))

        # 定义模型房室
        self.depot_cmt = compartment(default_dose=True)
        self.central_cmt = compartment(default_obs=True)

        # 定义 theta 参数及初值
        self.pop_v = theta(7.81, bounds=(0, None))
        self.pop_cl = theta(0.134, bounds=(0, None))
        self.pop_ka = theta(0.571, bounds=(0, None))
        self.pop_alag = theta(0.823, bounds=(0, None))

        # 定义 eta/omega 参数及 omega 的方差初值
        self.eta_v = omega(0.049)
        self.eta_cl = omega(0.0802)
        self.eta_ka = omega(0.47)
        self.eta_alag = omega(0.156)

        # 定义 epsilon/sigma 参数及 sigma 的方差初值
        self.eps_prop = sigma(0.0104)
        self.eps_add = sigma(0.554)

    def pred(self) -> Expression:
        cl = self.pop_cl * exp(self.eta_cl)
        v = self.pop_v * exp(self.eta_v)
        ka = self.pop_ka * exp(self.eta_ka)

        k = cl / v

        # 设置 depot 房室的吸收延迟参数
        alag1 = self.pop_alag * exp(self.eta_alag)
        self.depot_cmt.alag = alag1

        # 定义微分方差
        self.depot_cmt.dAdt = -ka * self.depot_cmt.A
        self.central_cmt.dAdt = ka * self.depot_cmt.A - k * self.central_cmt.A

        ipred = self.central_cmt.A / v
        y = ipred * (1 + self.eps_prop) + self.eps_add

        return y

model = PopModel(mod=Warfarin, data=warfarin)
fit_res = model.fit(FOCEi(maxiter=9999, print=10), cov=True)
fit_res.summary()
$PROBLEM Warfarin PK Model
$DATA warfarin.csv IGNORE=#
$INPUT ID TIME AMT DV DVID MDV WT AGE SEX
$SUBROUTINES ADVAN6 TRANS1 TOL=3
$MODEL COMP(dose_cmt, DEFDOSE) COMP(central_cmt, DEFOBS)

$PK
V = THETA(1) * EXP(ETA(1))
CL = THETA(2) * EXP(ETA(2))
KA = THETA(3) * EXP(ETA(3))
ALAG1 = THETA(4) * EXP(ETA(4))
K = CL / V

$DES
DADT(1) = -KA * A(1)
DADT(2) = KA * A(1) - K * A(2)

$ERROR
IPRED = A(2) / V
Y = IPRED * (1 + EPS(1)) + EPS(2)

$THETA
(0.0, 7.81, 1000000.0)   ; pop_v
(0.0, 0.134, 1000000.0)  ; pop_cl
(0.0, 0.571, 1000000.0)  ; pop_ka
(0.0, 0.823, 1000000.0)  ; pop_alag

$OMEGA 0.049
$OMEGA 0.0802
$OMEGA 0.47
$OMEGA 0.156

$SIGMA 0.0104
$SIGMA 0.554

$ESTIMATION METHOD=COND INTER MAXEVAL=9999 PRINT=10
$COVARIANCE