随着药物研发复杂性的不断提高和个体化医疗需求的增长,定量药理学已成为现代药物研发和临床应用中不可或缺的一部分。定量药理学通过数学模型和计算机模拟,将药物在体内的行为与其治疗效果联系起来,为药物研发决策和临床用药方案优化提供了科学依据。
这是一份Manus整理的教程,虽然绝大部分内容我都看过,但难免有一本正经的胡说八道的地方,教程的正确性需要有智慧的眼光来看待。本教程旨在介绍如何使用R语言进行定量药理学分析和建模。R语言作为一种开源的统计分析工具,具有强大的数据处理和可视化能力,同时拥有丰富的专业扩展包,使其成为定量药理学研究的理想工具。无论您是药学研究人员、临床药师,还是对定量药理学感兴趣的学生,本教程都将帮助您掌握使用R语言进行药代动力学和药效学建模的基本技能。
本教程不要求读者具有深厚的编程背景,但基本的R语言知识将有助于更好地理解和应用教程内容。我们将从定量药理学的基础概念开始,逐步介绍R语言环境的设置、数据准备、模型构建、评估和应用,并通过实际案例展示定量药理学在药物研发和临床实践中的价值。
让我们开始这段探索定量药理学与R语言结合的旅程,共同揭示药物与人体相互作用的奥秘。
基于R语言的定量药理学教程#
随着药物研发复杂性的不断提高和个体化医疗需求的增长,定量药理学已成为现代药物研发和临床应用中不可或缺的一部分。定量药理学通过数学模型和计算机模拟,将药物在体内的行为与其治疗效果联系起来,为药物研发决策和临床用药方案优化提供了科学依据。
本教程旨在介绍如何使用R语言进行定量药理学分析和建模。R语言作为一种开源的统计分析工具,具有强大的数据处理和可视化能力,同时拥有丰富的专业扩展包,使其成为定量药理学研究的理想工具。无论您是药学研究人员、临床药师,还是对定量药理学感兴趣的学生,本教程都将帮助您掌握使用R语言进行药代动力学和药效学建模的基本技能。
本教程不要求读者具有深厚的编程背景,但基本的R语言知识将有助于更好地理解和应用教程内容。我们将从定量药理学的基础概念开始,逐步介绍R语言环境的设置、数据准备、模型构建、评估和应用,并通过实际案例展示定量药理学在药物研发和临床实践中的价值。
让我们开始这段探索定量药理学与R语言结合的旅程,共同揭示药物与人体相互作用的奥秘。
第一章:定量药理学基础#
1.1 定量药理学概述#
1.1.1 定义与发展历史#
定量药理学(Quantitative Pharmacology)是一门综合性学科,应用数学模型和计算机模拟技术来描述和预测药物与生物系统之间的相互作用。它整合了药理学、生理学、病理学、生物统计学和计算机科学等多个领域的知识,旨在量化药物在体内的行为及其治疗效果。
定量药理学的发展可以追溯到20世纪60年代,当时药代动力学(Pharmacokinetics, PK)的概念开始形成。随着计算机技术的进步,20世纪80年代出现了非线性混合效应模型(Nonlinear Mixed-Effects Model),使得群体药代动力学分析成为可能。进入21世纪,随着系统生物学和计算能力的发展,定量系统药理学(Quantitative Systems Pharmacology, QSP)和生理药代动力学(Physiologically-Based Pharmacokinetics, PBPK)等新兴领域不断扩展,使定量药理学的应用范围更加广泛。
1.1.2 在药物研发中的应用价值#
定量药理学在药物研发的各个阶段都发挥着重要作用:
临床前研究阶段:
- 帮助选择候选药物和确定首次人体试验剂量
- 预测药物在人体内的行为
- 评估药物安全性和有效性的潜在风险
临床研究阶段:
- 优化临床试验设计和采样方案
- 分析剂量-暴露-反应关系
- 评估特殊人群(如儿童、老年人、肝肾功能不全患者)的给药方案
监管审批阶段:
- 提供药物安全性和有效性的定量证据
- 支持标签用法用量的确定
- 解释不同研究结果之间的差异
上市后阶段:
- 优化个体化给药方案
- 评估药物-药物相互作用
- 支持适应症扩展和剂型开发
美国食品药品监督管理局(FDA)和欧洲药品管理局(EMA)等监管机构已经认识到定量药理学的价值,并鼓励在药物开发中采用基于模型的药物研发(Model-Based Drug Development, MBDD)和模型引导下的药物研发(Model-Informed Drug Development, MIDD)策略。这些策略可以减少不必要的临床试验,提高研发效率,降低研发成本,并促进更安全、更有效的药物进入市场。
1.1.3 与传统药理学的区别#
传统药理学主要关注药物作用的定性描述和机制研究,而定量药理学则强调通过数学模型对药物行为进行定量预测和解释。两者的主要区别包括:
特点 | 传统药理学 | 定量药理学 |
---|
研究方法 | 实验观察为主 | 结合实验数据和数学模型 |
数据分析 | 以统计分析为主 | 以模型拟合和模拟为主 |
预测能力 | 有限,主要基于经验 | 强,可进行定量预测 |
个体差异 | 难以量化 | 可通过模型参数量化 |
应用范围 | 主要用于机制研究 | 广泛应用于研发决策和临床实践 |
定量药理学并不是要取代传统药理学,而是在其基础上发展出的一种更加定量化、系统化的研究方法,两者相辅相成,共同推动药物研究的发展。
1.2 定量药理学的核心概念#
1.2.1 药代动力学(PK)基础#
药代动力学(Pharmacokinetics, PK)研究药物在体内的吸收(Absorption)、分布(Distribution)、代谢(Metabolism)和排泄(Excretion)过程,简称ADME过程。PK描述了"机体对药物的作用",主要关注药物浓度随时间的变化。
基本参数:
清除率(Clearance, CL):单位时间内从血液中清除药物的血液体积,通常以L/h表示。
分布容积(Volume of Distribution, V):药物在体内的表观分布空间,通常以L表示。
半衰期(Half-life, t1/2):血药浓度降低到峰值的一半所需的时间,通常以h表示。
t1/2 = 0.693 × V / CL
生物利用度(Bioavailability, F):药物进入体循环的比例,静脉给药的F为1(或100%)。
吸收速率常数(Absorption Rate Constant, Ka):描述药物从给药部位吸收到体循环的速率。
房室模型:
药代动力学常用房室模型来描述药物在体内的分布和消除。常见的房室模型包括:
一室模型:将全身视为一个均质的房室,适用于分布迅速的药物。
二室模型:包括中央室(血液和血流丰富组织)和外周室(血流较少的组织),适用于分布相对缓慢的药物。
三室模型:在二室模型基础上增加一个深层外周室,适用于分布更为复杂的药物。
非房室模型分析(NCA):
非房室模型分析是一种不依赖于特定房室模型假设的PK分析方法,通过计算浓度-时间曲线下面积(AUC)等参数来表征药物暴露。主要参数包括:
最大浓度(Cmax):观察到的最高血药浓度。
达峰时间(Tmax):达到Cmax的时间。
浓度-时间曲线下面积(AUC):反映药物总暴露量。
终末消除速率常数(λz):药物终末相消除的速率常数。
1.2.2 药效学(PD)基础#
药效学(Pharmacodynamics, PD)研究药物与靶点相互作用产生的生物效应,描述了"药物对机体的作用",主要关注药物浓度与效应之间的关系。
基本概念:
效应器(Effector):药物作用的靶点,如受体、酶、离子通道等。
激动剂(Agonist):与靶点结合后能激活靶点产生效应的药物。
拮抗剂(Antagonist):与靶点结合后能阻断激动剂作用的药物。
效能(Efficacy):药物产生最大效应的能力。
效力(Potency):产生特定效应所需的药物浓度,通常用EC50(产生50%最大效应的浓度)表示。
浓度-效应关系模型:
Emax模型:
E = (Emax × C) / (EC50 + C)
其中,E为效应,Emax为最大效应,C为药物浓度,EC50为产生50%最大效应的浓度。
Sigmoid Emax模型:
E = (Emax × C^n) / (EC50^n + C^n)
其中,n为Hill系数,描述浓度-效应曲线的陡峭程度。
线性模型:
E = Slope × C
适用于浓度范围较窄且远低于EC50的情况。
对数线性模型:
E = Slope × log(C)
适用于某些具有高内在变异性的数据。
时间-效应关系:
药效学效应可以根据与给药时间的关系分为:
直接效应:效应与药物浓度同步变化,无明显滞后。
间接效应:效应与药物浓度之间存在时间滞后,通常通过影响生理过程的产生或消除率来实现。
滞后效应:效应出现明显滞后,可能涉及复杂的信号转导或生理适应过程。
1.2.3 PK/PD整合模型#
PK/PD整合模型将药代动力学和药效学结合起来,描述从给药到效应的完整过程,即剂量-浓度-效应关系。这种整合模型有助于理解药物作用的时间过程和剂量依赖性。
常见的PK/PD整合模型:
直接效应模型:
假设效应与药物浓度直接相关,无时间滞后。
E = f(C),其中f可以是Emax模型、Sigmoid模型等。
效应室模型:
引入一个假设的"效应室",药物需要从中央室扩散到效应室才能产生效应,用于解释观察到的PK和PD之间的时间滞后。
dCe/dt = k1e × C - ke0 × Ce
E = f(Ce)
其中,Ce为效应室浓度,k1e为药物从中央室到效应室的传递速率常数,ke0为药物从效应室消除的速率常数。
间接响应模型:
药物通过影响生理过程的产生率或消除率来间接产生效应。
- 模型I:抑制产生率
- 模型II:促进消除率
- 模型III:促进产生率
- 模型IV:抑制消除率
耐受性模型:
描述长期给药后药效减弱的现象,通常通过引入一个反馈变量来实现。
疾病进展模型:
结合疾病自然进展和药物干预效应,适用于慢性疾病的长期治疗。
PK/PD整合模型的建立有助于:
- 确定合理的给药方案
- 预测不同剂量下的疗效和安全性
- 解释个体间差异
- 支持特殊人群的剂量调整
- 优化临床试验设计
1.3 非线性混合效应模型#
非线性混合效应模型(Nonlinear Mixed-Effects Model)是定量药理学中广泛应用的统计方法,用于分析来自多个个体的稀疏数据,同时考虑个体间和个体内变异。这种方法特别适合群体药代动力学和药效学分析。
1.3.1 模型组成#
非线性混合效应模型通常包括三个主要组成部分:
结构模型(Structural Model):
描述药物在典型个体中的行为,如一室、二室或三室PK模型,或各种PD模型。结构模型参数也称为固定效应参数(Fixed Effects Parameters),代表群体平均水平。
统计学模型(Statistical Model):
描述参数变异的概率分布,包括:
个体间变异(Inter-Individual Variability, IIV):
不同个体之间参数值的差异,通常假设服从对数正态分布:
Pi = P × exp(ηi)
其中,Pi是个体i的参数值,P是群体典型值,ηi是个体随机效应,假设服从均值为0、方差为ω²的正态分布。
个体内变异(Intra-Individual Variability, IOV):
同一个体在不同场合下参数值的差异。
残差变异(Residual Variability):
模型预测值与观测值之间的差异,可以采用加性误差、比例误差或组合误差模型。
协变量模型(Covariate Model):
描述个体特征(如年龄、体重、性别、肝肾功能等)对模型参数的影响,有助于解释部分个体间变异并支持个体化给药。常见的协变量关系包括:
线性关系:
P = θ1 + θ2 × (COV - COVmedian)
幂函数关系:
P = θ1 × (COV/COVmedian)^θ2
指数关系:
P = θ1 × exp[θ2 × (COV - COVmedian)]
1.3.2 参数估计方法#
非线性混合效应模型的参数估计通常采用最大似然法,主要方法包括:
一阶条件估计法(First-Order Conditional Estimation, FOCE):
在每次迭代中,基于当前参数估计值计算个体随机效应,然后更新参数估计。
随机期望最大化算法(Stochastic Approximation Expectation-Maximization, SAEM):
结合蒙特卡洛模拟和EM算法,特别适合处理复杂模型和稀疏数据。
马尔可夫链蒙特卡洛方法(Markov Chain Monte Carlo, MCMC):
基于贝叶斯方法,通过模拟参数的后验分布进行估计。
1.3.3 模型评估#
非线性混合效应模型的评估通常包括:
目标函数值(Objective Function Value, OFV):
-2倍对数似然值,用于比较嵌套模型。
参数精度:
通过标准误差、置信区间或引导法评估。
诊断图:
- 观测值vs群体预测值(PRED)
- 观测值vs个体预测值(IPRED)
- 条件加权残差(CWRES)vs时间或预测值
- 视觉预测检验(Visual Predictive Check, VPC)
收敛性:
评估模型是否成功收敛,参数估计是否稳定。
模型稳健性:
通过改变初始估计值或使用不同估计方法检验模型稳定性。
1.4 定量药理学在药物研发中的应用#
1.4.1 临床试验设计优化#
定量药理学可以帮助优化临床试验设计,提高试验效率和成功率:
剂量选择:
- 基于临床前数据预测人体有效剂量范围
- 确定剂量递增试验的起始剂量和递增步骤
- 设计剂量-反应研究以确定最佳治疗剂量
采样方案优化:
- 确定关键采样时间点,最大化信息获取
- 减少不必要的采样,降低受试者负担
- 设计群体PK研究的稀疏采样策略
终点选择:
- 确定合适的药效学标志物
- 预测临床终点与替代终点的关系
- 评估不同终点的敏感性和特异性
样本量估计:
- 基于模拟确定检测治疗效果所需的最小样本量
- 考虑个体间变异对样本量的影响
- 评估不同试验设计的统计效能
1.4.2 给药方案个体化#
定量药理学为个体化给药提供了科学依据:
基于协变量的剂量调整:
- 根据体重、年龄、性别等人口学特征调整剂量
- 基于肝肾功能指标调整剂量
- 考虑遗传多态性对药物代谢的影响
治疗药物监测(Therapeutic Drug Monitoring, TDM):
- 确定治疗窗(有效浓度范围)
- 基于测量的药物浓度调整后续剂量
- 贝叶斯方法整合先验信息和实测数据
特殊给药方案设计:
- 负荷剂量和维持剂量的确定
- 间歇给药方案的优化
- 持续输注速率的计算
联合用药策略:
- 预测药物相互作用的影响
- 优化联合用药的剂量比例
- 调整给药时间以最大化协同作用
1.4.3 特殊人群剂量调整#
定量药理学在特殊人群用药中发挥重要作用:
儿科人群:
- 基于生长发育阶段的生理变化预测药物行为
- 考虑年龄相关的器官功能发育对剂量的影响
- 设计适合儿童的给药方案和剂型
老年人群:
- 考虑生理功能衰退对药物代谢和排泄的影响
- 评估多重用药的风险
- 根据器官功能调整剂量
肝肾功能不全患者:
- 量化肝肾功能对药物清除的影响
- 建立肝肾功能指标与剂量调整的关系
- 预测不同程度功能损伤下的药物暴露
孕妇:
- 考虑妊娠期生理变化对药代动力学的影响
- 评估胎儿暴露风险
- 在保证母亲治疗效果的同时最小化胎儿风险
特定疾病状态:
- 评估疾病对药物处置的影响
- 考虑疾病进展对药效的影响
- 根据疾病严重程度调整治疗策略
通过定量药理学方法,可以在有限的数据基础上,为特殊人群提供更加科学、合理的用药建议,提高治疗效果,降低不良反应风险。
本章介绍了定量药理学的基本概念、核心原理和应用价值。定量药理学通过数学模型和计算机模拟,将药物在体内的行为与其治疗效果联系起来,为药物研发决策和临床用药方案优化提供了科学依据。
药代动力学描述了"机体对药物的作用",关注药物在体内的吸收、分布、代谢和排泄过程;药效学描述了"药物对机体的作用",关注药物浓度与效应之间的关系;PK/PD整合模型将两者结合,描述从给药到效应的完整过程。
非线性混合效应模型是定量药理学中广泛应用的统计方法,通过结构模型、统计学模型和协变量模型,同时考虑群体趋势和个体变异,为群体药代动力学和药效学分析提供了强大工具。
定量药理学在药物研发的各个阶段都发挥着重要作用,包括临床试验设计优化、给药方案个体化和特殊人群剂量调整等。随着计算技术的进步和监管要求的提高,定量药理学将在药物研发和临床实践中发挥越来越重要的作用。
在接下来的章节中,我们将介绍如何使用R语言实现这些定量药理学概念和方法,从环境设置、数据准备到模型构建、评估和应用,帮助读者掌握定量药理学的实际操作技能。
第二章:R语言基础与环境设置#
2.1 R语言简介#
2.1.1 R语言的特点与优势#
R语言是一种专为统计计算和数据分析设计的编程语言和软件环境,由Ross Ihaka和Robert Gentleman于1993年开发。作为GNU项目的一部分,R是自由、开源的软件,可在各种操作系统上运行,包括Windows、macOS和Linux。
R语言在定量药理学领域具有以下优势:
开源免费:与商业软件(如NONMEM、Phoenix NLME等)相比,R完全免费,降低了研究成本。
统计分析能力强:R最初就是为统计分析设计的,拥有丰富的统计函数和方法,能够满足药理学研究中复杂的统计需求。
图形可视化出色:R提供了强大的数据可视化功能,可以创建高质量的科学图表,这对于展示药代动力学和药效学结果至关重要。
扩展包生态系统丰富:R拥有超过18,000个扩展包,其中包括专门用于药理学分析的包,如nlmixr、mrgsolve、RxODE等。
可重复性研究支持:R支持脚本化分析,便于研究结果的重现和验证,符合现代科学研究的可重复性要求。
社区支持活跃:R拥有庞大的用户社区,提供丰富的学习资源、技术支持和最新发展信息。
与其他工具集成能力强:R可以与其他编程语言(如C++、Python)和数据库系统集成,增强了其应用灵活性。
2.1.2 与其他编程语言的比较#
在定量药理学领域,除了R语言外,还有其他几种常用的编程语言和软件工具。下面是R与这些工具的简要比较:
特性 | R | Python | MATLAB | SAS | NONMEM |
---|
开源免费 | ✓ | ✓ | ✗ | ✗ | ✗ |
学习曲线 | 中等 | 平缓 | 中等 | 陡峭 | 陡峭 |
统计分析能力 | 强 | 中等 | 中等 | 强 | 中等 |
图形可视化 | 强 | 强 | 强 | 弱 | 弱 |
药理学专用包 | 丰富 | 有限 | 有限 | 有限 | 专用软件 |
计算效率 | 中等 | 高 | 高 | 高 | 高 |
社区支持 | 活跃 | 非常活跃 | 活跃 | 有限 | 专业支持 |
监管认可度 | 中等 | 中等 | 高 | 高 | 高 |
R语言在统计分析和图形可视化方面表现出色,且拥有丰富的药理学专用包,使其成为定量药理学研究的理想工具。虽然在计算效率上可能不如某些商业软件,但通过与C++等语言的集成,R也可以实现高效计算。
2.1.3 在定量药理学中的应用前景#
随着定量药理学在药物研发中的重要性不断提升,R语言在该领域的应用也日益广泛。未来的发展趋势包括:
开源模型库的扩展:更多的药代动力学和药效学模型将以R包的形式开放共享,促进知识交流和方法标准化。
与机器学习的结合:R强大的机器学习生态系统将与定量药理学模型结合,用于复杂关系的探索和预测。
实时分析和决策支持:基于R的交互式应用(如使用Shiny开发的Web应用)将用于临床试验中的实时数据分析和决策支持。
监管接受度提高:随着开源工具在药物研发中的应用增加,监管机构对基于R的分析结果的接受度也将提高。
教育和培训资源增加:更多的教育资源将帮助药理学研究人员掌握R语言,降低学习门槛。
与其他专业软件的接口改进:R与NONMEM、Phoenix等专业软件的接口将进一步完善,实现工具间的无缝协作。
云计算和高性能计算集成:R将更好地利用云计算和高性能计算资源,处理大规模药理学数据和复杂模型。
2.2 R环境安装与配置#
2.2.1 R与RStudio的安装#
安装R#
R可以从CRAN(Comprehensive R Archive Network)官方网站下载安装:
访问CRAN官方网站:https://cran.r-project.org/
根据您的操作系统选择相应的版本:
- Windows用户:点击"Download R for Windows",然后选择"base",下载最新版本的安装程序
- macOS用户:点击"Download R for macOS",下载适合您macOS版本的安装包
- Linux用户:点击"Download R for Linux",根据您的Linux发行版选择相应的安装说明
运行下载的安装程序,按照向导完成安装过程。默认设置通常适合大多数用户。
安装RStudio#
RStudio是一个功能强大的R集成开发环境(IDE),提供了代码编辑器、调试工具、可视化界面等功能,大大提高了R的使用体验。
- 访问RStudio官方网站:https://www.rstudio.com/products/rstudio/download/
- 下载RStudio Desktop的免费版本(Open Source License)
- 选择适合您操作系统的安装包
- 运行下载的安装程序,按照向导完成安装过程
注意:安装RStudio前必须先安装R,因为RStudio是基于R运行的。
2.2.2 基本界面介绍#
RStudio界面通常分为四个主要区域:
源代码编辑器(左上):
- 用于编写和编辑R脚本
- 支持语法高亮、代码折叠、自动完成等功能
- 可以同时打开多个文件,以标签页形式显示
控制台(左下):
- 用于直接输入R命令并查看执行结果
- 显示命令历史和执行过程中的消息
环境/历史记录(右上):
- 环境标签页显示当前工作空间中的对象(变量、函数等)
- 历史记录标签页显示之前执行过的命令
- 还可能包含其他标签页,如连接、构建等
文件/图形/包/帮助(右下):
- 文件标签页:浏览和管理文件系统
- 图形标签页:显示生成的图形
- 包标签页:管理已安装的R包
- 帮助标签页:查看函数和包的文档
基本操作#
- 创建新脚本:File → New File → R Script,或使用快捷键Ctrl+Shift+N(Windows/Linux)或Cmd+Shift+N(macOS)
- 运行代码:选中代码后按Ctrl+Enter(Windows/Linux)或Cmd+Enter(macOS),或点击"Run"按钮
- 安装包:在控制台中输入
install.packages("包名")
,或通过Tools → Install Packages菜单 - 加载包:在脚本或控制台中输入
library(包名)
- 获取帮助:在控制台中输入
?函数名
或help(函数名)
,或使用Help菜单
2.2.3 包管理与更新#
R的强大功能很大程度上来自于其丰富的扩展包生态系统。正确管理和更新这些包对于保持分析环境的稳定和高效至关重要。
安装包#
有多种方法可以安装R包:
从CRAN安装(最常用):
1
2
| install.packages("ggplot2") # 安装单个包
install.packages(c("dplyr", "tidyr", "readr")) # 安装多个包
|
从Bioconductor安装(生物信息学相关包):
1
2
3
| if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install("GenomicRanges")
|
从GitHub安装(开发版本或未发布到CRAN的包):
1
2
3
4
| # 首先安装devtools包
install.packages("devtools")
# 然后从GitHub安装包
devtools::install_github("nlmixrdevelopment/nlmixr")
|
从本地文件安装:
1
| install.packages("path/to/package.tar.gz", repos = NULL, type = "source")
|
加载包#
安装包后,需要将其加载到当前R会话中才能使用:
1
2
3
4
5
| library(ggplot2) # 加载单个包
# 加载多个包的简便方法
packages <- c("dplyr", "tidyr", "readr")
invisible(lapply(packages, library, character.only = TRUE))
|
更新包#
定期更新包可以获取bug修复和新功能:
1
2
3
4
5
6
7
8
| # 更新所有包
update.packages()
# 更新特定包
install.packages("ggplot2") # 重新安装即可更新
# 检查哪些包需要更新
old.packages()
|
包版本管理#
在定量药理学研究中,包版本的一致性对于结果的可重复性至关重要。可以使用renv
包来管理项目特定的包版本:
1
2
3
4
5
6
7
8
9
10
11
| # 安装renv包
install.packages("renv")
# 初始化项目的包环境
renv::init()
# 保存当前包环境的快照
renv::snapshot()
# 恢复之前保存的包环境
renv::restore()
|
2.2.4 工作目录与项目管理#
良好的项目组织对于定量药理学研究的可重复性和协作至关重要。
工作目录#
工作目录是R默认查找文件和保存输出的位置。
1
2
3
4
5
6
| # 查看当前工作目录
getwd()
# 设置工作目录
setwd("/path/to/your/directory") # Unix/Mac
setwd("C:/path/to/your/directory") # Windows
|
注意:在RStudio项目中,最好不要使用setwd()
,而是依赖项目结构来管理文件路径。
RStudio项目#
RStudio项目提供了一种组织与特定分析相关的文件的方式:
创建新项目:File → New Project,然后选择创建新目录或使用现有目录
项目结构:建议采用以下基本结构:
data/
:原始数据和处理后的数据R/
:R脚本和函数output/
:分析结果、图表和报告doc/
:文档和说明
使用相对路径:在项目中使用相对路径引用文件,提高可移植性
1
2
3
4
5
| # 好的做法
data <- read.csv("data/pk_data.csv")
# 避免使用绝对路径
# data <- read.csv("C:/Users/name/project/data/pk_data.csv")
|
使用here
包:简化项目内文件路径的处理
1
2
3
4
5
| install.packages("here")
library(here)
# 无论当前工作目录在哪,都能正确引用项目内的文件
data <- read.csv(here("data", "pk_data.csv"))
|
版本控制集成:RStudio支持Git版本控制,可以在创建项目时选择"Create a git repository",或者通过Tools → Version Control → Project Setup配置
2.3 定量药理学相关R包介绍#
定量药理学分析涉及多个步骤,包括数据处理、模型构建、参数估计、模型评估和结果可视化。R生态系统提供了多种专门的包来支持这些任务。
2.3.1 非线性混合效应模型包#
nlmixr/nlmixr2#
nlmixr是一个用于拟合非线性混合效应模型的开源R包,可以看作是NONMEM的开源替代品。nlmixr2是其更新版本,提供了更多功能和性能改进。
主要特点:
- 支持多种估计方法,包括SAEM、FOCE等
- 可以拟合传统的房室PK模型和基于ODE的复杂模型
- 与tidyverse生态系统兼容
- 提供模型诊断和可视化工具
安装:
1
2
3
4
5
| # 从CRAN安装
install.packages("nlmixr2")
# 或从GitHub安装开发版本
devtools::install_github("nlmixrdevelopment/nlmixr2")
|
基本用法示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| library(nlmixr2)
# 定义模型
one.cmt <- function() {
ini({
tka <- 0.45 # log Ka
tcl <- 1 # log CL
tv <- 3.45 # log V
eta.ka ~ 0.6
eta.cl ~ 0.3
eta.v ~ 0.1
add.err <- 0.7
})
model({
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl)
v <- exp(tv + eta.v)
linCmt() ~ add(add.err)
})
}
# 拟合模型
fit <- nlmixr(one.cmt, data=pkdata, est="saem")
# 查看结果
summary(fit)
|
Pmetrics#
Pmetrics是一个基于R的非参数和参数化群体PK/PD分析软件包,由南加州大学LAPKB实验室开发。
主要特点:
- 提供非参数和参数化方法
- 支持贝叶斯后验分析
- 包含Monte Carlo模拟功能
- 适用于抗生素等特殊药物的PK/PD分析
安装:
1
2
3
4
| # 从LAPKB安装
install.packages("Pmetrics",
repos=c("https://repo.lapkb.com",
"https://cloud.r-project.org"))
|
基本用法示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
| library(Pmetrics)
# 准备数据
data <- PMreadMatrix("pkdata.csv")
# 定义模型
model <- PMbuild("model.txt", data)
# 运行分析
results <- PMrun(model)
# 查看结果
PMplot(results)
|
2.3.2 微分方程模拟包#
mrgsolve#
mrgsolve是一个用于模拟基于常微分方程(ODE)的药理学模型的R包,特别适合PK/PD模拟。
主要特点:
- 高效的ODE求解器
- 灵活的剂量方案设计
- 支持参数不确定性分析
- 与dplyr和ggplot2等包集成良好
安装:
1
| install.packages("mrgsolve")
|
基本用法示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| library(mrgsolve)
# 定义模型代码
code <- '
$PARAM CL = 1, VC = 20, KA = 1.2
$CMT GUT CENT
$ODE
dxdt_GUT = -KA * GUT;
dxdt_CENT = KA * GUT - (CL/VC) * CENT;
$TABLE
CP = CENT/VC;
$CAPTURE CP
'
# 编译模型
mod <- mcode("pk1", code)
# 设置剂量
e <- ev(amt=100, cmt=1) # 100mg口服给药
# 运行模拟
out <- mod %>% ev(e) %>% mrgsim(end=24, delta=0.1)
# 可视化结果
plot(out, CP ~ time)
|
RxODE#
RxODE是另一个用于ODE模型模拟的R包,与mrgsolve类似,但提供了一些不同的功能。
主要特点:
- 高效的ODE求解器
- 支持随机效应模拟
- 与nlmixr紧密集成
- 适合群体模拟
安装:
1
| install.packages("RxODE")
|
基本用法示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| library(RxODE)
# 定义模型
ode <- "
d/dt(depot) = -ka * depot;
d/dt(cent) = ka * depot - (cl/v) * cent;
cp = cent/v;
"
# 编译模型
mod <- RxODE(model = ode)
# 设置参数
theta <- c(ka = 1.2, cl = 1, v = 20)
# 设置初始条件和时间点
inits <- c(depot = 100, cent = 0)
times <- seq(0, 24, by = 0.1)
# 运行模拟
sim <- mod$solve(theta, inits, times)
# 可视化结果
plot(sim$time, sim$cp, type = "l",
xlab = "Time (h)", ylab = "Concentration")
|
2.3.3 数据处理与可视化包#
ggplot2#
ggplot2是一个基于图形语法的数据可视化包,在定量药理学中广泛用于创建高质量的图表。
主要特点:
- 基于图层的绘图系统
- 高度可定制的图形外观
- 支持多种图形类型
- 适合创建出版质量的图表
安装:
1
| install.packages("ggplot2")
|
基本用法示例:
1
2
3
4
5
6
7
8
9
10
| library(ggplot2)
# 创建浓度-时间曲线
ggplot(pkdata, aes(x = time, y = conc, color = factor(dose))) +
geom_point() +
geom_line() +
scale_x_continuous(name = "Time (h)") +
scale_y_continuous(name = "Concentration (ng/mL)") +
scale_color_discrete(name = "Dose (mg)") +
theme_bw()
|
dplyr和tidyverse#
dplyr是tidyverse生态系统的一部分,提供了一套用于数据操作的函数。在定量药理学中,它用于数据清洗、转换和汇总。
主要特点:
- 直观的数据操作语法
- 高效的数据过滤、排序和汇总
- 支持分组操作
- 与其他tidyverse包无缝集成
安装:
1
2
3
| install.packages("tidyverse") # 安装整个tidyverse
# 或者只安装dplyr
install.packages("dplyr")
|
基本用法示例:
1
2
3
4
5
6
7
8
9
10
| library(dplyr)
# 数据处理示例
pkdata_processed <- pkdata %>%
filter(time > 0) %>% # 过滤时间大于0的数据
mutate(log_conc = log(conc)) %>% # 创建对数浓度变量
group_by(subject, dose) %>% # 按受试者和剂量分组
summarize(auc = sum(conc * diff(c(0, time))), # 计算AUC
cmax = max(conc), # 计算Cmax
tmax = time[which.max(conc)]) # 计算Tmax
|
Xpose和xpose4#
Xpose和xpose4是用于NONMEM和nlmixr模型诊断的R包,提供了全面的图形工具。
主要特点:
- 自动生成标准诊断图
- 支持视觉预测检验(VPC)
- 与nlmixr和NONMEM集成
- 基于ggplot2的现代图形
安装:
1
2
3
4
5
| # 安装xpose4(基于lattice)
install.packages("xpose4")
# 安装xpose(基于ggplot2)
install.packages("xpose")
|
基本用法示例:
1
2
3
4
5
6
7
8
9
10
11
| library(xpose)
# 导入nlmixr拟合结果
xpdb <- xpose_data_nlmixr(fit)
# 创建诊断图
dv_vs_pred(xpdb)
dv_vs_ipred(xpdb)
res_vs_pred(xpdb)
res_vs_idv(xpdb)
vpc(xpdb)
|
2.3.4 试验设计包#
PopED#
PopED是一个用于群体PK/PD实验优化设计的R包,帮助研究者设计更高效的临床试验。
主要特点:
- 优化采样时间点
- 优化剂量水平
- 支持多种优化算法
- 适用于各种PK/PD模型
安装:
1
| install.packages("PopED")
|
基本用法示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| library(PopED)
# 定义模型
ff <- function(model_switch, xt, parameters, poped.db) {
with(as.list(parameters),{
y = xt
MS <- model_switch
# 一室模型
if(MS==1){
y = biopharm::one.comp.oral.sd.CL(xt, CL, V, KA)
}
return(list(y=y, poped.db=poped.db))
})
}
# 设置模型参数
sfg <- function(x, a, bpop, b, bocc) {
parameters = c(CL = bpop[1] * exp(b[1]),
V = bpop[2] * exp(b[2]),
KA = bpop[3] * exp(b[3]))
return(parameters)
}
# 创建PopED数据库
poped.db <- create.poped.database(
ff_fun = ff,
fg_fun = sfg,
bpop = c(CL = 1, V = 20, KA = 1.2),
notfixed_bpop = c(1, 1, 1),
d = c(CL = 0.09, V = 0.09, KA = 0.36),
sigma = 0.04,
groupsize = 20,
xt = c(0.5, 1, 2, 4, 8, 12, 24),
model_switch = 1
)
# 运行优化
output <- poped_optimize(poped.db)
# 查看结果
summary(output)
|
2.4 基本数据结构与操作#
在进行定量药理学分析之前,了解R的基本数据结构和操作是必要的。这些知识将帮助您有效地处理和分析药理学数据。
2.4.1 向量、矩阵、数据框#
向量是R中最基本的数据结构,包含相同类型的元素序列。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 创建数值向量
conc <- c(0.1, 0.5, 2.3, 4.7, 3.2, 1.8, 0.9)
# 创建字符向量
subject_id <- c("S001", "S002", "S003", "S004")
# 创建逻辑向量
above_threshold <- conc > 2.0
# 向量运算
conc * 2 # 所有元素乘以2
log(conc) # 对所有元素取对数
mean(conc) # 计算平均值
sd(conc) # 计算标准差
|
矩阵是二维数据结构,包含相同类型的元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # 创建矩阵
dose_matrix <- matrix(c(10, 20, 30, 10, 20, 30), nrow = 3, ncol = 2)
# 为行和列命名
rownames(dose_matrix) <- c("Subject1", "Subject2", "Subject3")
colnames(dose_matrix) <- c("Day1", "Day2")
# 矩阵索引
dose_matrix[1, 2] # 第1行第2列的元素
dose_matrix[, 1] # 第1列的所有元素
dose_matrix[2, ] # 第2行的所有元素
# 矩阵运算
t(dose_matrix) # 转置
dose_matrix * 2 # 所有元素乘以2
|
数据框#
数据框是最常用的数据结构,类似于表格,可以包含不同类型的列。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # 创建数据框
pk_data <- data.frame(
subject = c("S001", "S001", "S001", "S002", "S002", "S002"),
time = c(0, 1, 2, 0, 1, 2),
conc = c(0, 10.5, 5.2, 0, 8.7, 4.3)
)
# 访问数据框元素
pk_data$subject # 访问subject列
pk_data[, "time"] # 另一种访问列的方式
pk_data[1, ] # 第1行
pk_data[pk_data$time > 0, ] # 条件筛选
# 添加新列
pk_data$log_conc <- log(pk_data$conc + 0.1) # 添加对数浓度列
# 数据框汇总
summary(pk_data)
|
列表是R中最灵活的数据结构,可以包含不同类型和长度的元素。
1
2
3
4
5
6
7
8
9
10
11
| # 创建列表
pk_model <- list(
parameters = c(CL = 1.0, V = 20.0, KA = 1.2),
data = pk_data,
description = "One-compartment model with first-order absorption"
)
# 访问列表元素
pk_model$parameters # 访问parameters元素
pk_model[[1]] # 另一种访问元素的方式
pk_model$data$conc # 嵌套访问
|
2.4.2 数据导入与导出#
定量药理学分析通常从导入数据开始。R提供了多种方法来导入不同格式的数据。
CSV文件#
1
2
3
4
5
| # 导入CSV文件
pk_data <- read.csv("data/pk_data.csv", header = TRUE)
# 导出CSV文件
write.csv(pk_data, "output/processed_pk_data.csv", row.names = FALSE)
|
Excel文件#
使用readxl
包导入Excel文件:
1
2
3
4
5
6
7
8
9
10
11
| # 安装readxl包
install.packages("readxl")
# 导入Excel文件
library(readxl)
pk_data <- read_excel("data/pk_data.xlsx", sheet = "PK_Data")
# 导出Excel文件(使用writexl包)
install.packages("writexl")
library(writexl)
write_xlsx(pk_data, "output/processed_pk_data.xlsx")
|
NONMEM格式文件#
使用nonmem2rx
包导入NONMEM格式文件:
1
2
3
4
5
6
7
8
9
| # 安装nonmem2rx包
install.packages("nonmem2rx")
# 导入NONMEM数据文件
library(nonmem2rx)
nm_data <- read_nonmem("data/pk.csv")
# 导入NONMEM控制流文件
nm_model <- nonmem2rx("models/run001.mod")
|
数据库连接#
使用DBI
和相应的数据库驱动包连接数据库:
1
2
3
4
5
6
7
8
9
10
11
12
| # 安装必要的包
install.packages(c("DBI", "RSQLite"))
# 连接SQLite数据库
library(DBI)
con <- dbConnect(RSQLite::SQLite(), "data/pk_database.sqlite")
# 查询数据
pk_data <- dbGetQuery(con, "SELECT * FROM pk_measurements")
# 关闭连接
dbDisconnect(con)
|
2.4.3 基本数据处理函数#
R提供了丰富的函数用于数据处理和转换。以下是一些在定量药理学分析中常用的函数。
数据筛选和子集#
1
2
3
4
5
6
7
| # 使用基础R
pk_data_subset <- pk_data[pk_data$time > 0 & pk_data$conc > 0, ]
# 使用dplyr
library(dplyr)
pk_data_subset <- pk_data %>%
filter(time > 0, conc > 0)
|
数据排序#
1
2
3
4
5
6
| # 使用基础R
pk_data_sorted <- pk_data[order(pk_data$subject, pk_data$time), ]
# 使用dplyr
pk_data_sorted <- pk_data %>%
arrange(subject, time)
|
数据转换#
1
2
3
4
5
6
7
8
9
10
| # 使用基础R
pk_data$dose_per_kg <- pk_data$dose / pk_data$weight
pk_data$log_conc <- log(pk_data$conc + 0.1) # 添加0.1避免log(0)
# 使用dplyr
pk_data <- pk_data %>%
mutate(
dose_per_kg = dose / weight,
log_conc = log(conc + 0.1)
)
|
数据汇总#
1
2
3
4
5
6
7
8
9
10
11
12
| # 使用基础R
pk_summary <- aggregate(conc ~ subject + dose, data = pk_data,
FUN = function(x) c(max = max(x), auc = sum(x)))
# 使用dplyr
pk_summary <- pk_data %>%
group_by(subject, dose) %>%
summarize(
cmax = max(conc),
tmax = time[which.max(conc)],
auc = sum(conc * diff(c(0, time)))
)
|
数据重塑#
使用tidyr
包进行数据重塑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # 安装tidyr包
install.packages("tidyr")
# 宽格式转长格式
library(tidyr)
pd_data_long <- pd_data_wide %>%
pivot_longer(
cols = c(bp, hr, temp),
names_to = "parameter",
values_to = "value"
)
# 长格式转宽格式
pd_data_wide <- pd_data_long %>%
pivot_wider(
names_from = parameter,
values_from = value
)
|
缺失值处理#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # 检查缺失值
sum(is.na(pk_data$conc))
colSums(is.na(pk_data))
# 删除含有缺失值的行
pk_data_complete <- na.omit(pk_data)
# 使用dplyr删除特定列中含有缺失值的行
pk_data_complete <- pk_data %>%
filter(!is.na(conc))
# 替换缺失值
pk_data$conc[is.na(pk_data$conc)] <- 0 # 替换为0
pk_data$conc[is.na(pk_data$conc)] <- min(pk_data$conc, na.rm = TRUE) / 2 # 替换为最小值的一半
# 使用插值替换缺失值
install.packages("zoo")
library(zoo)
pk_data$conc <- na.approx(pk_data$conc, na.rm = FALSE) # 线性插值
|
2.5 R语言编程基础#
虽然许多定量药理学分析可以使用现有的R包完成,但了解R语言的基本编程概念将帮助您创建更灵活、更高效的分析流程。
2.5.1 控制结构#
条件语句#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # if-else语句
if (max(pk_data$conc) > 100) {
print("High concentration detected")
} else {
print("Concentration within normal range")
}
# ifelse函数(向量化操作)
pk_data$conc_category <- ifelse(pk_data$conc > 10, "High", "Low")
# 多条件判断
pk_data$dose_level <- case_when(
pk_data$dose < 10 ~ "Low",
pk_data$dose >= 10 & pk_data$dose < 50 ~ "Medium",
pk_data$dose >= 50 ~ "High"
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| # for循环
subjects <- unique(pk_data$subject)
for (subj in subjects) {
subj_data <- pk_data[pk_data$subject == subj, ]
cat("Subject", subj, "has", nrow(subj_data), "observations\n")
}
# while循环
i <- 1
while (i <= length(subjects)) {
cat("Processing subject", subjects[i], "\n")
i <- i + 1
}
# apply系列函数(替代循环的更高效方法)
# lapply:返回列表
subject_counts <- lapply(subjects, function(subj) {
sum(pk_data$subject == subj)
})
# sapply:简化结果
subject_counts <- sapply(subjects, function(subj) {
sum(pk_data$subject == subj)
})
# tapply:按因子分组应用函数
max_conc_by_subject <- tapply(pk_data$conc, pk_data$subject, max)
|
2.5.2 函数编写#
创建自定义函数可以提高代码的可读性和可重用性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| # 创建计算药代动力学参数的函数
calc_pk_params <- function(time, conc, dose = NULL) {
# 输入检查
if (length(time) != length(conc)) {
stop("Time and concentration vectors must have the same length")
}
# 排序数据(确保按时间顺序)
ord <- order(time)
time <- time[ord]
conc <- conc[ord]
# 计算参数
cmax <- max(conc)
tmax <- time[which.max(conc)]
# 使用线性梯形法计算AUC
auc <- sum(diff(time) * (conc[-1] + conc[-length(conc)]) / 2)
# 如果提供了剂量,计算清除率
cl <- ifelse(!is.null(dose), dose / auc, NA)
# 返回结果
return(list(
cmax = cmax,
tmax = tmax,
auc = auc,
cl = cl
))
}
# 使用函数
subj_data <- pk_data[pk_data$subject == "S001", ]
pk_params <- calc_pk_params(subj_data$time, subj_data$conc, subj_data$dose[1])
print(pk_params)
|
2.5.3 错误处理#
良好的错误处理可以使您的代码更加健壮。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| # try-catch结构
fit_model <- function(data) {
tryCatch(
{
# 尝试拟合模型
model <- nlmixr(one.cmt, data = data, est = "saem")
return(model)
},
error = function(e) {
# 处理错误
message("Error fitting model: ", e$message)
return(NULL)
},
warning = function(w) {
# 处理警告
message("Warning during model fitting: ", w$message)
# 继续执行
},
finally = {
# 无论是否发生错误,都会执行
message("Model fitting attempt completed")
}
)
}
# 使用函数
model <- fit_model(pk_data)
if (!is.null(model)) {
summary(model)
} else {
message("Model fitting failed, using alternative approach")
# 替代方法
}
|
本章介绍了R语言的基础知识和在定量药理学中的应用。我们首先了解了R语言的特点和优势,然后学习了如何安装和配置R环境。接着,我们探讨了定量药理学相关的R包,包括非线性混合效应模型包、微分方程模拟包、数据处理与可视化包以及试验设计包。最后,我们回顾了R的基本数据结构、数据导入导出方法、数据处理函数和编程基础。
掌握这些基础知识将为您在后续章节中学习更高级的定量药理学分析技术奠定基础。在下一章中,我们将深入探讨药理学数据的准备和探索性分析,学习如何处理和可视化药代动力学和药效学数据。
第三章:药代动力学建模#
3.1 药代动力学数据准备与探索#
在开始建模之前,正确准备和探索药代动力学数据是至关重要的。这一步可以帮助我们了解数据结构、识别潜在问题,并为模型选择提供初步依据。
3.1.1 数据结构与格式要求#
药代动力学数据通常包含以下关键变量:
- ID:受试者标识符
- TIME:采样时间点
- DV(Dependent Variable):观测值,通常是药物浓度
- AMT:给药剂量
- CMT:房室号(用于多房室模型)
- EVID:事件标识符(0表示观测,1表示给药)
- MDV(Missing Dependent Variable):缺失值标识符
- 协变量:如体重、年龄、性别、肝肾功能等
以下是一个典型的PK数据结构示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| # 创建示例PK数据
pk_data <- data.frame(
ID = rep(1:3, each = 8),
TIME = rep(c(0, 0.5, 1, 2, 4, 8, 12, 24), 3),
DV = c(0, 2.1, 4.5, 3.2, 2.0, 1.1, 0.6, 0.2,
0, 1.8, 3.9, 2.8, 1.7, 0.9, 0.5, 0.1,
0, 2.4, 5.1, 3.6, 2.3, 1.3, 0.7, 0.3),
AMT = c(100, 0, 0, 0, 0, 0, 0, 0,
100, 0, 0, 0, 0, 0, 0, 0,
100, 0, 0, 0, 0, 0, 0, 0),
CMT = 1,
EVID = c(1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0),
MDV = c(1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0),
WT = rep(c(70, 65, 80), each = 8),
AGE = rep(c(35, 42, 28), each = 8),
SEX = rep(c(1, 0, 1), each = 8)
)
# 查看数据结构
head(pk_data)
|
对于不同的建模软件,数据格式可能有特定要求:
- nlmixr/nlmixr2:接受标准的长格式数据,变量名可以自定义
- NONMEM:通常要求特定的变量名和格式
- Pmetrics:需要特定格式的输入文件
3.1.2 数据清洗与转换#
在建模前,通常需要对原始数据进行清洗和转换:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| library(dplyr)
library(tidyr)
# 检查并处理缺失值
pk_data_clean <- pk_data %>%
# 将浓度为NA的观测标记为MDV=1
mutate(MDV = ifelse(is.na(DV), 1, MDV))
# 检查并处理异常值
pk_data_clean <- pk_data_clean %>%
# 将浓度小于定量下限(LOQ)的值替换为LOQ/2
mutate(DV = ifelse(DV < 0.1 & DV > 0, 0.05, DV))
# 添加对数转换的浓度
pk_data_clean <- pk_data_clean %>%
mutate(LOGDV = ifelse(DV > 0, log(DV), NA))
# 标准化协变量
pk_data_clean <- pk_data_clean %>%
mutate(
WT_NORM = WT / 70, # 体重标准化为70kg
AGE_CENT = AGE - median(AGE) # 年龄中心化
)
# 为不同给药场合添加OCC变量(如果有多次给药)
pk_data_clean <- pk_data_clean %>%
group_by(ID) %>%
mutate(OCC = cumsum(EVID == 1)) %>%
ungroup()
|
3.1.3 探索性数据分析#
在建模前进行探索性数据分析,可以帮助我们了解数据特征和潜在的模型结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| library(ggplot2)
# 绘制浓度-时间曲线
ggplot(pk_data_clean %>% filter(EVID == 0),
aes(x = TIME, y = DV, color = factor(ID))) +
geom_point() +
geom_line() +
scale_y_log10() +
labs(title = "浓度-时间曲线",
x = "时间 (h)",
y = "浓度 (ng/mL)",
color = "受试者") +
theme_bw()
# 计算并可视化主要PK参数
pk_params <- pk_data_clean %>%
filter(EVID == 0) %>%
group_by(ID) %>%
summarize(
Cmax = max(DV),
Tmax = TIME[which.max(DV)],
AUClast = sum(diff(c(0, TIME)) * (DV[-1] + DV[-length(DV)]) / 2),
T_half = NA # 半衰期需要通过模型估计
)
# 查看PK参数
print(pk_params)
# 可视化PK参数与协变量的关系
ggplot(pk_params %>%
left_join(pk_data_clean %>%
select(ID, WT, AGE, SEX) %>%
distinct(), by = "ID"),
aes(x = WT, y = Cmax, color = factor(SEX))) +
geom_point() +
labs(title = "Cmax vs 体重",
x = "体重 (kg)",
y = "Cmax (ng/mL)",
color = "性别") +
theme_bw()
|
3.1.4 初步模型选择依据#
探索性分析可以帮助我们初步确定模型结构:
房室数量:
- 观察浓度-时间曲线的形状
- 单指数衰减通常表明一室模型可能适用
- 多相衰减可能需要多室模型
吸收过程:
- 观察达峰时间和上升曲线形状
- 快速达峰可能表明一级吸收或零级吸收
- 缓慢或延迟达峰可能需要考虑迟滞模型或传递房室
消除过程:
- 在半对数坐标下观察终末相是否为直线
- 非线性消除可能表明存在饱和过程
变异性来源:
3.2 非房室模型分析#
非房室模型分析(Non-Compartmental Analysis, NCA)是药代动力学研究中最基本的方法,不依赖于特定的房室模型假设,通过计算浓度-时间曲线下面积等参数来表征药物在体内的行为。
3.2.1 NCA的基本原理#
NCA基于以下假设:
- 所有消除过程都发生在采样房室(通常是中央房室)
- 所有吸收和分布过程都是瞬时完成的
- 药物遵循线性药代动力学
NCA的主要优势在于其简单性和稳健性,不需要复杂的模型假设,适用于初步PK评估和生物等效性研究。
3.2.2 使用R进行NCA分析#
R中有多个包可用于NCA分析,其中PKNCA
是一个功能全面的选择:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| # 安装PKNCA包
install.packages("PKNCA")
# 加载包
library(PKNCA)
library(dplyr)
# 准备数据
nca_data <- pk_data_clean %>%
filter(EVID == 0) %>%
select(ID, TIME, DV, AMT)
# 设置NCA参数
conc_obj <- PKNCAconc(nca_data,
conc ~ TIME | ID,
exclude = DV < 0)
dose_data <- pk_data_clean %>%
filter(EVID == 1) %>%
select(ID, TIME, AMT)
dose_obj <- PKNCAdose(dose_data,
dose ~ TIME | ID)
# 定义要计算的NCA参数
nca_parameters <- data.frame(
parameter = c("auclast", "cmax", "tmax", "half.life", "cl.obs"),
method = c("linear", "max", "max", "calc", "calc")
)
# 执行NCA分析
nca_obj <- PKNCAdata(conc_obj, dose_obj)
nca_results <- pk.nca(nca_obj, nca_parameters)
# 查看结果
summary(nca_results)
|
3.2.3 主要NCA参数计算与解释#
以下是主要NCA参数的计算方法和解释:
Cmax(最大浓度):
- 计算:观测到的最高浓度值
- 解释:反映药物的最大暴露水平
Tmax(达峰时间):
AUC(曲线下面积):
- 计算方法:
- 线性梯形法:AUC = Σ[(ti+1 - ti) × (Ci + Ci+1) / 2]
- 对数梯形法:适用于采样间隔较长的终末相
- 类型:
- AUClast:从0到最后一个采样点的AUC
- AUCinf:从0到无穷大的AUC,AUCinf = AUClast + Clast/λz
- 解释:反映药物的总暴露量
λz(终末消除速率常数):
- 计算:终末相浓度对数值对时间的线性回归斜率
- 解释:反映药物从体内消除的速率
t1/2(半衰期):
- 计算:t1/2 = ln(2) / λz
- 解释:药物浓度降低到一半所需的时间
CL(清除率):
- 计算:CL = Dose / AUCinf
- 解释:单位时间内从血液中清除药物的血液体积
Vd(分布容积):
- 计算:Vd = CL / λz
- 解释:药物在体内的表观分布空间
MRT(平均滞留时间):
- 计算:MRT = AUMC / AUC,其中AUMC是浓度×时间对时间的曲线下面积
- 解释:药物分子在体内平均停留的时间
3.2.4 NCA结果可视化#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| # 提取NCA结果
nca_summary <- as.data.frame(nca_results$result)
# 合并协变量数据
nca_with_cov <- nca_summary %>%
filter(parameter %in% c("auclast", "cmax", "tmax", "half.life")) %>%
select(ID = subject, parameter, value) %>%
pivot_wider(names_from = parameter, values_from = value) %>%
left_join(pk_data_clean %>%
select(ID, WT, AGE, SEX) %>%
distinct(), by = "ID")
# 可视化NCA参数
# AUC vs 体重
ggplot(nca_with_cov, aes(x = WT, y = auclast, color = factor(SEX))) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
labs(title = "AUC vs 体重",
x = "体重 (kg)",
y = "AUC (h*ng/mL)",
color = "性别") +
theme_bw()
# Cmax vs 体重
ggplot(nca_with_cov, aes(x = WT, y = cmax, color = factor(SEX))) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
labs(title = "Cmax vs 体重",
x = "体重 (kg)",
y = "Cmax (ng/mL)",
color = "性别") +
theme_bw()
# 半衰期分布
ggplot(nca_with_cov, aes(x = half.life)) +
geom_histogram(bins = 10, fill = "skyblue", color = "black") +
labs(title = "半衰期分布",
x = "半衰期 (h)",
y = "频数") +
theme_bw()
|
3.2.5 NCA在生物等效性研究中的应用#
生物等效性(BE)研究是NCA的重要应用领域,用于比较两种制剂的药代动力学特性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| # 假设我们有两种制剂(测试制剂T和参比制剂R)的NCA结果
be_data <- data.frame(
subject = rep(1:12, each = 2),
formulation = rep(c("T", "R"), 12),
sequence = rep(rep(c("TR", "RT"), each = 2), 6),
period = rep(c(1, 2, 2, 1), 6),
AUC = c(rnorm(12, mean = 100, sd = 20), rnorm(12, mean = 105, sd = 20)),
Cmax = c(rnorm(12, mean = 15, sd = 3), rnorm(12, mean = 16, sd = 3))
)
# 计算几何平均比和90%置信区间
library(bear)
# 对数转换
be_data$logAUC <- log(be_data$AUC)
be_data$logCmax <- log(be_data$Cmax)
# 使用混合效应模型进行BE分析
library(lme4)
# AUC的BE分析
auc_model <- lmer(logAUC ~ formulation + sequence + period + (1|subject),
data = be_data)
auc_summary <- summary(auc_model)
# 提取固定效应
auc_fixed <- fixef(auc_model)
auc_T_R_ratio <- exp(auc_fixed["formulationT"]) # T相对于R的比值
# 计算90%置信区间
auc_ci <- confint(auc_model, parm = "formulationT", level = 0.9)
auc_lower_ci <- exp(auc_ci[1])
auc_upper_ci <- exp(auc_ci[2])
# Cmax的BE分析
cmax_model <- lmer(logCmax ~ formulation + sequence + period + (1|subject),
data = be_data)
cmax_summary <- summary(cmax_model)
# 提取固定效应
cmax_fixed <- fixef(cmax_model)
cmax_T_R_ratio <- exp(cmax_fixed["formulationT"]) # T相对于R的比值
# 计算90%置信区间
cmax_ci <- confint(cmax_model, parm = "formulationT", level = 0.9)
cmax_lower_ci <- exp(cmax_ci[1])
cmax_upper_ci <- exp(cmax_ci[2])
# 汇总BE结果
be_results <- data.frame(
Parameter = c("AUC", "Cmax"),
Ratio = c(auc_T_R_ratio, cmax_T_R_ratio) * 100,
Lower_90CI = c(auc_lower_ci, cmax_lower_ci) * 100,
Upper_90CI = c(auc_upper_ci, cmax_upper_ci) * 100,
BE_Conclusion = c(
ifelse(auc_lower_ci >= 0.8 & auc_upper_ci <= 1.25, "BE", "Not BE"),
ifelse(cmax_lower_ci >= 0.8 & cmax_upper_ci <= 1.25, "BE", "Not BE")
)
)
# 打印BE结果
print(be_results)
|
3.3 房室模型构建#
房室模型是药代动力学研究中最常用的模型类型,它将人体视为由一个或多个相互连接的房室组成的系统,用于描述药物在体内的吸收、分布和消除过程。
3.3.1 常见房室模型介绍#
一室模型#
一室模型是最简单的房室模型,将全身视为一个均质的房室。
静脉给药一室模型:
- 浓度-时间方程:C(t) = (Dose/V) × e^(-CL/V × t)
- 参数:清除率(CL)和分布容积(V)
口服给药一室模型:
- 浓度-时间方程:C(t) = (F × Dose × Ka / (V × (Ka - CL/V))) × (e^(-CL/V × t) - e^(-Ka × t))
- 参数:清除率(CL)、分布容积(V)、吸收速率常数(Ka)和生物利用度(F)
二室模型#
二室模型将人体分为中央室(血液和血流丰富组织)和外周室(血流较少的组织)。
静脉给药二室模型:
- 浓度-时间方程(中央室):C(t) = A × e^(-α × t) + B × e^(-β × t)
- 参数:中央室分布容积(V1)、外周室分布容积(V2)、中央室清除率(CL)和房室间清除率(Q)
口服给药二室模型:
- 在一级吸收的基础上增加了分布相
- 参数:与静脉给药二室模型相同,外加吸收速率常数(Ka)和生物利用度(F)
三室模型#
三室模型在二室模型基础上增加了一个深层外周室,用于描述与中央室交换较慢的组织。
3.3.2 使用nlmixr2构建房室模型#
nlmixr2是R中用于非线性混合效应模型的强大工具,特别适合药代动力学建模。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| # 安装并加载nlmixr2
install.packages("nlmixr2")
library(nlmixr2)
# 准备数据
# 确保数据包含ID, TIME, DV, AMT, CMT, EVID, MDV等必要列
# 定义一室模型(口服给药)
one_cmt_model <- function() {
ini({
# 固定效应参数(群体典型值)
tka <- log(1.0) # log(Ka)
tcl <- log(5.0) # log(CL)
tv <- log(80.0) # log(V)
# 随机效应参数(个体间变异)
eta.ka ~ 0.4
eta.cl ~ 0.3
eta.v ~ 0.2
# 残差误差模型
add.err <- 0.1 # 加性误差
prop.err <- 0.2 # 比例误差
})
model({
# 参数转换(从对数尺度)
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl)
v <- exp(tv + eta.v)
# 定义微分方程
d/dt(depot) = -ka * depot
d/dt(central) = ka * depot - cl/v * central
# 或使用内置的线性房室模型函数
# linCmt() ~ add(add.err) + prop(prop.err)
# 连接模型(预测值与观测值的关系)
cp = central / v
cp ~ add(add.err) + prop(prop.err)
})
}
# 拟合模型
fit_one_cmt <- nlmixr(one_cmt_model, data = pk_data_clean, est = "saem")
# 查看拟合结果
summary(fit_one_cmt)
|
3.3.3 定义二室模型#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| # 定义二室模型(口服给药)
two_cmt_model <- function() {
ini({
# 固定效应参数
tka <- log(1.0) # log(Ka)
tcl <- log(5.0) # log(CL)
tv1 <- log(50.0) # log(V1)
tq <- log(10.0) # log(Q)
tv2 <- log(100.0) # log(V2)
# 随机效应参数
eta.ka ~ 0.4
eta.cl ~ 0.3
eta.v1 ~ 0.2
eta.q ~ 0.3
eta.v2 ~ 0.3
# 残差误差模型
add.err <- 0.1
prop.err <- 0.2
})
model({
# 参数转换
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl)
v1 <- exp(tv1 + eta.v1)
q <- exp(tq + eta.q)
v2 <- exp(tv2 + eta.v2)
# 定义微分方程
d/dt(depot) = -ka * depot
d/dt(central) = ka * depot - cl/v1 * central - q/v1 * central + q/v2 * peripheral
d/dt(peripheral) = q/v1 * central - q/v2 * peripheral
# 或使用内置的线性房室模型函数
# linCmt() ~ add(add.err) + prop(prop.err)
# 连接模型
cp = central / v1
cp ~ add(add.err) + prop(prop.err)
})
}
# 拟合模型
fit_two_cmt <- nlmixr(two_cmt_model, data = pk_data_clean, est = "saem")
# 查看拟合结果
summary(fit_two_cmt)
|
3.3.4 特殊吸收模型#
除了标准的一级吸收模型外,还有多种特殊吸收模型可以描述更复杂的吸收过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
| # 定义具有迟滞吸收的一室模型
delay_abs_model <- function() {
ini({
# 固定效应参数
tka <- log(1.0) # log(Ka)
tcl <- log(5.0) # log(CL)
tv <- log(80.0) # log(V)
tktr <- log(2.0) # log(Ktr),传递速率常数
# 随机效应参数
eta.ka ~ 0.4
eta.cl ~ 0.3
eta.v ~ 0.2
eta.ktr ~ 0.5
# 残差误差模型
add.err <- 0.1
prop.err <- 0.2
})
model({
# 参数转换
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl)
v <- exp(tv + eta.v)
ktr <- exp(tktr + eta.ktr)
# 定义微分方程(传递房室模型)
d/dt(depot) = -ktr * depot
d/dt(transit) = ktr * depot - ka * transit
d/dt(central) = ka * transit - cl/v * central
# 连接模型
cp = central / v
cp ~ add(add.err) + prop(prop.err)
})
}
# 定义具有零级吸收的一室模型
zero_order_abs_model <- function() {
ini({
# 固定效应参数
tdur <- log(2.0) # log(吸收持续时间)
tcl <- log(5.0) # log(CL)
tv <- log(80.0) # log(V)
# 随机效应参数
eta.dur ~ 0.4
eta.cl ~ 0.3
eta.v ~ 0.2
# 残差误差模型
add.err <- 0.1
prop.err <- 0.2
})
model({
# 参数转换
dur <- exp(tdur + eta.dur)
cl <- exp(tcl + eta.cl)
v <- exp(tv + eta.v)
# 定义微分方程(零级吸收)
f <- 1 # 生物利用度
rate <- f * amt / dur
d/dt(central) = rate - cl/v * central
# 连接模型
cp = central / v
cp ~ add(add.err) + prop(prop.err)
})
}
|
3.3.5 非线性消除模型#
当药物消除涉及饱和过程时,可以使用Michaelis-Menten动力学描述:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| # 定义具有Michaelis-Menten消除的一室模型
mm_elim_model <- function() {
ini({
# 固定效应参数
tka <- log(1.0) # log(Ka)
tvmax <- log(10.0) # log(Vmax)
tkm <- log(5.0) # log(Km)
tv <- log(80.0) # log(V)
# 随机效应参数
eta.ka ~ 0.4
eta.vmax ~ 0.3
eta.km ~ 0.4
eta.v ~ 0.2
# 残差误差模型
add.err <- 0.1
prop.err <- 0.2
})
model({
# 参数转换
ka <- exp(tka + eta.ka)
vmax <- exp(tvmax + eta.vmax)
km <- exp(tkm + eta.km)
v <- exp(tv + eta.v)
# 定义微分方程(Michaelis-Menten消除)
d/dt(depot) = -ka * depot
d/dt(central) = ka * depot - vmax * central/(km + central)
# 连接模型
cp = central / v
cp ~ add(add.err) + prop(prop.err)
})
}
|
3.4 参数估计与模型评估#
模型构建后,需要进行参数估计和模型评估,以确定模型的适合度和预测能力。
3.4.1 参数估计方法#
nlmixr2支持多种参数估计方法:
SAEM(随机近似期望最大化):
FOCE(一阶条件估计):
- 传统的参数估计方法
- 与NONMEM的FOCE方法兼容
FOCEi(带交互的FOCE):
- 考虑了随机效应和残差误差之间的交互
- 通常比FOCE更准确
1
2
3
4
5
6
7
8
| # 使用SAEM方法拟合模型
fit_saem <- nlmixr(one_cmt_model, data = pk_data_clean, est = "saem")
# 使用FOCE方法拟合模型
fit_foce <- nlmixr(one_cmt_model, data = pk_data_clean, est = "foce")
# 使用FOCEi方法拟合模型
fit_focei <- nlmixr(one_cmt_model, data = pk_data_clean, est = "focei")
|
3.4.2 模型诊断图#
模型诊断图是评估模型适合度的重要工具:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| library(xpose.nlmixr2)
library(ggplot2)
# 创建xpose数据库对象
xpdb <- xpose_data_nlmixr(fit_saem)
# 观测值vs群体预测值
dv_vs_pred(xpdb) +
theme_bw() +
labs(title = "观测值 vs 群体预测值")
# 观测值vs个体预测值
dv_vs_ipred(xpdb) +
theme_bw() +
labs(title = "观测值 vs 个体预测值")
# 条件加权残差vs时间
res_vs_idv(xpdb) +
theme_bw() +
labs(title = "条件加权残差 vs 时间")
# 条件加权残差vs群体预测值
res_vs_pred(xpdb) +
theme_bw() +
labs(title = "条件加权残差 vs 群体预测值")
# 个体拟合图
ind_plots(xpdb, n_individuals = 9) +
theme_bw() +
labs(title = "个体拟合图")
|
3.4.3 视觉预测检验(VPC)#
视觉预测检验是评估模型预测能力的重要工具:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # 执行VPC
vpc_nlmixr2 <- vpc(fit_saem, n = 500, stratify = NULL, seed = 1234)
# 绘制VPC图
plot(vpc_nlmixr2) +
theme_bw() +
labs(title = "视觉预测检验 (VPC)",
x = "时间 (h)",
y = "浓度 (ng/mL)")
# 执行预测校正的VPC (pcVPC)
vpc_pc_nlmixr2 <- vpc(fit_saem, n = 500, prediction_correction = TRUE,
stratify = NULL, seed = 1234)
# 绘制pcVPC图
plot(vpc_pc_nlmixr2) +
theme_bw() +
labs(title = "预测校正的视觉预测检验 (pcVPC)",
x = "时间 (h)",
y = "浓度 (ng/mL)")
|
3.4.4 模型选择标准#
在比较不同模型时,可以使用以下标准:
目标函数值(OFV):
- 通常使用-2倍对数似然值
- 嵌套模型间的OFV差异遵循卡方分布
赤池信息准则(AIC):
- AIC = OFV + 2 × p,其中p是参数数量
- 较小的AIC表示更好的模型
贝叶斯信息准则(BIC):
- BIC = OFV + log(n) × p,其中n是观测数,p是参数数量
- 较小的BIC表示更好的模型
条件加权残差(CWRES):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # 比较一室模型和二室模型
model_comparison <- data.frame(
Model = c("One-compartment", "Two-compartment"),
OFV = c(fit_one_cmt$objf, fit_two_cmt$objf),
AIC = c(fit_one_cmt$AIC, fit_two_cmt$AIC),
BIC = c(fit_one_cmt$BIC, fit_two_cmt$BIC),
Parameters = c(length(fit_one_cmt$theta), length(fit_two_cmt$theta))
)
# 计算模型间的OFV差异和p值
delta_OFV <- abs(fit_one_cmt$objf - fit_two_cmt$objf)
delta_params <- abs(length(fit_one_cmt$theta) - length(fit_two_cmt$theta))
p_value <- 1 - pchisq(delta_OFV, df = delta_params)
# 添加到比较表
model_comparison$delta_OFV <- c(NA, delta_OFV)
model_comparison$p_value <- c(NA, p_value)
# 打印比较结果
print(model_comparison)
|
3.4.5 参数精度评估#
评估参数估计的精度对于确定模型的可靠性至关重要:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 查看参数估计的相对标准误差(RSE)
summary(fit_saem)
# 使用引导法评估参数精度
library(bootpop)
# 执行引导
boot_results <- bootpop(fit_saem, nboot = 100, seed = 1234)
# 查看引导结果
summary(boot_results)
# 可视化引导结果
plot(boot_results)
|
3.5 协变量模型构建#
协变量模型可以解释部分个体间变异,提高模型的预测能力,并支持个体化给药。
3.5.1 协变量筛选策略#
常用的协变量筛选策略包括:
全模型法:
- 首先构建包含所有潜在协变量的模型
- 然后逐步删除不显著的协变量
逐步前向纳入/后向剔除法:
- 从基础模型开始,逐个添加协变量
- 保留显著改善模型的协变量
- 最后进行后向剔除,删除不显著的协变量
基于生理学的先验选择:
- 基于已知的生理学关系选择协变量
- 例如,体重对清除率和分布容积的影响
3.5.2 常见协变量关系#
常见的协变量关系包括:
线性关系:
1
| P = θ1 × (1 + θ2 × (COV - COVref))
|
幂函数关系:
1
| P = θ1 × (COV/COVref)^θ2
|
指数关系:
1
| P = θ1 × exp(θ2 × (COV - COVref))
|
分类协变量:
1
| P = θ1 × (1 + θ2 × CAT)
|
其中CAT为0或1
3.5.3 使用nlmixr2构建协变量模型#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| # 定义包含体重作为协变量的一室模型
cov_model <- function() {
ini({
# 固定效应参数
tka <- log(1.0) # log(Ka)
tcl <- log(5.0) # log(CL)
tv <- log(80.0) # log(V)
wt_cl <- 0.75 # 体重对CL的影响指数
wt_v <- 1.0 # 体重对V的影响指数
# 随机效应参数
eta.ka ~ 0.4
eta.cl ~ 0.3
eta.v ~ 0.2
# 残差误差模型
add.err <- 0.1
prop.err <- 0.2
})
model({
# 协变量效应
wt70 <- WT/70 # 标准化体重
# 参数转换
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl) * wt70^wt_cl # 体重对CL的影响
v <- exp(tv + eta.v) * wt70^wt_v # 体重对V的影响
# 定义微分方程
d/dt(depot) = -ka * depot
d/dt(central) = ka * depot - cl/v * central
# 连接模型
cp = central / v
cp ~ add(add.err) + prop(prop.err)
})
}
# 拟合协变量模型
fit_cov <- nlmixr(cov_model, data = pk_data_clean, est = "saem")
# 查看拟合结果
summary(fit_cov)
|
3.5.4 协变量模型评估#
评估协变量模型的方法包括:
统计学显著性:
- OFV减少≥3.84表示在p<0.05水平上显著(单个参数)
- 对于多个协变量,可以使用更严格的标准(如OFV减少≥10.83,p<0.001)
随机效应减少:
- 评估协变量纳入前后随机效应方差的减少程度
- 通常用方差减少百分比表示
诊断图:
- 随机效应vs协变量(应该无明显趋势)
- 条件加权残差vs协变量(应该无明显趋势)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| # 比较基础模型和协变量模型
cov_comparison <- data.frame(
Model = c("Base Model", "Covariate Model"),
OFV = c(fit_one_cmt$objf, fit_cov$objf),
AIC = c(fit_one_cmt$AIC, fit_cov$AIC),
BIC = c(fit_one_cmt$BIC, fit_cov$BIC),
CL_BSV = c(fit_one_cmt$omega[2,2], fit_cov$omega[2,2]),
V_BSV = c(fit_one_cmt$omega[3,3], fit_cov$omega[3,3])
)
# 计算BSV减少百分比
cov_comparison$CL_BSV_reduction <- c(NA, (1 - fit_cov$omega[2,2]/fit_one_cmt$omega[2,2]) * 100)
cov_comparison$V_BSV_reduction <- c(NA, (1 - fit_cov$omega[3,3]/fit_one_cmt$omega[3,3]) * 100)
# 计算OFV差异和p值
delta_OFV <- abs(fit_one_cmt$objf - fit_cov$objf)
delta_params <- abs(length(fit_one_cmt$theta) - length(fit_cov$theta))
p_value <- 1 - pchisq(delta_OFV, df = delta_params)
# 添加到比较表
cov_comparison$delta_OFV <- c(NA, delta_OFV)
cov_comparison$p_value <- c(NA, p_value)
# 打印比较结果
print(cov_comparison)
# 创建随机效应vs协变量图
library(ggplot2)
# 提取个体参数估计值
ind_params <- fit_one_cmt$eta
# 合并协变量数据
eta_cov <- data.frame(
ID = unique(pk_data_clean$ID),
eta.cl = ind_params[,2],
eta.v = ind_params[,3]
) %>%
left_join(pk_data_clean %>%
select(ID, WT) %>%
distinct(), by = "ID")
# 绘制eta.cl vs WT
ggplot(eta_cov, aes(x = WT, y = eta.cl)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
geom_hline(yintercept = 0, linetype = "dashed") +
labs(title = "η(CL) vs 体重",
x = "体重 (kg)",
y = "η(CL)") +
theme_bw()
# 绘制eta.v vs WT
ggplot(eta_cov, aes(x = WT, y = eta.v)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
geom_hline(yintercept = 0, linetype = "dashed") +
labs(title = "η(V) vs 体重",
x = "体重 (kg)",
y = "η(V)") +
theme_bw()
|
3.6 模型应用#
构建并验证模型后,可以将其应用于各种药代动力学问题。
3.6.1 剂量模拟#
使用模型进行剂量模拟,评估不同剂量方案的药物暴露:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| library(ggplot2)
# 使用最终模型进行模拟
final_model <- fit_cov # 假设协变量模型是最终模型
# 创建不同剂量的模拟数据
sim_doses <- c(50, 100, 200)
sim_times <- seq(0, 48, by = 0.1)
sim_subjects <- 100
# 创建模拟数据框
sim_data <- data.frame()
for (dose in sim_doses) {
for (i in 1:sim_subjects) {
# 随机生成体重
wt <- rnorm(1, mean = 70, sd = 10)
# 创建单个受试者的数据
subj_data <- data.frame(
ID = paste0(i, "_", dose),
TIME = c(0, sim_times),
DV = NA,
AMT = c(dose, rep(0, length(sim_times))),
CMT = 1,
EVID = c(1, rep(0, length(sim_times))),
MDV = c(1, rep(1, length(sim_times))),
WT = wt
)
sim_data <- rbind(sim_data, subj_data)
}
}
# 使用模型进行模拟
sim_res <- predict(final_model, sim_data)
# 提取预测结果
sim_pred <- cbind(sim_data, PRED = sim_res$PRED)
sim_pred$DOSE <- as.factor(gsub(".*_", "", sim_pred$ID))
# 计算每个剂量组的分位数
sim_summary <- sim_pred %>%
filter(EVID == 0) %>%
group_by(DOSE, TIME) %>%
summarize(
median = median(PRED),
lower = quantile(PRED, 0.05),
upper = quantile(PRED, 0.95)
)
# 绘制模拟结果
ggplot(sim_summary, aes(x = TIME, y = median, color = DOSE, fill = DOSE)) +
geom_line() +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2, color = NA) +
scale_y_log10() +
labs(title = "不同剂量的浓度-时间曲线模拟",
x = "时间 (h)",
y = "预测浓度 (ng/mL)",
color = "剂量 (mg)",
fill = "剂量 (mg)") +
theme_bw()
|
3.6.2 特殊人群剂量调整#
使用模型评估特殊人群(如肾功能不全患者)的剂量调整需求:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
| # 假设我们有一个包含肌酐清除率(CRCL)作为协变量的模型
renal_model <- function() {
ini({
# 固定效应参数
tka <- log(1.0) # log(Ka)
tcl <- log(5.0) # log(CL)
tv <- log(80.0) # log(V)
crcl_cl <- 0.75 # CRCL对CL的影响指数
# 随机效应参数
eta.ka ~ 0.4
eta.cl ~ 0.3
eta.v ~ 0.2
# 残差误差模型
add.err <- 0.1
prop.err <- 0.2
})
model({
# 协变量效应
crcl90 <- CRCL/90 # 标准化肌酐清除率
# 参数转换
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl) * crcl90^crcl_cl # CRCL对CL的影响
v <- exp(tv + eta.v)
# 定义微分方程
d/dt(depot) = -ka * depot
d/dt(central) = ka * depot - cl/v * central
# 连接模型
cp = central / v
cp ~ add(add.err) + prop(prop.err)
})
}
# 假设我们已经拟合了模型
# fit_renal <- nlmixr(renal_model, data = pk_data_with_crcl, est = "saem")
# 创建不同肾功能水平的模拟数据
renal_groups <- list(
"正常" = 100,
"轻度不全" = 60,
"中度不全" = 30,
"重度不全" = 15
)
dose <- 100 # 标准剂量
sim_times <- seq(0, 48, by = 0.1)
sim_subjects <- 50
# 创建模拟数据框
renal_sim_data <- data.frame()
for (group_name in names(renal_groups)) {
crcl <- renal_groups[[group_name]]
for (i in 1:sim_subjects) {
# 添加一些变异性
crcl_i <- rnorm(1, mean = crcl, sd = crcl * 0.1)
if (crcl_i < 0) crcl_i <- 1 # 避免负值
# 创建单个受试者的数据
subj_data <- data.frame(
ID = paste0(group_name, "_", i),
TIME = c(0, sim_times),
DV = NA,
AMT = c(dose, rep(0, length(sim_times))),
CMT = 1,
EVID = c(1, rep(0, length(sim_times))),
MDV = c(1, rep(1, length(sim_times))),
CRCL = crcl_i,
GROUP = group_name
)
renal_sim_data <- rbind(renal_sim_data, subj_data)
}
}
# 使用模型进行模拟(这里使用假设的模型参数)
# renal_sim_res <- predict(fit_renal, renal_sim_data)
# 假设我们已经有了模拟结果
# 创建一个模拟的预测结果
set.seed(123)
renal_sim_data$PRED <- NA
for (group_name in names(renal_groups)) {
crcl <- renal_groups[[group_name]]
scale_factor <- (crcl/90)^0.75 # 假设的CRCL对CL的影响
# 基础浓度曲线(一室模型,口服给药)
base_curve <- function(t) {
ka <- 1.0
cl <- 5.0 * scale_factor
v <- 80.0
dose <- 100
f <- 1.0
if (t == 0) return(0)
return((f * dose * ka / (v * (ka - cl/v))) *
(exp(-cl/v * t) - exp(-ka * t)))
}
# 为每个受试者生成预测值
for (i in 1:sim_subjects) {
id <- paste0(group_name, "_", i)
idx <- renal_sim_data$ID == id & renal_sim_data$EVID == 0
t <- renal_sim_data$TIME[idx]
# 添加一些随机变异
pred <- sapply(t, base_curve) *
exp(rnorm(length(t), mean = 0, sd = 0.2))
renal_sim_data$PRED[idx] <- pred
}
}
# 计算每个肾功能组的分位数
renal_sim_summary <- renal_sim_data %>%
filter(EVID == 0) %>%
group_by(GROUP, TIME) %>%
summarize(
median = median(PRED),
lower = quantile(PRED, 0.05),
upper = quantile(PRED, 0.95)
)
# 绘制模拟结果
ggplot(renal_sim_summary, aes(x = TIME, y = median, color = GROUP, fill = GROUP)) +
geom_line() +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2, color = NA) +
scale_y_log10() +
labs(title = "不同肾功能水平的浓度-时间曲线模拟",
x = "时间 (h)",
y = "预测浓度 (ng/mL)",
color = "肾功能",
fill = "肾功能") +
theme_bw()
# 计算剂量调整建议
target_auc <- 100 # 假设的目标AUC
renal_dose_adj <- data.frame(
GROUP = names(renal_groups),
CRCL = unlist(renal_groups),
REL_CL = (unlist(renal_groups)/90)^0.75, # 相对清除率
DOSE_ADJ = 100 * (unlist(renal_groups)/90)^0.75 # 剂量调整
)
# 打印剂量调整建议
print(renal_dose_adj)
|
3.6.3 治疗药物监测(TDM)#
使用模型支持治疗药物监测,基于测量的药物浓度调整个体给药方案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| # 假设我们有一个患者的TDM数据
tdm_data <- data.frame(
ID = 1,
TIME = c(0, 2, 6),
DV = c(0, 8.5, 4.2),
AMT = c(100, 0, 0),
CMT = 1,
EVID = c(1, 0, 0),
MDV = c(1, 0, 0),
WT = 65
)
# 使用最终模型进行贝叶斯后验估计
bayes_est <- nlmixr2est::nlmixr2(final_model, tdm_data, est = "posthoc")
# 查看个体参数估计
ind_params <- bayes_est$posthoc
# 使用个体参数进行预测和剂量调整
# 创建预测数据
pred_times <- seq(0, 24, by = 0.1)
pred_data <- data.frame(
ID = 1,
TIME = c(0, pred_times),
DV = NA,
AMT = c(100, rep(0, length(pred_times))),
CMT = 1,
EVID = c(1, rep(0, length(pred_times))),
MDV = c(1, rep(1, length(pred_times))),
WT = 65
)
# 使用个体参数进行预测
pred_res <- predict(bayes_est, pred_data)
# 提取预测结果
pred_data$IPRED <- pred_res$IPRED
# 绘制TDM数据和预测曲线
ggplot() +
geom_point(data = tdm_data %>% filter(EVID == 0),
aes(x = TIME, y = DV), size = 3) +
geom_line(data = pred_data %>% filter(EVID == 0),
aes(x = TIME, y = IPRED)) +
labs(title = "治疗药物监测与个体预测",
x = "时间 (h)",
y = "浓度 (ng/mL)") +
theme_bw()
# 计算剂量调整建议
# 假设目标AUC为100
target_auc <- 100
current_auc <- sum(diff(c(0, pred_times)) *
(pred_data$IPRED[-1] + pred_data$IPRED[-length(pred_data$IPRED)]) / 2)
dose_adjustment <- target_auc / current_auc * 100
# 打印剂量调整建议
cat("当前剂量: 100 mg\n")
cat("估计AUC:", round(current_auc, 2), "h*ng/mL\n")
cat("目标AUC:", target_auc, "h*ng/mL\n")
cat("建议剂量:", round(dose_adjustment, 0), "mg\n")
|
本章介绍了药代动力学建模的基本原理和实践方法。我们首先学习了如何准备和探索药代动力学数据,然后介绍了非房室模型分析的方法和应用。接着,我们深入探讨了房室模型的构建,包括一室模型、二室模型和特殊吸收模型。我们还学习了参数估计方法和模型评估技术,包括诊断图和视觉预测检验。最后,我们讨论了协变量模型的构建和模型的实际应用,如剂量模拟、特殊人群剂量调整和治疗药物监测。
通过本章的学习,读者应该能够使用R语言进行基本的药代动力学建模和分析,为药物研发和临床实践提供定量支持。在下一章中,我们将探讨药效学建模,学习如何描述药物浓度与效应之间的关系。
第四章:药效学建模#
4.1 药效学数据准备与探索#
药效学(Pharmacodynamics, PD)研究药物与靶点相互作用产生的生物效应,描述了"药物对机体的作用"。在开始建模之前,正确准备和探索药效学数据是至关重要的。
4.1.1 药效学数据类型与特点#
药效学数据类型多样,根据测量方式和数据特性可分为以下几类:
连续型数据:
- 血压、心率、血糖等生理指标
- 酶活性、受体占有率等生化指标
- 肿瘤体积、炎症面积等病理指标
计数型数据:
分类型数据:
- 疼痛评分(如视觉模拟评分,VAS)
- 临床评分量表(如Hamilton抑郁量表)
- 不良反应分级
二元型数据:
时间-事件数据:
每种数据类型需要不同的建模方法和统计分析技术。
4.1.2 数据结构与格式要求#
药效学数据通常包含以下关键变量:
- ID:受试者标识符
- TIME:观测时间点
- DV(Dependent Variable):药效学观测值
- DOSE:给药剂量
- CONC:药物浓度(如果有PK测量)
- 协变量:如体重、年龄、性别、疾病严重程度等
以下是一个典型的PD数据结构示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # 创建示例PD数据
pd_data <- data.frame(
ID = rep(1:3, each = 6),
TIME = rep(c(0, 1, 2, 4, 8, 12), 3),
DOSE = rep(c(10, 30, 100), each = 6),
CONC = c(0, 5.2, 4.1, 2.3, 0.9, 0.3,
0, 15.6, 12.3, 6.9, 2.7, 0.9,
0, 52.0, 41.0, 23.0, 9.0, 3.0),
EFFECT = c(0, 15, 25, 18, 8, 2,
0, 35, 45, 30, 15, 5,
0, 65, 80, 60, 30, 10),
WT = rep(c(70, 65, 80), each = 6),
SEX = rep(c(1, 0, 1), each = 6)
)
# 查看数据结构
head(pd_data)
|
对于不同的建模软件,数据格式可能有特定要求:
- nlmixr/nlmixr2:接受标准的长格式数据,变量名可以自定义
- NONMEM:通常要求特定的变量名和格式
- R的统计建模函数:如
nls()
、glm()
等,通常需要数据框格式
4.1.3 数据清洗与转换#
在建模前,通常需要对原始数据进行清洗和转换:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| library(dplyr)
library(tidyr)
# 检查并处理缺失值
pd_data_clean <- pd_data %>%
# 将效应为NA的观测标记
mutate(FLAG = ifelse(is.na(EFFECT), 1, 0))
# 计算基线值
pd_data_clean <- pd_data_clean %>%
group_by(ID) %>%
mutate(BASELINE = EFFECT[TIME == min(TIME)]) %>%
ungroup()
# 计算相对于基线的变化
pd_data_clean <- pd_data_clean %>%
mutate(
CHANGE = EFFECT - BASELINE,
PCHG = (EFFECT - BASELINE) / BASELINE * 100
)
# 对于某些模型,可能需要对效应进行转换
pd_data_clean <- pd_data_clean %>%
mutate(
LOGIT_EFFECT = ifelse(EFFECT > 0 & EFFECT < 100,
log(EFFECT / (100 - EFFECT)), NA)
)
# 标准化协变量
pd_data_clean <- pd_data_clean %>%
mutate(
WT_NORM = WT / 70 # 体重标准化为70kg
)
|
4.1.4 探索性数据分析#
在建模前进行探索性数据分析,可以帮助我们了解数据特征和潜在的模型结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| library(ggplot2)
# 绘制效应-时间曲线
ggplot(pd_data_clean, aes(x = TIME, y = EFFECT, color = factor(DOSE), group = interaction(ID, DOSE))) +
geom_point() +
geom_line() +
labs(title = "效应-时间曲线",
x = "时间 (h)",
y = "效应",
color = "剂量 (mg)") +
theme_bw()
# 绘制效应-浓度曲线
ggplot(pd_data_clean, aes(x = CONC, y = EFFECT, color = factor(ID))) +
geom_point() +
geom_path(arrow = arrow(length = unit(0.2, "cm"), ends = "last", type = "closed")) +
labs(title = "效应-浓度曲线",
x = "浓度 (ng/mL)",
y = "效应",
color = "受试者") +
theme_bw()
# 检查滞后现象
ggplot(pd_data_clean, aes(x = CONC, y = EFFECT, color = factor(ID))) +
geom_point() +
geom_path() +
facet_wrap(~ID) +
labs(title = "效应-浓度关系(检查滞后现象)",
x = "浓度 (ng/mL)",
y = "效应",
color = "受试者") +
theme_bw()
# 绘制剂量-反应曲线
pd_summary <- pd_data_clean %>%
group_by(DOSE) %>%
summarize(
MAX_EFFECT = mean(EFFECT[TIME == 2]), # 假设最大效应在2小时
SE = sd(EFFECT[TIME == 2]) / sqrt(n())
)
ggplot(pd_summary, aes(x = DOSE, y = MAX_EFFECT)) +
geom_point(size = 3) +
geom_errorbar(aes(ymin = MAX_EFFECT - SE, ymax = MAX_EFFECT + SE), width = 0.1) +
scale_x_log10() +
labs(title = "剂量-反应曲线",
x = "剂量 (mg, 对数尺度)",
y = "最大效应") +
theme_bw()
|
4.1.5 初步模型选择依据#
探索性分析可以帮助我们初步确定模型结构:
浓度-效应关系形状:
- 线性关系可能适合线性模型
- S形曲线可能适合Emax或Sigmoid Emax模型
- 钟形曲线可能需要双向模型
时间-效应关系:
- 效应与浓度同步变化可能适合直接效应模型
- 效应滞后于浓度可能需要效应室模型或间接响应模型
- 效应持续时间长于药物暴露可能需要考虑耐受性或反馈机制
基线效应:
- 存在明显基线效应需要在模型中考虑
- 基线随时间变化可能需要疾病进展模型
变异性来源:
4.2 直接效应模型#
直接效应模型假设药物效应与药物浓度直接相关,无时间滞后。这是最简单的PD模型类型,适用于药物作用迅速且可逆的情况。
4.2.1 线性模型#
线性模型假设效应与浓度成正比:
$E = E_0 + \text{Slope} \times C$
其中,$E$是效应,$E_0$是基线效应,$\text{Slope}$是斜率,$C$是药物浓度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # 使用基础R的nls函数拟合线性模型
linear_model <- nls(EFFECT ~ E0 + Slope * CONC,
data = pd_data_clean,
start = list(E0 = 0, Slope = 1))
# 查看拟合结果
summary(linear_model)
# 使用拟合结果进行预测
conc_range <- seq(0, max(pd_data_clean$CONC), length.out = 100)
pred_linear <- predict(linear_model, newdata = data.frame(CONC = conc_range))
# 绘制拟合曲线
ggplot() +
geom_point(data = pd_data_clean, aes(x = CONC, y = EFFECT)) +
geom_line(data = data.frame(CONC = conc_range, EFFECT = pred_linear),
aes(x = CONC, y = EFFECT), color = "blue") +
labs(title = "线性模型拟合",
x = "浓度 (ng/mL)",
y = "效应") +
theme_bw()
|
4.2.2 Emax模型#
Emax模型是药效学中最常用的模型之一,描述了药物浓度与效应之间的非线性饱和关系:
$E = E_0 + \frac{E_{max} \times C}{EC_{50} + C}$
其中,$E_{max}$是最大效应,$EC_{50}$是产生50%最大效应的浓度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # 使用基础R的nls函数拟合Emax模型
emax_model <- nls(EFFECT ~ E0 + (Emax * CONC) / (EC50 + CONC),
data = pd_data_clean,
start = list(E0 = 0, Emax = 100, EC50 = 10))
# 查看拟合结果
summary(emax_model)
# 使用拟合结果进行预测
pred_emax <- predict(emax_model, newdata = data.frame(CONC = conc_range))
# 绘制拟合曲线
ggplot() +
geom_point(data = pd_data_clean, aes(x = CONC, y = EFFECT)) +
geom_line(data = data.frame(CONC = conc_range, EFFECT = pred_emax),
aes(x = CONC, y = EFFECT), color = "red") +
labs(title = "Emax模型拟合",
x = "浓度 (ng/mL)",
y = "效应") +
theme_bw()
|
4.2.3 Sigmoid Emax模型#
Sigmoid Emax模型在Emax模型基础上增加了Hill系数,可以描述更陡峭或更平缓的浓度-效应曲线:
$E = E_0 + \frac{E_{max} \times C^n}{EC_{50}^n + C^n}$
其中,$n$是Hill系数,描述曲线的陡峭程度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # 使用基础R的nls函数拟合Sigmoid Emax模型
sigmoid_model <- nls(EFFECT ~ E0 + (Emax * CONC^Hill) / (EC50^Hill + CONC^Hill),
data = pd_data_clean,
start = list(E0 = 0, Emax = 100, EC50 = 10, Hill = 1))
# 查看拟合结果
summary(sigmoid_model)
# 使用拟合结果进行预测
pred_sigmoid <- predict(sigmoid_model, newdata = data.frame(CONC = conc_range))
# 绘制拟合曲线
ggplot() +
geom_point(data = pd_data_clean, aes(x = CONC, y = EFFECT)) +
geom_line(data = data.frame(CONC = conc_range, EFFECT = pred_sigmoid),
aes(x = CONC, y = EFFECT), color = "green") +
labs(title = "Sigmoid Emax模型拟合",
x = "浓度 (ng/mL)",
y = "效应") +
theme_bw()
|
4.2.4 抑制性Emax模型#
对于抑制性药物(如降压药),可以使用抑制性Emax模型:
$E = E_0 \times (1 - \frac{I_{max} \times C}{IC_{50} + C})$
其中,$I_{max}$是最大抑制比例,$IC_{50}$是产生50%最大抑制的浓度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| # 假设我们有抑制性药物的数据
inhibitory_data <- data.frame(
CONC = c(0, 1, 3, 10, 30, 100),
EFFECT = c(100, 80, 60, 40, 30, 25) # 效应随浓度增加而降低
)
# 使用基础R的nls函数拟合抑制性Emax模型
inhibitory_model <- nls(EFFECT ~ E0 * (1 - (Imax * CONC) / (IC50 + CONC)),
data = inhibitory_data,
start = list(E0 = 100, Imax = 0.8, IC50 = 10))
# 查看拟合结果
summary(inhibitory_model)
# 使用拟合结果进行预测
conc_range_inh <- seq(0, max(inhibitory_data$CONC), length.out = 100)
pred_inhibitory <- predict(inhibitory_model,
newdata = data.frame(CONC = conc_range_inh))
# 绘制拟合曲线
ggplot() +
geom_point(data = inhibitory_data, aes(x = CONC, y = EFFECT)) +
geom_line(data = data.frame(CONC = conc_range_inh, EFFECT = pred_inhibitory),
aes(x = CONC, y = EFFECT), color = "purple") +
labs(title = "抑制性Emax模型拟合",
x = "浓度 (ng/mL)",
y = "效应") +
theme_bw()
|
4.2.5 双向模型#
某些药物在低浓度时产生一种效应,在高浓度时产生相反的效应,可以使用双向模型:
$E = E_0 + \frac{E_{max1} \times C}{EC_{50,1} + C} - \frac{E_{max2} \times C^n}{EC_{50,2}^n + C^n}$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| # 假设我们有双向效应的数据
biphasic_data <- data.frame(
CONC = c(0, 0.1, 0.3, 1, 3, 10, 30, 100),
EFFECT = c(0, 10, 25, 40, 30, 15, 5, 0) # 先增加后减少
)
# 使用基础R的nls函数拟合双向模型
biphasic_model <- nls(EFFECT ~ E0 + (Emax1 * CONC) / (EC501 + CONC) -
(Emax2 * CONC^Hill) / (EC502^Hill + CONC^Hill),
data = biphasic_data,
start = list(E0 = 0, Emax1 = 50, EC501 = 1,
Emax2 = 50, EC502 = 10, Hill = 1))
# 查看拟合结果
summary(biphasic_model)
# 使用拟合结果进行预测
conc_range_bi <- seq(0, max(biphasic_data$CONC), length.out = 100)
pred_biphasic <- predict(biphasic_model,
newdata = data.frame(CONC = conc_range_bi))
# 绘制拟合曲线
ggplot() +
geom_point(data = biphasic_data, aes(x = CONC, y = EFFECT)) +
geom_line(data = data.frame(CONC = conc_range_bi, EFFECT = pred_biphasic),
aes(x = CONC, y = EFFECT), color = "orange") +
labs(title = "双向模型拟合",
x = "浓度 (ng/mL)",
y = "效应") +
theme_bw()
|
4.2.6 模型比较与选择#
在拟合多个模型后,需要比较它们的性能并选择最佳模型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| # 比较线性模型、Emax模型和Sigmoid Emax模型
model_comparison <- data.frame(
Model = c("Linear", "Emax", "Sigmoid Emax"),
RSS = c(sum(residuals(linear_model)^2),
sum(residuals(emax_model)^2),
sum(residuals(sigmoid_model)^2)),
AIC = c(AIC(linear_model), AIC(emax_model), AIC(sigmoid_model)),
BIC = c(BIC(linear_model), BIC(emax_model), BIC(sigmoid_model))
)
# 打印比较结果
print(model_comparison)
# 绘制所有模型的拟合曲线
ggplot() +
geom_point(data = pd_data_clean, aes(x = CONC, y = EFFECT)) +
geom_line(data = data.frame(CONC = conc_range, EFFECT = pred_linear),
aes(x = CONC, y = EFFECT, color = "Linear")) +
geom_line(data = data.frame(CONC = conc_range, EFFECT = pred_emax),
aes(x = CONC, y = EFFECT, color = "Emax")) +
geom_line(data = data.frame(CONC = conc_range, EFFECT = pred_sigmoid),
aes(x = CONC, y = EFFECT, color = "Sigmoid Emax")) +
scale_color_manual(values = c("Linear" = "blue", "Emax" = "red",
"Sigmoid Emax" = "green")) +
labs(title = "模型比较",
x = "浓度 (ng/mL)",
y = "效应",
color = "模型") +
theme_bw()
|
4.3 时间延迟模型#
在许多情况下,药物效应与浓度之间存在时间滞后,需要使用时间延迟模型来描述这种关系。
4.3.1 效应室模型#
效应室模型引入一个假设的"效应室",药物需要从中央室扩散到效应室才能产生效应:
$\frac{dC_e}{dt} = k_{1e} \times C - k_{e0} \times C_e$
$E = f(C_e)$
其中,$C_e$是效应室浓度,$k_{1e}$是药物从中央室到效应室的传递速率常数,$k_{e0}$是药物从效应室消除的速率常数,$f(C_e)$是效应室浓度与效应的关系函数(如Emax模型)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| # 使用mrgsolve包实现效应室模型
library(mrgsolve)
# 定义效应室模型代码
effect_comp_code <- '
$PARAM
CL = 5, V = 20, KA = 1.2, // PK参数
KE0 = 0.5, // 效应室速率常数
E0 = 0, EMAX = 100, EC50 = 10 // PD参数
$CMT GUT CENT EFFECT
$ODE
dxdt_GUT = -KA * GUT;
dxdt_CENT = KA * GUT - (CL/V) * CENT;
dxdt_EFFECT = KE0 * (CENT/V - EFFECT); // 效应室方程
$TABLE
CP = CENT/V;
CE = EFFECT;
RESP = E0 + (EMAX * CE) / (EC50 + CE); // Emax模型
$CAPTURE CP CE RESP
'
# 编译模型
effect_comp_model <- mcode("effect_comp", effect_comp_code)
# 设置剂量和观测时间
ev <- ev(amt = 100, cmt = 1) // 100mg口服给药
times <- seq(0, 24, by = 0.1)
# 运行模拟
out <- effect_comp_model %>%
ev(ev) %>%
mrgsim(end = 24, delta = 0.1)
# 转换为数据框
sim_data <- as.data.frame(out)
# 绘制浓度、效应室浓度和效应随时间的变化
ggplot(sim_data) +
geom_line(aes(x = time, y = CP, color = "血浆浓度")) +
geom_line(aes(x = time, y = CE, color = "效应室浓度")) +
geom_line(aes(x = time, y = RESP, color = "效应")) +
scale_y_continuous(name = "浓度 (ng/mL) / 效应") +
scale_color_manual(values = c("血浆浓度" = "blue",
"效应室浓度" = "red",
"效应" = "green")) +
labs(title = "效应室模型模拟",
x = "时间 (h)",
color = "变量") +
theme_bw()
# 绘制滞后环(hysteresis loop)
ggplot(sim_data, aes(x = CP, y = RESP)) +
geom_path(arrow = arrow(length = unit(0.2, "cm"),
ends = "last", type = "closed")) +
labs(title = "滞后环",
x = "血浆浓度 (ng/mL)",
y = "效应") +
theme_bw()
|
4.3.2 间接响应模型#
间接响应模型假设药物通过影响生理过程的产生率或消除率来间接产生效应。Jusko和D’Argenio提出了四种基本的间接响应模型:
模型I:抑制产生率
$\frac{dR}{dt} = k_{in} \times (1 - \frac{E_{max} \times C}{EC_{50} + C}) - k_{out} \times R$
模型II:促进消除率
$\frac{dR}{dt} = k_{in} - k_{out} \times (1 + \frac{E_{max} \times C}{EC_{50} + C}) \times R$
模型III:促进产生率
$\frac{dR}{dt} = k_{in} \times (1 + \frac{E_{max} \times C}{EC_{50} + C}) - k_{out} \times R$
模型IV:抑制消除率
$\frac{dR}{dt} = k_{in} - k_{out} \times (1 - \frac{E_{max} \times C}{EC_{50} + C}) \times R$
其中,$R$是响应变量,$k_{in}$是产生率常数,$k_{out}$是消除率常数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| # 使用mrgsolve包实现间接响应模型
library(mrgsolve)
# 定义间接响应模型代码(以模型I为例)
indirect_code <- '
$PARAM
CL = 5, V = 20, KA = 1.2, // PK参数
KIN = 10, KOUT = 0.5, // 产生和消除率常数
EMAX = 1, EC50 = 10 // 药效学参数
$CMT GUT CENT RESP
$ODE
dxdt_GUT = -KA * GUT;
dxdt_CENT = KA * GUT - (CL/V) * CENT;
CP = CENT/V;
INH = EMAX * CP / (EC50 + CP); // 抑制函数
// 模型I:抑制产生率
dxdt_RESP = KIN * (1 - INH) - KOUT * RESP;
$TABLE
CP = CENT/V;
$CAPTURE CP RESP
'
# 编译模型
indirect_model <- mcode("indirect", indirect_code)
# 设置剂量和观测时间
ev <- ev(amt = 100, cmt = 1) // 100mg口服给药
times <- seq(0, 48, by = 0.1)
# 运行模拟
out <- indirect_model %>%
ev(ev) %>%
mrgsim(end = 48, delta = 0.1)
# 转换为数据框
sim_data <- as.data.frame(out)
# 绘制浓度和响应随时间的变化
ggplot(sim_data) +
geom_line(aes(x = time, y = CP, color = "血浆浓度")) +
geom_line(aes(x = time, y = RESP, color = "响应")) +
scale_y_continuous(name = "浓度 (ng/mL) / 响应") +
scale_color_manual(values = c("血浆浓度" = "blue", "响应" = "red")) +
labs(title = "间接响应模型模拟(模型I:抑制产生率)",
x = "时间 (h)",
color = "变量") +
theme_bw()
# 绘制滞后环
ggplot(sim_data, aes(x = CP, y = RESP)) +
geom_path(arrow = arrow(length = unit(0.2, "cm"),
ends = "last", type = "closed")) +
labs(title = "滞后环",
x = "血浆浓度 (ng/mL)",
y = "响应") +
theme_bw()
|
4.3.3 耐受性模型#
长期给药后,药物效应可能会减弱,这种现象称为耐受性或脱敏。耐受性模型通常引入一个反馈变量来描述这种现象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| # 使用mrgsolve包实现耐受性模型
library(mrgsolve)
# 定义耐受性模型代码
tolerance_code <- '
$PARAM
CL = 5, V = 20, KA = 1.2, // PK参数
E0 = 0, EMAX = 100, EC50 = 10, // 基本PD参数
KTOL = 0.05, KOUT = 0.2 // 耐受性参数
$CMT GUT CENT TOL RESP
$ODE
dxdt_GUT = -KA * GUT;
dxdt_CENT = KA * GUT - (CL/V) * CENT;
CP = CENT/V;
STIM = EMAX * CP / (EC50 + CP); // 刺激函数
// 耐受性发展
dxdt_TOL = KTOL * STIM - KOUT * TOL;
// 响应(考虑耐受性)
RESP = E0 + STIM * (1 - TOL);
dxdt_RESP = 0; // 仅用于捕获RESP
$TABLE
CP = CENT/V;
$CAPTURE CP RESP TOL
'
# 编译模型
tolerance_model <- mcode("tolerance", tolerance_code)
# 设置多次给药方案
ev <- ev(amt = 100, cmt = 1, ii = 12, addl = 7) // 每12小时给药一次,共8次
times <- seq(0, 96, by = 0.1)
# 运行模拟
out <- tolerance_model %>%
ev(ev) %>%
mrgsim(end = 96, delta = 0.1)
# 转换为数据框
sim_data <- as.data.frame(out)
# 绘制浓度、响应和耐受性随时间的变化
ggplot(sim_data) +
geom_line(aes(x = time, y = CP, color = "血浆浓度")) +
geom_line(aes(x = time, y = RESP, color = "响应")) +
geom_line(aes(x = time, y = TOL * 100, color = "耐受性")) + // 缩放以便可视化
scale_y_continuous(name = "浓度 (ng/mL) / 响应 / 耐受性(%)") +
scale_color_manual(values = c("血浆浓度" = "blue",
"响应" = "red",
"耐受性" = "green")) +
labs(title = "耐受性模型模拟",
x = "时间 (h)",
color = "变量") +
theme_bw()
|
4.3.4 疾病进展模型#
对于慢性疾病,疾病自然进展可能会影响药物效应的观察。疾病进展模型结合了疾病自然进展和药物干预效应:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| # 使用mrgsolve包实现疾病进展模型
library(mrgsolve)
# 定义疾病进展模型代码
disease_code <- '
$PARAM
CL = 5, V = 20, KA = 1.2, // PK参数
BASE = 100, // 基线值
ALPHA = 0.01, // 疾病进展率
EMAX = 0.8, EC50 = 10 // 药效学参数
$CMT GUT CENT RESP
$ODE
dxdt_GUT = -KA * GUT;
dxdt_CENT = KA * GUT - (CL/V) * CENT;
CP = CENT/V;
// 疾病进展 + 药物效应
DRUG_EFFECT = EMAX * CP / (EC50 + CP);
dxdt_RESP = ALPHA * RESP * (1 - DRUG_EFFECT);
$TABLE
CP = CENT/V;
$CAPTURE CP RESP
'
# 编译模型
disease_model <- mcode("disease", disease_code)
# 设置初始条件和给药方案
init <- c(RESP = 100) // 初始疾病状态
ev1 <- ev(amt = 0, cmt = 1) // 安慰剂(无治疗)
ev2 <- ev(amt = 100, cmt = 1, ii = 24, addl = 29) // 每天给药一次,共30天
# 运行模拟(无治疗)
out1 <- disease_model %>%
init(init) %>%
ev(ev1) %>%
mrgsim(end = 720, delta = 1) // 模拟30天
# 运行模拟(有治疗)
out2 <- disease_model %>%
init(init) %>%
ev(ev2) %>%
mrgsim(end = 720, delta = 1) // 模拟30天
# 转换为数据框并合并
sim_data1 <- as.data.frame(out1)
sim_data1$Treatment <- "无治疗"
sim_data2 <- as.data.frame(out2)
sim_data2$Treatment <- "有治疗"
sim_data <- rbind(sim_data1, sim_data2)
# 绘制疾病进展曲线
ggplot(sim_data, aes(x = time/24, y = RESP, color = Treatment)) +
geom_line() +
labs(title = "疾病进展模型模拟",
x = "时间 (天)",
y = "疾病状态",
color = "治疗") +
theme_bw()
|
4.4 群体药效学建模#
群体药效学建模考虑了个体间变异,使用非线性混合效应模型同时分析来自多个个体的数据。
4.4.1 使用nlmixr2构建群体PD模型#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| # 安装并加载nlmixr2
library(nlmixr2)
# 准备数据
# 确保数据包含ID, TIME, CONC, EFFECT等必要列
# 定义直接效应Emax模型
emax_pd_model <- function() {
ini({
# 固定效应参数(群体典型值)
E0 <- 0 # 基线效应
Emax <- 100 # 最大效应
EC50 <- 10 # 产生50%最大效应的浓度
# 随机效应参数(个体间变异)
eta.E0 ~ 0.1
eta.Emax ~ 0.3
eta.EC50 ~ 0.5
# 残差误差模型
add.err <- 5 # 加性误差
})
model({
# 参数转换
E0i = E0 * exp(eta.E0)
Emaxi = Emax * exp(eta.Emax)
EC50i = EC50 * exp(eta.EC50)
# Emax模型
EFFECT = E0i + (Emaxi * CONC) / (EC50i + CONC)
# 残差模型
EFFECT ~ add(add.err)
})
}
# 拟合模型
fit_emax_pd <- nlmixr(emax_pd_model, data = pd_data_clean, est = "saem")
# 查看拟合结果
summary(fit_emax_pd)
|
4.4.2 使用nlmixr2构建效应室模型#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| # 定义效应室模型
effect_comp_pd_model <- function() {
ini({
# 固定效应参数
E0 <- 0 # 基线效应
Emax <- 100 # 最大效应
EC50 <- 10 # 产生50%最大效应的浓度
ke0 <- 0.5 # 效应室速率常数
# 随机效应参数
eta.E0 ~ 0.1
eta.Emax ~ 0.3
eta.EC50 ~ 0.5
eta.ke0 ~ 0.4
# 残差误差模型
add.err <- 5 # 加性误差
})
model({
# 参数转换
E0i = E0 * exp(eta.E0)
Emaxi = Emax * exp(eta.Emax)
EC50i = EC50 * exp(eta.EC50)
ke0i = ke0 * exp(eta.ke0)
# 效应室微分方程
d/dt(Ce) = ke0i * (CONC - Ce)
# Emax模型
EFFECT = E0i + (Emaxi * Ce) / (EC50i + Ce)
# 残差模型
EFFECT ~ add(add.err)
})
}
# 拟合模型
fit_effect_comp <- nlmixr(effect_comp_pd_model, data = pd_data_clean, est = "saem")
# 查看拟合结果
summary(fit_effect_comp)
|
4.4.3 使用nlmixr2构建间接响应模型#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| # 定义间接响应模型(模型I:抑制产生率)
indirect_pd_model <- function() {
ini({
# 固定效应参数
kin <- 10 # 产生率常数
kout <- 0.5 # 消除率常数
Imax <- 1 # 最大抑制比例
IC50 <- 10 # 产生50%最大抑制的浓度
# 随机效应参数
eta.kin ~ 0.3
eta.kout ~ 0.3
eta.Imax ~ 0.2
eta.IC50 ~ 0.5
# 残差误差模型
add.err <- 5 # 加性误差
})
model({
# 参数转换
kini = kin * exp(eta.kin)
kouti = kout * exp(eta.kout)
Imaxi = Imax * exp(eta.Imax)
IC50i = IC50 * exp(eta.IC50)
# 抑制函数
INH = Imaxi * CONC / (IC50i + CONC)
# 间接响应微分方程(模型I:抑制产生率)
d/dt(RESP) = kini * (1 - INH) - kouti * RESP
# 残差模型
RESP ~ add(add.err)
})
}
# 拟合模型
fit_indirect <- nlmixr(indirect_pd_model, data = pd_data_clean, est = "saem")
# 查看拟合结果
summary(fit_indirect)
|
4.4.4 模型诊断与评估#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| library(xpose.nlmixr2)
library(ggplot2)
# 创建xpose数据库对象
xpdb <- xpose_data_nlmixr(fit_emax_pd)
# 观测值vs群体预测值
dv_vs_pred(xpdb) +
theme_bw() +
labs(title = "观测值 vs 群体预测值")
# 观测值vs个体预测值
dv_vs_ipred(xpdb) +
theme_bw() +
labs(title = "观测值 vs 个体预测值")
# 条件加权残差vs时间
res_vs_idv(xpdb) +
theme_bw() +
labs(title = "条件加权残差 vs 时间")
# 条件加权残差vs群体预测值
res_vs_pred(xpdb) +
theme_bw() +
labs(title = "条件加权残差 vs 群体预测值")
# 个体拟合图
ind_plots(xpdb, n_individuals = 9) +
theme_bw() +
labs(title = "个体拟合图")
# 视觉预测检验(VPC)
vpc_nlmixr2 <- vpc(fit_emax_pd, n = 500, stratify = NULL, seed = 1234)
plot(vpc_nlmixr2) +
theme_bw() +
labs(title = "视觉预测检验 (VPC)",
x = "浓度 (ng/mL)",
y = "效应")
|
4.4.5 协变量模型构建#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
| # 定义包含体重作为协变量的Emax模型
cov_pd_model <- function() {
ini({
# 固定效应参数
E0 <- 0 # 基线效应
Emax <- 100 # 最大效应
EC50 <- 10 # 产生50%最大效应的浓度
WT_EC50 <- 0.75 # 体重对EC50的影响指数
# 随机效应参数
eta.E0 ~ 0.1
eta.Emax ~ 0.3
eta.EC50 ~ 0.5
# 残差误差模型
add.err <- 5 # 加性误差
})
model({
# 协变量效应
wt70 <- WT/70 # 标准化体重
# 参数转换
E0i = E0 * exp(eta.E0)
Emaxi = Emax * exp(eta.Emax)
EC50i = EC50 * exp(eta.EC50) * wt70^WT_EC50 # 体重对EC50的影响
# Emax模型
EFFECT = E0i + (Emaxi * CONC) / (EC50i + CONC)
# 残差模型
EFFECT ~ add(add.err)
})
}
# 拟合协变量模型
fit_cov_pd <- nlmixr(cov_pd_model, data = pd_data_clean, est = "saem")
# 查看拟合结果
summary(fit_cov_pd)
# 比较基础模型和协变量模型
cov_comparison <- data.frame(
Model = c("Base Model", "Covariate Model"),
OFV = c(fit_emax_pd$objf, fit_cov_pd$objf),
AIC = c(fit_emax_pd$AIC, fit_cov_pd$AIC),
BIC = c(fit_emax_pd$BIC, fit_cov_pd$BIC),
EC50_BSV = c(fit_emax_pd$omega[3,3], fit_cov_pd$omega[3,3])
)
# 计算BSV减少百分比
cov_comparison$EC50_BSV_reduction <- c(NA, (1 - fit_cov_pd$omega[3,3]/fit_emax_pd$omega[3,3]) * 100)
# 计算OFV差异和p值
delta_OFV <- abs(fit_emax_pd$objf - fit_cov_pd$objf)
delta_params <- abs(length(fit_emax_pd$theta) - length(fit_cov_pd$theta))
p_value <- 1 - pchisq(delta_OFV, df = delta_params)
# 添加到比较表
cov_comparison$delta_OFV <- c(NA, delta_OFV)
cov_comparison$p_value <- c(NA, p_value)
# 打印比较结果
print(cov_comparison)
|
4.5 PK/PD整合模型#
PK/PD整合模型将药代动力学和药效学结合起来,描述从给药到效应的完整过程。
4.5.1 顺序PK/PD建模#
顺序PK/PD建模是一种两步法,首先拟合PK模型,然后使用PK模型预测的浓度拟合PD模型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| # 第一步:拟合PK模型
# 假设我们已经拟合了PK模型并获得了个体参数
# fit_pk <- nlmixr(pk_model, data = pk_data, est = "saem")
# 使用PK模型预测浓度
# pred_pk <- predict(fit_pk, pk_data)
# pk_data$PRED_CONC <- pred_pk$PRED
# 第二步:使用预测的浓度拟合PD模型
# pd_data_with_pred <- merge(pd_data,
# pk_data[, c("ID", "TIME", "PRED_CONC")],
# by = c("ID", "TIME"))
# 定义PD模型(使用预测的浓度)
pd_model_with_pred <- function() {
ini({
# 固定效应参数
E0 <- 0 # 基线效应
Emax <- 100 # 最大效应
EC50 <- 10 # 产生50%最大效应的浓度
# 随机效应参数
eta.E0 ~ 0.1
eta.Emax ~ 0.3
eta.EC50 ~ 0.5
# 残差误差模型
add.err <- 5 # 加性误差
})
model({
# 参数转换
E0i = E0 * exp(eta.E0)
Emaxi = Emax * exp(eta.Emax)
EC50i = EC50 * exp(eta.EC50)
# Emax模型(使用预测的浓度)
EFFECT = E0i + (Emaxi * PRED_CONC) / (EC50i + PRED_CONC)
# 残差模型
EFFECT ~ add(add.err)
})
}
# 拟合PD模型
# fit_pd_with_pred <- nlmixr(pd_model_with_pred,
# data = pd_data_with_pred,
# est = "saem")
# 查看拟合结果
# summary(fit_pd_with_pred)
|
4.5.2 同时PK/PD建模#
同时PK/PD建模是一种一步法,同时拟合PK和PD模型,考虑两者之间的相关性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| # 定义同时PK/PD模型
pkpd_model <- function() {
ini({
# PK参数
tka <- log(1.0) # log(Ka)
tcl <- log(5.0) # log(CL)
tv <- log(80.0) # log(V)
# PD参数
E0 <- 0 # 基线效应
Emax <- 100 # 最大效应
EC50 <- 10 # 产生50%最大效应的浓度
# 随机效应参数
eta.ka ~ 0.4
eta.cl ~ 0.3
eta.v ~ 0.2
eta.E0 ~ 0.1
eta.Emax ~ 0.3
eta.EC50 ~ 0.5
# 残差误差模型
prop.err <- 0.2 # PK比例误差
add.err <- 5 # PD加性误差
})
model({
# PK参数转换
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl)
v <- exp(tv + eta.v)
# PD参数转换
E0i = E0 * exp(eta.E0)
Emaxi = Emax * exp(eta.Emax)
EC50i = EC50 * exp(eta.EC50)
# PK模型
d/dt(depot) = -ka * depot
d/dt(central) = ka * depot - cl/v * central
# 计算浓度
cp = central / v
# PD模型
EFFECT = E0i + (Emaxi * cp) / (EC50i + cp)
# 残差模型
cp ~ prop(prop.err)
EFFECT ~ add(add.err)
})
}
# 准备同时包含PK和PD数据的数据集
# pkpd_data <- ...
# 拟合同时PK/PD模型
# fit_pkpd <- nlmixr(pkpd_model, data = pkpd_data, est = "saem")
# 查看拟合结果
# summary(fit_pkpd)
|
4.5.3 效应室PK/PD模型#
效应室PK/PD模型考虑了药物效应与浓度之间的时间滞后:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| # 定义效应室PK/PD模型
pkpd_effect_comp_model <- function() {
ini({
# PK参数
tka <- log(1.0) # log(Ka)
tcl <- log(5.0) # log(CL)
tv <- log(80.0) # log(V)
# 效应室参数
tke0 <- log(0.5) # log(ke0)
# PD参数
E0 <- 0 # 基线效应
Emax <- 100 # 最大效应
EC50 <- 10 # 产生50%最大效应的浓度
# 随机效应参数
eta.ka ~ 0.4
eta.cl ~ 0.3
eta.v ~ 0.2
eta.ke0 ~ 0.4
eta.E0 ~ 0.1
eta.Emax ~ 0.3
eta.EC50 ~ 0.5
# 残差误差模型
prop.err <- 0.2 # PK比例误差
add.err <- 5 # PD加性误差
})
model({
# PK参数转换
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl)
v <- exp(tv + eta.v)
ke0 <- exp(tke0 + eta.ke0)
# PD参数转换
E0i = E0 * exp(eta.E0)
Emaxi = Emax * exp(eta.Emax)
EC50i = EC50 * exp(eta.EC50)
# PK模型
d/dt(depot) = -ka * depot
d/dt(central) = ka * depot - cl/v * central
# 计算浓度
cp = central / v
# 效应室模型
d/dt(effect) = ke0 * (cp - effect)
# PD模型
EFFECT = E0i + (Emaxi * effect) / (EC50i + effect)
# 残差模型
cp ~ prop(prop.err)
EFFECT ~ add(add.err)
})
}
# 拟合效应室PK/PD模型
# fit_pkpd_effect <- nlmixr(pkpd_effect_comp_model,
# data = pkpd_data,
# est = "saem")
# 查看拟合结果
# summary(fit_pkpd_effect)
|
4.5.4 间接响应PK/PD模型#
间接响应PK/PD模型描述了药物通过影响生理过程的产生率或消除率来间接产生效应:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
| # 定义间接响应PK/PD模型(模型I:抑制产生率)
pkpd_indirect_model <- function() {
ini({
# PK参数
tka <- log(1.0) # log(Ka)
tcl <- log(5.0) # log(CL)
tv <- log(80.0) # log(V)
# PD参数
kin <- 10 # 产生率常数
kout <- 0.5 # 消除率常数
Imax <- 1 # 最大抑制比例
IC50 <- 10 # 产生50%最大抑制的浓度
# 随机效应参数
eta.ka ~ 0.4
eta.cl ~ 0.3
eta.v ~ 0.2
eta.kin ~ 0.3
eta.kout ~ 0.3
eta.Imax ~ 0.2
eta.IC50 ~ 0.5
# 残差误差模型
prop.err <- 0.2 # PK比例误差
add.err <- 5 # PD加性误差
})
model({
# PK参数转换
ka <- exp(tka + eta.ka)
cl <- exp(tcl + eta.cl)
v <- exp(tv + eta.v)
# PD参数转换
kini = kin * exp(eta.kin)
kouti = kout * exp(eta.kout)
Imaxi = Imax * exp(eta.Imax)
IC50i = IC50 * exp(eta.IC50)
# PK模型
d/dt(depot) = -ka * depot
d/dt(central) = ka * depot - cl/v * central
# 计算浓度
cp = central / v
# 抑制函数
INH = Imaxi * cp / (IC50i + cp)
# 间接响应模型(模型I:抑制产生率)
d/dt(RESP) = kini * (1 - INH) - kouti * RESP
# 残差模型
cp ~ prop(prop.err)
RESP ~ add(add.err)
})
}
# 拟合间接响应PK/PD模型
# fit_pkpd_indirect <- nlmixr(pkpd_indirect_model,
# data = pkpd_data,
# est = "saem")
# 查看拟合结果
# summary(fit_pkpd_indirect)
|
4.6 模型应用#
构建并验证模型后,可以将其应用于各种药效学问题。
4.6.1 剂量-反应关系模拟#
使用模型模拟不同剂量下的药物效应,帮助确定最佳治疗剂量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
| library(ggplot2)
# 使用最终模型进行模拟
# final_model <- fit_pkpd_effect # 假设效应室PK/PD模型是最终模型
# 创建不同剂量的模拟数据
sim_doses <- c(10, 30, 100, 300)
sim_times <- seq(0, 48, by = 0.1)
sim_subjects <- 100
# 创建模拟数据框
sim_data <- data.frame()
for (dose in sim_doses) {
for (i in 1:sim_subjects) {
# 随机生成体重
wt <- rnorm(1, mean = 70, sd = 10)
# 创建单个受试者的数据
subj_data <- data.frame(
ID = paste0(i, "_", dose),
TIME = c(0, sim_times),
DV = NA,
AMT = c(dose, rep(0, length(sim_times))),
CMT = 1,
EVID = c(1, rep(0, length(sim_times))),
MDV = c(1, rep(1, length(sim_times))),
WT = wt
)
sim_data <- rbind(sim_data, subj_data)
}
}
# 使用模型进行模拟
# sim_res <- predict(final_model, sim_data)
# 提取预测结果
# sim_pred <- cbind(sim_data, EFFECT = sim_res$EFFECT)
# sim_pred$DOSE <- as.factor(gsub(".*_", "", sim_pred$ID))
# 计算每个剂量组的分位数
# sim_summary <- sim_pred %>%
# filter(EVID == 0) %>%
# group_by(DOSE, TIME) %>%
# summarize(
# median = median(EFFECT),
# lower = quantile(EFFECT, 0.05),
# upper = quantile(EFFECT, 0.95)
# )
# 绘制模拟结果
# ggplot(sim_summary, aes(x = TIME, y = median, color = DOSE, fill = DOSE)) +
# geom_line() +
# geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2, color = NA) +
# labs(title = "不同剂量的效应-时间曲线模拟",
# x = "时间 (h)",
# y = "预测效应",
# color = "剂量 (mg)",
# fill = "剂量 (mg)") +
# theme_bw()
# 模拟剂量-反应曲线
# 假设我们已经有了模拟结果
# 创建一个模拟的剂量-反应数据
set.seed(123)
dose_resp_data <- data.frame(
DOSE = rep(c(1, 3, 10, 30, 100, 300), each = 20),
EFFECT = c(
rnorm(20, mean = 5, sd = 2),
rnorm(20, mean = 15, sd = 3),
rnorm(20, mean = 35, sd = 5),
rnorm(20, mean = 60, sd = 7),
rnorm(20, mean = 80, sd = 8),
rnorm(20, mean = 90, sd = 8)
)
)
# 计算每个剂量组的均值和标准误
dose_resp_summary <- dose_resp_data %>%
group_by(DOSE) %>%
summarize(
mean_effect = mean(EFFECT),
se = sd(EFFECT) / sqrt(n())
)
# 拟合Emax模型
emax_fit <- nls(mean_effect ~ E0 + (Emax * DOSE) / (ED50 + DOSE),
data = dose_resp_summary,
start = list(E0 = 0, Emax = 100, ED50 = 10))
# 使用拟合结果进行预测
dose_range <- seq(0.1, 1000, length.out = 100)
pred_emax <- predict(emax_fit, newdata = data.frame(DOSE = dose_range))
# 绘制剂量-反应曲线
ggplot() +
geom_point(data = dose_resp_summary,
aes(x = DOSE, y = mean_effect), size = 3) +
geom_errorbar(data = dose_resp_summary,
aes(x = DOSE,
ymin = mean_effect - se,
ymax = mean_effect + se),
width = 0.1) +
geom_line(data = data.frame(DOSE = dose_range, EFFECT = pred_emax),
aes(x = DOSE, y = EFFECT), color = "blue") +
scale_x_log10() +
labs(title = "剂量-反应曲线",
x = "剂量 (mg, 对数尺度)",
y = "效应") +
theme_bw()
# 计算ED50和ED90
params <- coef(emax_fit)
ED50 <- params["ED50"]
ED90 <- params["ED50"] * 9 # ED90 = ED50 * 9 for Emax model
cat("ED50:", round(ED50, 2), "mg\n")
cat("ED90:", round(ED90, 2), "mg\n")
|
4.6.2 特殊人群剂量调整#
使用模型评估特殊人群(如肝功能不全患者)的剂量调整需求:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
| # 假设我们有一个包含肝功能指标(LFT)作为协变量的模型
# 创建不同肝功能水平的模拟数据
liver_groups <- list(
"正常" = 1.0,
"轻度不全" = 0.7,
"中度不全" = 0.4,
"重度不全" = 0.2
)
dose <- 100 # 标准剂量
sim_times <- seq(0, 48, by = 0.1)
sim_subjects <- 50
# 创建模拟数据框
liver_sim_data <- data.frame()
for (group_name in names(liver_groups)) {
lft <- liver_groups[[group_name]]
for (i in 1:sim_subjects) {
# 添加一些变异性
lft_i <- rnorm(1, mean = lft, sd = lft * 0.1)
if (lft_i < 0.1) lft_i <- 0.1 # 避免过小值
if (lft_i > 1.0) lft_i <- 1.0 # 避免过大值
# 创建单个受试者的数据
subj_data <- data.frame(
ID = paste0(group_name, "_", i),
TIME = c(0, sim_times),
DV = NA,
AMT = c(dose, rep(0, length(sim_times))),
CMT = 1,
EVID = c(1, rep(0, length(sim_times))),
MDV = c(1, rep(1, length(sim_times))),
LFT = lft_i,
GROUP = group_name
)
liver_sim_data <- rbind(liver_sim_data, subj_data)
}
}
# 假设我们已经有了模拟结果
# 创建一个模拟的预测结果
set.seed(123)
liver_sim_data$EFFECT <- NA
for (group_name in names(liver_groups)) {
lft <- liver_groups[[group_name]]
scale_factor <- lft # 假设的LFT对效应的影响
# 基础效应曲线(Emax模型)
base_curve <- function(t) {
if (t == 0) return(0)
# 简化的PK/PD模型
ka <- 1.0
cl <- 5.0 / scale_factor # 假设肝功能影响清除率
v <- 80.0
dose <- 100
# 计算浓度
conc <- (dose * ka / (v * (ka - cl/v))) *
(exp(-cl/v * t) - exp(-ka * t))
# 计算效应
e0 <- 0
emax <- 100
ec50 <- 10
return(e0 + (emax * conc) / (ec50 + conc))
}
# 为每个受试者生成预测值
for (i in 1:sim_subjects) {
id <- paste0(group_name, "_", i)
idx <- liver_sim_data$ID == id & liver_sim_data$EVID == 0
t <- liver_sim_data$TIME[idx]
# 添加一些随机变异
effect <- sapply(t, base_curve) *
exp(rnorm(length(t), mean = 0, sd = 0.2))
liver_sim_data$EFFECT[idx] <- effect
}
}
# 计算每个肝功能组的分位数
liver_sim_summary <- liver_sim_data %>%
filter(EVID == 0) %>%
group_by(GROUP, TIME) %>%
summarize(
median = median(EFFECT),
lower = quantile(EFFECT, 0.05),
upper = quantile(EFFECT, 0.95)
)
# 绘制模拟结果
ggplot(liver_sim_summary, aes(x = TIME, y = median, color = GROUP, fill = GROUP)) +
geom_line() +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2, color = NA) +
labs(title = "不同肝功能水平的效应-时间曲线模拟",
x = "时间 (h)",
y = "预测效应",
color = "肝功能",
fill = "肝功能") +
theme_bw()
# 计算剂量调整建议
target_auc <- 1500 # 假设的目标AUC
liver_dose_adj <- data.frame(
GROUP = names(liver_groups),
LFT = unlist(liver_groups),
REL_CL = unlist(liver_groups), # 相对清除率
DOSE_ADJ = 100 * unlist(liver_groups) # 剂量调整
)
# 打印剂量调整建议
print(liver_dose_adj)
|
4.6.3 临床试验设计优化#
使用模型优化临床试验设计,包括剂量选择、采样时间和样本量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
| # 使用模型模拟不同剂量方案的效应-时间曲线
# 假设我们已经有了模型参数
e0 <- 0
emax <- 100
ec50 <- 10
# 定义剂量方案
dose_regimens <- list(
"单次给药" = data.frame(
time = c(0),
dose = c(100)
),
"每日一次" = data.frame(
time = c(0, 24, 48),
dose = c(50, 50, 50)
),
"每日两次" = data.frame(
time = c(0, 12, 24, 36, 48),
dose = c(25, 25, 25, 25, 25)
)
)
# 简化的PK/PD模型函数
pkpd_sim <- function(dose_times, dose_amounts, sim_times) {
# PK参数
ka <- 1.0
cl <- 5.0
v <- 80.0
# PD参数
e0 <- 0
emax <- 100
ec50 <- 10
# 初始化结果
conc <- rep(0, length(sim_times))
# 计算每个给药对浓度的贡献
for (i in 1:length(dose_times)) {
t_dose <- dose_times[i]
amt <- dose_amounts[i]
for (j in 1:length(sim_times)) {
t <- sim_times[j]
if (t >= t_dose) {
dt <- t - t_dose
conc[j] <- conc[j] + (amt * ka / (v * (ka - cl/v))) *
(exp(-cl/v * dt) - exp(-ka * dt))
}
}
}
# 计算效应
effect <- e0 + (emax * conc) / (ec50 + conc)
return(data.frame(time = sim_times, conc = conc, effect = effect))
}
# 模拟不同剂量方案
sim_times <- seq(0, 72, by = 0.1)
sim_results <- list()
for (regimen_name in names(dose_regimens)) {
regimen <- dose_regimens[[regimen_name]]
sim <- pkpd_sim(regimen$time, regimen$dose, sim_times)
sim$regimen <- regimen_name
sim_results[[regimen_name]] <- sim
}
# 合并结果
sim_data <- do.call(rbind, sim_results)
# 绘制效应-时间曲线
ggplot(sim_data, aes(x = time, y = effect, color = regimen)) +
geom_line() +
labs(title = "不同剂量方案的效应-时间曲线",
x = "时间 (h)",
y = "预测效应",
color = "剂量方案") +
theme_bw()
# 计算每个方案的效应指标
regimen_metrics <- sim_data %>%
group_by(regimen) %>%
summarize(
max_effect = max(effect),
min_effect = min(effect[time > 0]),
mean_effect = mean(effect),
time_above_50 = sum(effect > 50) * 0.1 # 时间间隔为0.1小时
)
# 打印方案比较结果
print(regimen_metrics)
# 优化采样时间
# 假设我们想要确定6个最佳采样时间点
# 使用D-优化准则(需要PopED包)
# library(PopED)
#
# # 定义模型函数
# model_function <- function(x, a, bpop, b, bocc) {
# t <- x[,1]
# ka <- bpop[1] * exp(b[1])
# cl <- bpop[2] * exp(b[2])
# v <- bpop[3] * exp(b[3])
# e0 <- bpop[4] * exp(b[4])
# emax <- bpop[5] * exp(b[5])
# ec50 <- bpop[6] * exp(b[6])
#
# # 计算浓度
# conc <- (100 * ka / (v * (ka - cl/v))) *
# (exp(-cl/v * t) - exp(-ka * t))
#
# # 计算效应
# effect <- e0 + (emax * conc) / (ec50 + conc)
#
# return(effect)
# }
#
# # 创建PopED数据库
# poped_db <- create.poped.database(
# ff_fun = model_function,
# fg_fun = NULL,
# bpop = c(ka = 1.0, cl = 5.0, v = 80.0, e0 = 0, emax = 100, ec50 = 10),
# d = c(ka = 0.09, cl = 0.09, v = 0.09, e0 = 0.09, emax = 0.09, ec50 = 0.09),
# sigma = 0.04,
# groupsize = 20,
# xt = c(0.5, 1, 2, 4, 8, 12), # 初始采样时间
# model_switch = 1
# )
#
# # 运行优化
# output <- poped_optimize(poped_db)
#
# # 查看优化后的采样时间
# optimal_times <- output$xt
# print(optimal_times)
|
4.6.4 生物标志物与临床终点的关系#
使用模型探索生物标志物与临床终点之间的关系,支持替代终点的使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| # 假设我们有生物标志物和临床终点的数据
biomarker_clinical <- data.frame(
ID = rep(1:50, each = 5),
TIME = rep(c(0, 1, 2, 4, 8), 50),
DOSE = rep(sample(c(10, 30, 100, 300), 50, replace = TRUE), each = 5),
BIOMARKER = rnorm(250, mean = 50, sd = 20),
CLINICAL = rnorm(250, mean = 70, sd = 25)
)
# 探索生物标志物与临床终点的关系
ggplot(biomarker_clinical, aes(x = BIOMARKER, y = CLINICAL)) +
geom_point() +
geom_smooth(method = "lm") +
labs(title = "生物标志物与临床终点的关系",
x = "生物标志物",
y = "临床终点") +
theme_bw()
# 拟合线性模型
lm_fit <- lm(CLINICAL ~ BIOMARKER, data = biomarker_clinical)
summary(lm_fit)
# 使用生物标志物预测临床终点
biomarker_range <- seq(min(biomarker_clinical$BIOMARKER),
max(biomarker_clinical$BIOMARKER),
length.out = 100)
pred_clinical <- predict(lm_fit,
newdata = data.frame(BIOMARKER = biomarker_range),
interval = "confidence")
# 绘制预测结果
ggplot() +
geom_point(data = biomarker_clinical, aes(x = BIOMARKER, y = CLINICAL)) +
geom_line(data = data.frame(BIOMARKER = biomarker_range,
CLINICAL = pred_clinical[, "fit"]),
aes(x = BIOMARKER, y = CLINICAL), color = "blue") +
geom_ribbon(data = data.frame(BIOMARKER = biomarker_range,
lower = pred_clinical[, "lwr"],
upper = pred_clinical[, "upr"]),
aes(x = BIOMARKER, ymin = lower, ymax = upper),
alpha = 0.2, fill = "blue") +
labs(title = "生物标志物预测临床终点",
x = "生物标志物",
y = "临床终点") +
theme_bw()
# 计算ROC曲线(假设临床终点>80为阳性)
library(pROC)
biomarker_clinical$CLINICAL_POS <- biomarker_clinical$CLINICAL > 80
roc_result <- roc(biomarker_clinical$CLINICAL_POS, biomarker_clinical$BIOMARKER)
auc_value <- auc(roc_result)
# 绘制ROC曲线
plot(roc_result, main = paste("ROC曲线 (AUC =", round(auc_value, 3), ")"))
# 确定最佳截断值
coords <- coords(roc_result, "best", ret = c("threshold", "sensitivity", "specificity"))
cat("最佳截断值:", coords["threshold"], "\n")
cat("敏感性:", coords["sensitivity"], "\n")
cat("特异性:", coords["specificity"], "\n")
|
本章介绍了药效学建模的基本原理和实践方法。我们首先学习了如何准备和探索药效学数据,然后介绍了直接效应模型,包括线性模型、Emax模型和Sigmoid Emax模型。接着,我们深入探讨了时间延迟模型,包括效应室模型、间接响应模型、耐受性模型和疾病进展模型。我们还学习了群体药效学建模和PK/PD整合模型的构建方法。最后,我们讨论了模型的实际应用,如剂量-反应关系模拟、特殊人群剂量调整、临床试验设计优化和生物标志物与临床终点关系的探索。
通过本章的学习,读者应该能够使用R语言进行基本的药效学建模和分析,为药物研发和临床实践提供定量支持。药效学建模与药代动力学建模相结合,构成了定量药理学的核心内容,为药物研发决策和临床用药方案优化提供了科学依据。
参考文献#
Mould DR, Upton RN. Basic concepts in population modeling, simulation, and model-based drug development. CPT Pharmacometrics Syst Pharmacol. 2012;1(9):e6. doi:10.1038/psp.2012.4
Sheiner LB, Rosenberg B, Marathe VV. Estimation of population characteristics of pharmacokinetic parameters from routine clinical data. J Pharmacokinet Biopharm. 1977;5(5):445-479. doi:10.1007/BF01061728
Gabrielsson J, Weiner D. Pharmacokinetic and Pharmacodynamic Data Analysis: Concepts and Applications. 5th ed. Swedish Pharmaceutical Press; 2016.
Bonate PL. Pharmacokinetic-Pharmacodynamic Modeling and Simulation. 2nd ed. Springer; 2011.
Rowland M, Tozer TN. Clinical Pharmacokinetics and Pharmacodynamics: Concepts and Applications. 4th ed. Lippincott Williams & Wilkins; 2010.
Mould DR, Upton RN. Basic concepts in population modeling, simulation, and model-based drug development-part 2: introduction to pharmacokinetic modeling methods. CPT Pharmacometrics Syst Pharmacol. 2013;2(4):e38. doi:10.1038/psp.2013.14
Upton RN, Mould DR. Basic concepts in population modeling, simulation, and model-based drug development: part 3-introduction to pharmacodynamic modeling methods. CPT Pharmacometrics Syst Pharmacol. 2014;3(1):e88. doi:10.1038/psp.2013.71
Wickham H, Grolemund G. R for Data Science: Import, Tidy, Transform, Visualize, and Model Data. O’Reilly Media; 2017.
Pinheiro JC, Bates DM. Mixed-Effects Models in S and S-PLUS. Springer; 2000.
Holford N. A time to event tutorial for pharmacometricians. CPT Pharmacometrics Syst Pharmacol. 2013;2(5):e43. doi:10.1038/psp.2013.18
Jusko WJ, Ko HC. Physiologic indirect response models characterize diverse types of pharmacodynamic effects. Clin Pharmacol Ther. 1994;56(4):406-419. doi:10.1038/clpt.1994.155
Karlsson MO, Savic RM. Diagnosing model diagnostics. Clin Pharmacol Ther. 2007;82(1):17-20. doi:10.1038/sj.clpt.6100241
Nguyen TH, Mouksassi MS, Holford N, et al. Model Evaluation of Continuous Data Pharmacometric Models: Metrics and Graphics. CPT Pharmacometrics Syst Pharmacol. 2017;6(2):87-109. doi:10.1002/psp4.12161
Hooker AC, Staatz CE, Karlsson MO. Conditional weighted residuals (CWRES): a model diagnostic for the FOCE method. Pharm Res. 2007;24(12):2187-2197. doi:10.1007/s11095-007-9361-y
Bergstrand M, Hooker AC, Wallin JE, Karlsson MO. Prediction-corrected visual predictive checks for diagnosing nonlinear mixed-effects models. AAPS J. 2011;13(2):143-151. doi:10.1208/s12248-011-9255-z
Wang Y. Derivation of various NONMEM estimation methods. J Pharmacokinet Pharmacodyn. 2007;34(5):575-593. doi:10.1007/s10928-007-9060-6
Savic RM, Karlsson MO. Importance of shrinkage in empirical bayes estimates for diagnostics: problems and solutions. AAPS J. 2009;11(3):558-569. doi:10.1208/s12248-009-9133-0
Jonsson EN, Karlsson MO. Automated covariate model building within NONMEM. Pharm Res. 1998;15(9):1463-1468. doi:10.1023/a:1011970125687
Holford N, Ma SC, Ploeger BA. Clinical trial simulation: a review. Clin Pharmacol Ther. 2010;88(2):166-182. doi:10.1038/clpt.2010.114
Duffull SB, Wright DF, Winter HR. Interpreting population pharmacokinetic-pharmacodynamic analyses - a clinical viewpoint. Br J Clin Pharmacol. 2011;71(6):807-814. doi:10.1111/j.1365-2125.2010.03891.x
Comets E, Brendel K, Mentré F. Computing normalised prediction distribution errors to evaluate nonlinear mixed-effect models: the npde add-on package for R. Comput Methods Programs Biomed. 2008;90(2):154-166. doi:10.1016/j.cmpb.2007.12.002
Byon W, Smith MK, Chan P, et al. Establishing best practices and guidance in population modeling: an experience with an internal population pharmacokinetic analysis guidance. CPT Pharmacometrics Syst Pharmacol. 2013;2(7):e51. doi:10.1038/psp.2013.26
Elmokadem A, Riggs MM, Baron KT. Quantitative Systems Pharmacology and Physiologically-Based Pharmacokinetic Modeling With mrgsolve: A Hands-On Tutorial. CPT Pharmacometrics Syst Pharmacol. 2019;8(12):883-893. doi:10.1002/psp4.12467
Wang W, Hallow KM, James DA. A Tutorial on RxODE: Simulating Differential Equation Pharmacometric Models in R. CPT Pharmacometrics Syst Pharmacol. 2016;5(1):3-10. doi:10.1002/psp4.12052
Fidler M, Wilkins JJ, Hooijmaijers R, et al. Nonlinear Mixed-Effects Model Development and Simulation Using nlmixr and Related R Open-Source Packages. CPT Pharmacometrics Syst Pharmacol. 2019;8(9):621-633. doi:10.1002/psp4.12445
Acharya C, Hooker AC, Türkyılmaz GY, Jönsson S, Karlsson MO. A diagnostic tool for population models using non-compartmental analysis: The ncappc package for R. Comput Methods Programs Biomed. 2016;127:83-93. doi:10.1016/j.cmpb.2016.01.013
Denney WS, Duvvuri S, Buckeridge C. Simple, Automatic Noncompartmental Analysis: The PKNCA R Package. J Pharmacokinet Pharmacodyn. 2015;42(1):11-107. doi:10.1007/s10928-015-9402-8
Lavielle M. Mixed Effects Models for the Population Approach: Models, Tasks, Methods and Tools. Chapman and Hall/CRC; 2014.
Ette EI, Williams PJ. Pharmacometrics: The Science of Quantitative Pharmacology. Wiley-Interscience; 2007.
Minto C, Schnider T. Expanding clinical applications of population pharmacodynamic modelling. Br J Clin Pharmacol. 1998;46(4):321-333. doi:10.1046/j.1365-2125.1998.00790.x
感谢您的关注!来选个表情,或者留个评论吧!