The V Lab
适用对象医学、心理学、公共卫生及循证研究学习者
学习时长约 180–240 分钟
先修要求效应量、置信区间、回归与基础 R

关于案例与软件 本教程的医学和心理学研究均为模拟的研究级汇总数据,不对应真实论文、患者或参与者。本页用 base R 展开核心计算,以便看清模型;正式综述应使用经过验证的专业软件,锁定版本与设置,并由另一分析者复核。

如何使用本教程

本教程沿着真实证据综合的顺序展开:

可回答的问题 → 预注册方案 → 系统检索与筛选 → 偏倚风险 → 可比效应量 → 合成模型 → 异质性 → 稳健性与缺失证据 → 确定性与报告

代码展示的是统计合成部分;它不能代替系统检索、双人筛选、数据核对和偏倚评估。建议先通读概念,再分别完成医学和心理学案例,最后使用检查清单设计自己的分析。

学习目标

完成本教程后,你应能够:

  • 区分系统综述、Meta 分析和叙述性综述;
  • 用 PICO/PICOS 和目标估计量定义可合成的问题;
  • 为二分类结局选择 RR、OR 或 RD,为连续结局选择 MD 或 Hedges’ gg;
  • 解释通用逆方差加权、共同效应模型与随机效应模型;
  • 计算并解释 QQ、I2I^2、τ2\tau^2、平均效应 CI 和预测区间;
  • 区分 DL、REML、Paule–Mandel 与 modified Knapp–Hartung 各自的作用;
  • 构建并阅读森林图与漏斗图;
  • 完成 leave-one-out、效应尺度和模型设定敏感性分析;
  • 审慎使用亚组分析和 Meta 回归;
  • 识别多结局、多时点、多臂和共享对照造成的依赖效应;
  • 讨论发表偏倚、小研究效应、证据确定性和 PRISMA 报告要求;
  • 为医学和心理学 Meta 分析写出不过度概括的结果段落。

1 Meta 分析在完整系统综述中的位置

1.1 三个概念不能互换

概念 核心任务 是否一定统计合成
系统综述 按预设、透明、可复核的方法检索、筛选、评价并综合证据 否
Meta 分析 在可辩护的共同问题和统计模型下定量合并研究结果 是
叙述性综述 以文字组织文献,方法透明度可有很大差异 否

一个 Meta 分析可以计算正确却回答错误的问题。例如,把不同疾病、不同干预版本、不同随访期或不同构念的量表合并,精确的平均数也可能没有清晰含义。反之,当临床或方法差异使合并不合理时,高质量系统综述可以不做 Meta 分析。

垃圾进,精确垃圾出 Meta 分析不会把有系统偏倚的研究“平均成无偏真相”。若偏倚方向相似,增加研究数可能让错误结论更精确。研究质量、可比性和缺失证据必须进入解释,而不是只在讨论最后列一句局限。

1.2 先定义每一次合成的 PICO 与 estimand

每一个 forest plot 背后都应有一个明确的 synthesis question:

  • P(Population):哪些患者或参与者、何种严重程度与场景?
  • I(Intervention/Exposure):干预成分、剂量、实施者和持续时间?
  • C(Comparator):安慰剂、常规照护、等待名单还是主动对照?
  • O(Outcome):定义、量表、方向和测量时间?
  • S(Study design):随机试验、队列、病例对照或其他设计?
  • Estimand:ITT 还是符合方案;末次值还是变化值;RR、MD 或其他尺度?

医学示例的目标是:在 12 项模拟平行随机试验代表的一组可交换场景中,新预防方案相对标准管理对 30 天感染风险的平均 RR。心理学示例的目标是:在 14 项模拟 CBT 试验中,治疗结束时抑郁症状的平均 Hedges’ gg;所有量表先统一为“分数越高症状越重”,所以负值有利于 CBT。

1.3 协议、检索、筛选和重复报告

在读取研究结果前,方案至少应固定:数据库和灰色文献来源、完整检索式、检索日期、语言和出版状态限制、双人筛选流程、冲突解决方式、主要结局与时间点、效应尺度、合成模型、零事件和缺失 SD 处理、亚组、敏感性分析及偏倚风险工具。

同一研究可能有注册记录、会议摘要、主要论文和多篇二次分析。Meta 分析的单位通常是研究或独立比较,不是 PDF 篇数;重复纳入同一参与者会人为提高精度。多篇报告应先链接为同一研究,再按预设规则抽取。

PRISMA 2020 是系统综述报告指南,不等于预注册。协议可根据主题注册于 PROSPERO、OSF 或其他适用平台;观察性流行病学 Meta 分析还可参考 MOOSE。

2 从原始汇总数据得到可比效应量

2.1 二分类结局:RR、OR 与 RD

令治疗组事件/非事件为 a,ba,b,对照组为 c,dc,d。风险比在对数尺度上计算:

yi=log⁡(RRi)=log⁡{a/(a+b)c/(c+d)},vi=1a−1a+b+1c−1c+d. y_i=\log(RR_i)=\log\left\{\frac{a/(a+b)}{c/(c+d)}\right\},\qquad v_i=\frac1a-\frac1{a+b}+\frac1c-\frac1{c+d}.

优势比为 OR=ad/(bc)OR=ad/(bc),风险差为 RD=a/(a+b)−c/(c+d)RD=a/(a+b)-c/(c+d)。三者回答不同问题:

尺度 零效应值 优点 限制
RR 1 队列与试验中较直观;常较稳定 仍需基线风险才能理解绝对影响
OR 1 病例对照研究可估;逻辑模型自然输出 结局常见时不能称为 RR
RD 0 直接表达绝对风险变化 常随基线风险明显变化,跨研究异质性可能大

分析前必须统一事件方向。“感染”与“无感染”互换会把 RR 变成另一个非简单倒数的量;不能等看到哪个方向显著后再选择结局编码。

2.2 零事件不是统一加 0.5 就结束

单臂零事件使普通 log RR 或 log OR 无定义;两臂都零事件对这些相对尺度不提供直接信息。固定向四格加 0.5 可能在小样本、不平衡分配和罕见事件时引入偏差。应预设并比较适合问题的方法,如 Mantel–Haenszel、广义线性混合模型、beta-binomial 或其他罕见事件方法。

本教程函数不会静默修正:只要四格中任一格为零,就要求预设处理;只有明确设置 correction = TRUE 才对该研究四格加连续性校正,并标记双零事件研究。

zero_demo <- data.frame(
  study = c("单臂零事件", "双臂零事件"),
  event_t = c(0, 0), total_t = c(50, 50),
  event_c = c(3, 0), total_c = c(50, 60)
)
zero_effect <- effect_log_rr(
  zero_demo$event_t, zero_demo$total_t,
  zero_demo$event_c, zero_demo$total_c,
  correction = TRUE
)
knitr::kable(
  cbind(zero_demo, zero_effect),
  digits = 3,
  caption = "显式 0.5 校正的教学示例;双零研究的 log RR 保留为缺失"
)
显式 0.5 校正的教学示例;双零研究的 log RR 保留为缺失
study event_t total_t event_c total_c yi vi se corrected double_zero
单臂零事件 0 50 3 50 -1.95 2.25 1.5 TRUE FALSE
双臂零事件 0 50 0 60 NA NA NA TRUE TRUE

2.3 连续结局:MD 与标准化均值差

当研究使用同一量表和单位时,均值差最容易解释:

MDi=X‾Ti−X‾Ci,vi=sTi2nTi+sCi2nCi. MD_i=\bar X_{Ti}-\bar X_{Ci},\qquad v_i=\frac{s_{Ti}^2}{n_{Ti}}+\frac{s_{Ci}^2}{n_{Ci}}.

不同量表测量同一构念时,可用合并组内 SD 标准化:

sp=(nT−1)sT2+(nC−1)sC2nT+nC−2,d=X‾T−X‾Csp,g=J(df)d. s_p=\sqrt{\frac{(n_T-1)s_T^2+(n_C-1)s_C^2}{n_T+n_C-2}},\quad d=\frac{\bar X_T-\bar X_C}{s_p},\quad g=J(df)d.

J(df)J(df) 对小样本 Cohen’s dd 偏倚作校正。本教程使用一种常见的大样本方差近似;专业软件可能提供不同方差选项,方案中必须记录。

SMD 不是“万能临床单位”。它会受到研究内个体异质性、量表信度、纳入标准和 SD 计算方式影响。只有当量表确实测量相同构念时才应合并;不能仅因为都叫“心理健康评分”就放在一起。

心理学数据的方向审核 抽取表必须记录每个量表的高分含义和是否反向。若一项量表高分代表改善、另一项高分代表症状加重,应在合成前翻转其中一个效应方向。推荐在方案中规定“负值有利于干预”或相反方向,并由第二位分析者核对。

3 通用逆方差模型

3.1 每项研究贡献效应和方差

许多 Meta 分析可统一写成:每项研究提供效应估计 yiy_i 及已知或估计的抽样方差 viv_i。共同效应模型的权重为 wi=1/viw_i=1/v_i:

μ̂=∑iwiyi∑iwi,SE(μ̂)=1∑iwi. \hat\mu=\frac{\sum_i w_i y_i}{\sum_i w_i},\qquad SE(\hat\mu)=\sqrt{\frac1{\sum_i w_i}}.

权重反映精度,不是研究质量分数。偏倚风险高的大型研究仍可能得到很大逆方差权重,因此偏倚风险不能通过简单乘一个主观“质量权重”解决。

3.2 共同效应与随机效应回答不同问题

模型 工作假设 汇总量的含义
共同效应(传统 fixed-effect) 所有研究估计同一个真实效应,差异来自抽样误差 该共同效应
随机效应 研究真实效应来自一个分布,观察差异来自真实变异与抽样误差 该分布的平均效应

随机效应权重为 wi*=1/(vi+τ2)w_i^*=1/(v_i+\tau^2),其中 τ2\tau^2 是研究间真实效应方差。随机效应并没有“解决”异质性;它用一个分布模型描述未解释的变异。选择模型应依据问题与预期差异,而不是先做 QQ 检验再自动切换。

随机效应并非天然更保守 存在异质性时,随机效应相对提高小研究权重。若小研究因选择性发表或方法问题给出更大效应,随机效应平均值甚至可能离无效值更远。共同效应和随机效应都依赖研究可比性与偏倚假设。

3.3 QQ、I2I^2、H2H^2 与 τ2\tau^2

  • Cochran QQ:观察到的加权差异与仅有抽样误差是否相容;少量研究时检出力低,很多研究时对微小差异敏感。
  • I2I^2:max⁡{0,(Q−df)/Q}×100%\max\{0,(Q-df)/Q\}\times100\%,描述观察不一致中可归于研究间变异的相对比例,而非“有异质性的研究百分比”。
  • H2H^2:这里使用传统的 Q/dfQ/df;1 表示观察不一致与自由度相当,抽样中也可能小于 1。不同软件还可能报告与 τ2\tau^2 一致的其他定义,必须核对实现。
  • τ2\tau^2:模型所估计的真实效应方差;其单位是效应尺度的平方,RR/OR 时位于 log 尺度。

I2I^2 会受研究精度影响:同样的 τ2\tau^2 在更精确研究中可能产生更高 I2I^2。应同时报告 τ2\tau^2、预测区间、研究情境和 effect scale,而不是用固定的 25%/50%/75% 标签替代判断。

3.4 DL、REML 和 Paule–Mandel

  • DerSimonian–Laird(DL):矩估计,计算简单;研究少或异质性大时可能低估不确定性。
  • REML:通过限制似然估计 τ2\tau^2,通常有较好的统计性质,是常用默认之一。
  • Paule–Mandel(PM):令随机效应加权残差 QQ 接近自由度的矩方法,也常表现稳健。

τ2\tau^2 估计器与平均效应 CI 方法是两个不同选择。HKSJ/Knapp–Hartung 调整平均效应的不确定性,并不估计 τ2\tau^2。

3.5 modified Knapp–Hartung 与预测区间

本教程随机效应平均值使用 modified Knapp–Hartung(mKH):以 t 分布替代正态临界值,并把残差尺度因子限制为至少 1,避免 KH 方差估计小于未调整的模型方差。mKH 可能较保守,尤其研究很少时;方案应说明具体实现。

平均效应 CI 回答平均值位于何处。预测区间尝试描述一项与纳入研究可交换的新研究中真实效应可能位于何处:

μ̂±tk−2,0.975τ̂2+Var̂(μ̂). \hat\mu\ \pm\ t_{k-2,0.975}\sqrt{\hat\tau^2+\widehat{Var}(\hat\mu)}.

本教程公式中的 Var̂(μ̂)\widehat{Var}(\hat\mu) 使用 mKH 调整后的均值方差。这是 Riley/HTS 类常用近似之一,不是唯一标准。研究很少、效应分布非正态或漏斗图不对称时,预测区间可能不稳定;它也不是未来研究“观察到的估计值”区间。

4 医学案例:12 项二分类结局随机试验

4.1 问题、数据结构与效应方向

模拟问题是:与标准管理相比,新预防方案是否降低 30 天感染风险?每一行是一项独立平行 RCT,事件均定义为感染,因此 RR<1RR<1 有利于新方案。

stopifnot(
  !anyDuplicated(medical_data$study),
  all(medical_data$event_t <= medical_data$total_t),
  all(medical_data$event_c <= medical_data$total_c),
  all(medical_data$total_t > 0),
  all(medical_data$total_c > 0)
)

medical_display <- within(medical_data, {
  risk_t <- event_t / total_t
  risk_c <- event_c / total_c
})

knitr::kable(
  medical_display[c("study", "year", "event_t", "total_t", "event_c", "total_c",
                    "risk_t", "risk_c")],
  digits = 3,
  col.names = c("研究", "年份", "新方案事件", "新方案总数",
                "标准管理事件", "标准管理总数", "新方案风险", "标准管理风险"),
  caption = "模拟医学试验的 30 天感染数据"
)
模拟医学试验的 30 天感染数据
研究 年份 新方案事件 新方案总数 标准管理事件 标准管理总数 新方案风险 标准管理风险
Med-01 2012 12 120 20 118 0.100 0.169
Med-02 2013 14 90 15 92 0.156 0.163
Med-03 2014 10 180 30 175 0.056 0.171
Med-04 2015 31 240 29 238 0.129 0.122
Med-05 2016 20 150 25 148 0.133 0.169
Med-06 2017 27 320 43 315 0.084 0.137
Med-07 2018 9 110 16 112 0.082 0.143
Med-08 2019 29 210 24 205 0.138 0.117
Med-09 2020 31 400 48 395 0.078 0.122
Med-10 2021 11 170 25 168 0.065 0.149
Med-11 2022 20 130 19 132 0.154 0.144
Med-12 2024 28 260 40 255 0.108 0.157

这些只是教学数据。真实抽取还应记录随机化单位、结局定义、失访、ITT 分母、聚类或多臂结构、调整估计、偏倚风险和资金来源。

4.2 计算每项研究的 log RR

medical_es <- effect_log_rr(
  medical_data$event_t, medical_data$total_t,
  medical_data$event_c, medical_data$total_c
)
medical_meta <- cbind(medical_data, medical_es)
medical_meta$rr <- exp(medical_meta$yi)
medical_meta$rr_lower <- exp(medical_meta$yi - qnorm(0.975) * medical_meta$se)
medical_meta$rr_upper <- exp(medical_meta$yi + qnorm(0.975) * medical_meta$se)

knitr::kable(
  medical_meta[c("study", "rr", "rr_lower", "rr_upper", "se")],
  digits = 3,
  col.names = c("研究", "RR", "95% CI 下限", "95% CI 上限", "log RR 的 SE"),
  caption = "各项医学试验的风险比"
)
各项医学试验的风险比
研究 RR 95% CI 下限 95% CI 上限 log RR 的 SE
Med-01 0.590 0.302 1.152 0.341
Med-02 0.954 0.489 1.861 0.341
Med-03 0.324 0.163 0.643 0.349
Med-04 1.060 0.660 1.702 0.242
Med-05 0.789 0.459 1.358 0.277
Med-06 0.618 0.392 0.975 0.232
Med-07 0.573 0.264 1.241 0.394
Med-08 1.180 0.712 1.955 0.258
Med-09 0.638 0.415 0.980 0.219
Med-10 0.435 0.221 0.855 0.345
Med-11 1.069 0.599 1.908 0.296
Med-12 0.687 0.437 1.078 0.230

每项区间表达该研究的抽样不确定性。小研究区间通常更宽,但较大样本不保证偏倚更小。

4.3 共同效应与随机效应结果

medical_common <- fit_meta(medical_meta$yi, medical_meta$vi, method = "common")
medical_dl <- fit_meta(medical_meta$yi, medical_meta$vi, method = "DL")
medical_pm <- fit_meta(medical_meta$yi, medical_meta$vi, method = "PM")
medical_reml <- fit_meta(medical_meta$yi, medical_meta$vi, method = "REML")

fit_row_ratio <- function(fit, label) {
  data.frame(
    模型 = label,
    RR = exp(fit$estimate),
    CI下限 = exp(fit$lower),
    CI上限 = exp(fit$upper),
    PI下限 = if (is.finite(fit$pred_lower)) exp(fit$pred_lower) else NA_real_,
    PI上限 = if (is.finite(fit$pred_upper)) exp(fit$pred_upper) else NA_real_,
    tau平方 = fit$tau2,
    check.names = FALSE
  )
}

medical_model_table <- rbind(
  fit_row_ratio(medical_common, "共同效应 + Wald"),
  fit_row_ratio(medical_dl, "随机效应 DL + mKH"),
  fit_row_ratio(medical_pm, "随机效应 PM + mKH"),
  fit_row_ratio(medical_reml, "随机效应 REML + mKH")
)

knitr::kable(
  medical_model_table,
  digits = 3,
  caption = "医学案例在不同模型与研究间方差估计器下的汇总"
)
医学案例在不同模型与研究间方差估计器下的汇总
模型 RR CI下限 CI上限 PI下限 PI上限 tau平方
共同效应 + Wald 0.729 0.623 0.854 NA NA 0.000
随机效应 DL + mKH 0.720 0.571 0.909 0.421 1.23 0.047
随机效应 PM + mKH 0.720 0.570 0.909 0.409 1.27 0.053
随机效应 REML + mKH 0.721 0.572 0.910 0.429 1.21 0.043

REML 随机效应平均 RR 约为 0.72,mKH 95% CI 为 0.57 至 0.91。这表示在模型所代表的可交换场景中,平均相对风险较低;它不是“每个医院都会降低相同比例”的承诺。

4.4 异质性与预测区间

medical_heterogeneity <- data.frame(
  指标 = c("Cochran Q", "Q 自由度", "Q 检验 p 值", "I-squared (%)",
           "H-squared", "REML tau-squared", "REML tau"),
  数值 = c(
    medical_reml$Q, medical_reml$Q_df, medical_reml$Q_p,
    medical_reml$I2, medical_reml$H2,
    medical_reml$tau2, sqrt(medical_reml$tau2)
  )
)
knitr::kable(
  medical_heterogeneity,
  digits = 3,
  caption = "医学案例的异质性统计量(tau 位于 log RR 尺度)"
)
医学案例的异质性统计量(tau 位于 log RR 尺度)
指标 数值
Cochran Q 17.595
Q 自由度 11.000
Q 检验 p 值 0.091
I-squared (%) 37.481
H-squared 1.600
REML tau-squared 0.043
REML tau 0.208

I2I^2 约为 37.5%,但不应只贴“中等异质性”标签。更直接的信息是 REML 95% 预测区间:RR 0.43 至 1.21,跨过 1。平均效应与 1 不相容,并不保证相似新场景的真实效应一定有利。

平均 CI 与预测区间并不矛盾:前者量化平均 log RR 的估计精度;后者把研究间真实变异也纳入,回答潜在新场景可能有多不同。

4.5 森林图

forest_meta(
  medical_meta$yi,
  medical_meta$vi,
  labels = paste(medical_meta$study, medical_meta$year),
  fit = medical_reml,
  ratio = TRUE,
  xlab = "风险比 RR(对数间距)",
  pooled_label = "REML 平均 RR",
  prediction_label = "95% 预测区间"
)
十二项医学试验的风险比森林图,包含单项置信区间、随机效应汇总菱形和预测区间。

模拟医学试验在 log 坐标上绘制的 RR 森林图。方块大小反映随机效应权重;菱形为 REML 平均效应,红线为预测区间。横轴标签显示 RR。

森林图先用于检查方向、精度、离群结果和可见异质性,再读汇总菱形。方块大小不是样本量本身,也不是研究质量评级。

4.6 从相对效应回到绝对尺度

RR 的实际意义取决于基线风险。下面把平均 RR 应用于纳入试验对照组风险的中位数,只作为一种场景转换:

reference_risk <- median(medical_meta$event_c / medical_meta$total_c)
pooled_rr <- exp(medical_reml$estimate)
treated_risk <- reference_risk * pooled_rr
illustrative_rd <- treated_risk - reference_risk

absolute_translation <- data.frame(
  对照参考风险 = reference_risk,
  应用平均RR后的风险 = treated_risk,
  每1000人的风险差 = 1000 * illustrative_rd,
  check.names = FALSE
)
knitr::kable(
  absolute_translation,
  digits = 3,
  caption = "把平均 RR 转换到一个教学性参考风险"
)
把平均 RR 转换到一个教学性参考风险
对照参考风险 应用平均RR后的风险 每1000人的风险差
0.146 0.106 -40.8

这不是直接合并 RD,也没有传播参考风险、RR 和异质性的全部不确定性。正式决策应使用目标人群的可信基线风险,并展示多个合理场景。

4.7 模型与 leave-one-out 敏感性分析

DL、PM 和 REML 的差异提醒我们:研究数有限时,τ2\tau^2 不是已知常数。还应逐项排除研究并重新估计 τ2\tau^2:

medical_loo <- leave_one_out(
  medical_meta$yi, medical_meta$vi,
  labels = medical_meta$study,
  method = "REML"
)
medical_loo$rr <- exp(medical_loo$estimate)
medical_loo$rr_lower <- exp(medical_loo$lower)
medical_loo$rr_upper <- exp(medical_loo$upper)

knitr::kable(
  medical_loo[c("omitted", "rr", "rr_lower", "rr_upper", "tau2", "I2")],
  digits = 3,
  col.names = c("排除研究", "平均 RR", "CI 下限", "CI 上限", "tau-squared", "I-squared (%)"),
  caption = "医学案例的 leave-one-out REML 分析"
)
医学案例的 leave-one-out REML 分析
排除研究 平均 RR CI 下限 CI 上限 tau-squared I-squared (%)
Med-01 0.730 0.567 0.941 0.051 41.8
Med-02 0.706 0.550 0.907 0.050 41.0
Med-03 0.763 0.623 0.934 0.014 16.0
Med-04 0.691 0.544 0.879 0.034 32.9
Med-05 0.713 0.550 0.923 0.058 42.9
Med-06 0.732 0.565 0.949 0.055 41.2
Med-07 0.730 0.567 0.938 0.049 41.9
Med-08 0.688 0.548 0.864 0.022 27.3
Med-09 0.730 0.562 0.948 0.058 41.7
Med-10 0.747 0.591 0.945 0.035 34.3
Med-11 0.697 0.547 0.889 0.042 36.7
Med-12 0.723 0.556 0.939 0.061 42.9

影响性分析是诊断工具,不是删研究算法。若某研究改变结论,应核查人群、设计、数据和偏倚风险,并报告含与不含它的结果;仅因它“让结果不显著”而删除属于结果驱动分析。

5 心理学案例:不同抑郁量表的 14 项 CBT 试验

5.1 为什么使用 Hedges’ gg

模拟研究使用 PHQ-9、BDI-II、HADS-D 和 CES-D。它们的单位和范围不同,因此全部 14 项研究不能用原始 MD 合并。我们假设这些量表在此问题中足够接近地测量同一抑郁症状构念,并已统一为高分更差;负 gg 有利于 CBT。

stopifnot(
  !anyDuplicated(psychology_data$study),
  all(psychology_data$n_t > 1), all(psychology_data$n_c > 1),
  all(psychology_data$sd_t > 0), all(psychology_data$sd_c > 0)
)

knitr::kable(
  psychology_data,
  digits = 2,
  col.names = c("研究", "量表", "CBT n", "CBT 均值", "CBT SD",
                "对照 n", "对照均值", "对照 SD", "治疗节数", "形式"),
  caption = "模拟心理学试验的治疗结束时抑郁量表数据"
)
模拟心理学试验的治疗结束时抑郁量表数据
研究 量表 CBT n CBT 均值 CBT SD 对照 n 对照均值 对照 SD 治疗节数 形式
Psy-01 PHQ-9 70 11.5 5.1 68 14.5 5.0 10 Individual
Psy-02 BDI-II 55 25.4 8.2 57 27.0 8.0 6 Group
Psy-03 HADS-D 90 10.4 4.0 88 12.0 4.2 8 Individual
Psy-04 CES-D 120 25.5 9.5 118 25.0 9.2 4 Group
Psy-05 PHQ-9 48 11.0 4.8 50 15.0 5.1 8 Individual
Psy-06 BDI-II 75 23.7 7.7 74 26.0 7.9 10 Group
Psy-07 HADS-D 130 9.5 3.8 128 11.5 4.0 6 Individual
Psy-08 CES-D 62 27.0 10.2 65 28.0 9.8 4 Group
Psy-09 PHQ-9 85 10.4 5.3 82 14.0 5.0 12 Individual
Psy-10 BDI-II 110 22.5 8.0 108 24.5 8.3 6 Group
Psy-11 HADS-D 58 10.7 4.1 60 12.5 4.0 8 Individual
Psy-12 CES-D 140 27.9 9.4 136 27.0 9.6 10 Group
Psy-13 PHQ-9 95 12.7 4.9 92 15.5 5.2 10 Individual
Psy-14 BDI-II 72 22.7 7.9 70 25.5 8.1 8 Group

真实综述还必须确认诊断标准、对照类型、治疗师训练、盲法可行性、依从性、量表版本和随访时点。等待名单与主动心理对照通常不能无条件视为同一 comparator。

5.2 计算 Hedges’ gg 并合成

psych_es <- effect_hedges_g(
  psychology_data$n_t, psychology_data$mean_t, psychology_data$sd_t,
  psychology_data$n_c, psychology_data$mean_c, psychology_data$sd_c
)
psych_meta <- cbind(psychology_data, psych_es)
psych_meta$g_lower <- psych_meta$yi - qnorm(0.975) * psych_meta$se
psych_meta$g_upper <- psych_meta$yi + qnorm(0.975) * psych_meta$se

psych_reml <- fit_meta(psych_meta$yi, psych_meta$vi, method = "REML")
psych_common <- fit_meta(psych_meta$yi, psych_meta$vi, method = "common")

knitr::kable(
  psych_meta[c("study", "scale", "yi", "g_lower", "g_upper")],
  digits = 3,
  col.names = c("研究", "量表", "Hedges g", "95% CI 下限", "95% CI 上限"),
  caption = "每项心理学试验的标准化均值差"
)
每项心理学试验的标准化均值差
研究 量表 Hedges g 95% CI 下限 95% CI 上限
Psy-01 PHQ-9 -0.591 -0.932 -0.250
Psy-02 BDI-II -0.196 -0.568 0.175
Psy-03 HADS-D -0.389 -0.685 -0.092
Psy-04 CES-D 0.053 -0.201 0.307
Psy-05 PHQ-9 -0.801 -1.212 -0.389
Psy-06 BDI-II -0.293 -0.616 0.029
Psy-07 HADS-D -0.511 -0.759 -0.263
Psy-08 CES-D -0.099 -0.448 0.249
Psy-09 PHQ-9 -0.695 -1.008 -0.383
Psy-10 BDI-II -0.245 -0.511 0.022
Psy-11 HADS-D -0.442 -0.807 -0.076
Psy-12 CES-D 0.094 -0.142 0.331
Psy-13 PHQ-9 -0.552 -0.844 -0.260
Psy-14 BDI-II -0.348 -0.680 -0.017
psych_results <- rbind(
  data.frame(
    模型 = "共同效应 + Wald", g = psych_common$estimate,
    CI下限 = psych_common$lower, CI上限 = psych_common$upper,
    PI下限 = NA, PI上限 = NA, tau平方 = 0
  ),
  data.frame(
    模型 = "随机效应 REML + mKH", g = psych_reml$estimate,
    CI下限 = psych_reml$lower, CI上限 = psych_reml$upper,
    PI下限 = psych_reml$pred_lower, PI上限 = psych_reml$pred_upper,
    tau平方 = psych_reml$tau2
  )
)

knitr::kable(
  psych_results,
  digits = 3,
  caption = "心理学案例的共同效应与随机效应结果"
)
心理学案例的共同效应与随机效应结果
模型 g CI下限 CI上限 PI下限 PI上限 tau平方
共同效应 + Wald -0.317 -0.398 -0.236 NA NA 0.000
随机效应 REML + mKH -0.345 -0.501 -0.188 -0.848 0.158 0.048

随机效应平均 gg 为 -0.34(mKH 95% CI -0.50 至 -0.19)。负方向平均有利于 CBT,但这不是 PHQ-9 分数下降多少分,也不应仅按 0.2/0.5/0.8 的固定经验阈值决定临床意义。

5.3 心理学异质性和预测区间

psych_heterogeneity <- data.frame(
  Q = psych_reml$Q,
  Q_df = psych_reml$Q_df,
  Q_p = psych_reml$Q_p,
  I2_percent = psych_reml$I2,
  tau2 = psych_reml$tau2,
  tau = sqrt(psych_reml$tau2),
  prediction_lower = psych_reml$pred_lower,
  prediction_upper = psych_reml$pred_upper,
  check.names = FALSE
)
knitr::kable(
  psych_heterogeneity,
  digits = 3,
  col.names = c("Q", "df", "Q p 值", "I-squared (%)", "tau-squared",
                "tau", "PI 下限", "PI 上限"),
  caption = "心理学案例的异质性与预测区间"
)
心理学案例的异质性与预测区间
Q df Q p 值 I-squared (%) tau-squared tau PI 下限 PI 上限
41 13 0 68.3 0.048 0.219 -0.848 0.158

预测区间约为 -0.85 至 0.16,跨过 0。即使平均效应的 CI 未跨 0,某些相似场景的真实效应仍可能接近无效或方向不同。可能原因包括对照强度、治疗形式、样本严重程度、量表、治疗师和偏倚风险,但本数据不能自动识别原因。

forest_meta(
  psych_meta$yi,
  psych_meta$vi,
  labels = paste(psych_meta$study, psych_meta$scale),
  fit = psych_reml,
  ratio = FALSE,
  xlab = "Hedges' g(负值有利于 CBT)",
  pooled_label = "REML 平均 g",
  prediction_label = "95% 预测区间"
)
十四项心理学试验的标准化均值差森林图,包含单项置信区间、汇总效应和跨过零的预测区间。

模拟心理学 CBT 试验的 Hedges’ g 森林图。负值有利于 CBT;菱形为 REML 平均效应,红线为预测区间。

5.4 同一量表时优先保留原始单位

四项 PHQ-9 研究可以用 MD 合成,因为量表和方向一致:

phq <- subset(psychology_data, scale == "PHQ-9")
phq_es <- effect_md(phq$n_t, phq$mean_t, phq$sd_t,
                    phq$n_c, phq$mean_c, phq$sd_c)
phq_fit <- fit_meta(phq_es$yi, phq_es$vi, method = "REML")

data.frame(
  研究数 = phq_fit$k,
  平均MD = phq_fit$estimate,
  CI下限 = phq_fit$lower,
  CI上限 = phq_fit$upper,
  tau平方 = phq_fit$tau2,
  check.names = FALSE
) |>
  knitr::kable(
    digits = 3,
    caption = "仅 PHQ-9 研究的随机效应均值差(CBT − 对照,单位为 PHQ-9 分)"
  )
仅 PHQ-9 研究的随机效应均值差(CBT − 对照,单位为 PHQ-9 分)
研究数 平均MD CI下限 CI上限 tau平方
4 -3.27 -4.6 -1.95 0

MD 更接近临床解释,但这里只代表 PHQ-9 子集。不能把它与全部量表的 gg 当成同一 estimand;也不应把治疗后分数 SMD 与变化分数 SMD 随意混合,除非预设的方法和相关性假设支持。

6 探索异质性:亚组与 Meta 回归

6.1 亚组差异必须直接检验

下面比较个体 CBT 与团体 CBT。先分别汇总只是描述;亚组差异应通过包含组别指示变量的 Meta 回归直接检验,而不是比较“一组显著、另一组不显著”。

format_levels <- levels(psych_meta$format)
psych_subgroup <- do.call(rbind, lapply(format_levels, function(level) {
  take <- psych_meta$format == level
  fit <- fit_meta(psych_meta$yi[take], psych_meta$vi[take], method = "REML")
  data.frame(
    形式 = level, 研究数 = sum(take), 平均g = fit$estimate,
    CI下限 = fit$lower, CI上限 = fit$upper, tau平方 = fit$tau2
  )
}))

format_dummy <- as.numeric(psych_meta$format == "Individual")
X_format <- cbind(`(Intercept)` = 1, Individual_vs_Group = format_dummy)
format_model <- fit_meta(
  psych_meta$yi, psych_meta$vi,
  method = "REML", X = X_format
)

knitr::kable(psych_subgroup, digits = 3, caption = "按 CBT 形式分层的描述性合成")
按 CBT 形式分层的描述性合成
形式 研究数 平均g CI下限 CI上限 tau平方
Group 7 -0.126 -0.301 0.049 0.013
Individual 7 -0.551 -0.698 -0.403 0.000
knitr::kable(
  format_model$coefficients,
  digits = 3,
  caption = "以 Group 为参照的随机效应 Meta 回归"
)
以 Group 为参照的随机效应 Meta 回归
term estimate se lower upper statistic p
(Intercept) -0.118 0.062 -0.252 0.016 -1.92 0.079
Individual_vs_Group -0.435 0.089 -0.630 -0.240 -4.86 0.000

这里 Individual_vs_Group 系数及其 p 值就是两个亚组平均效应差异的直接检验。若 moderator 有三个或更多水平,应使用全部虚拟变量的 omnibus F/Wald 检验,而不能挑一个系数。该研究层比较即使很精确,也可能被人群、对照强度、治疗节数或偏倚风险混杂,不能解释为把同一患者从团体 CBT 改为个体 CBT 的因果效应。

6.2 连续 moderator:治疗节数

sessions_centered <- psych_meta$sessions - mean(psych_meta$sessions)
X_sessions <- cbind(`(Intercept)` = 1, sessions_centered = sessions_centered)
sessions_model <- fit_meta(
  psych_meta$yi, psych_meta$vi,
  method = "REML", X = X_sessions
)

knitr::kable(
  sessions_model$coefficients,
  digits = 3,
  caption = "治疗节数的探索性随机效应 Meta 回归"
)
治疗节数的探索性随机效应 Meta 回归
term estimate se lower upper statistic p
(Intercept) -0.344 0.068 -0.493 -0.195 -5.04 0.000
sessions_centered -0.051 0.029 -0.114 0.012 -1.75 0.105

斜率描述研究层面每多一节治疗与平均 gg 的关联,并不是个体剂量反应。14 项研究只支持非常有限的 moderator 探索;“每个系数至少约 10 项研究”至多是警示下限,不是充分保证。多重尝试 moderator 会制造偶然发现。

7 小研究效应与缺失证据

7.1 漏斗图能提示什么

漏斗图绘制效应估计与标准误。若只有抽样误差、模型适当且没有大小相关效应,较精确研究通常聚集在顶部,较小研究在底部更分散。

funnel_meta(
  psych_meta$yi,
  psych_meta$vi,
  fit = psych_reml,
  xlab = "Hedges' g"
)
心理学试验效应量对标准误的漏斗图,带有中心线和三角形伪置信界限。

模拟心理学试验的漏斗图。虚线为 REML 平均效应及其 95% 伪界限;不对称不等同于发表偏倚。

漏斗图不对称可能来自发表或选择性报告,也可能来自真实异质性、小研究实施质量、效应尺度与基线风险关系、异常研究或偶然性。对称也不能证明没有缺失结果。

7.2 Egger 回归只是一个诊断

psych_egger <- egger_test(psych_meta$yi, psych_meta$vi)
knitr::kable(
  psych_egger,
  digits = 3,
  caption = "心理学案例的 Egger 回归截距检验"
)
心理学案例的 Egger 回归截距检验
intercept se t df p
-5.26 2.69 -1.95 12 0.075

Egger 检验通常不应在少于约 10 项独立研究时被强调;即使研究更多,它也是小研究效应检验,不是“发表偏倚检验”。存在异质性时其解释更复杂。Trim-and-fill 也不是找回真实缺失研究的可靠修复,应至多作为强假设下的敏感性分析。

7.3 缺失证据需要从研究过程评估

更有信息的做法包括:检索注册平台和方案;比较计划与报告结局;联系作者;纳入灰色文献;核对时间点;检查结果是否因显著性而选择;在合理选择机制下做敏感性分析。不能只靠一个漏斗图决定证据是否可信。

8 依赖效应与复杂研究结构

8.1 为什么“效应行数”不等于独立研究数

心理学研究常报告多个量表、多个随访、多个干预组和多个亚组。医学试验可能共享一个对照组。把这些相关效应当成独立研究会重复计算参与者并低估标准误。

结构 相关性来源 合理方向
同一研究多个结局 同一参与者完成多个量表 预设一个主要结局;或多变量/多层 Meta 分析
多个时间点 同一参与者重复测量 预设主要时间点;或显式建模时间内相关性
多臂试验共享对照 对照参与者被用于多个比较 合并相关干预臂、拆分对照或使用多变量方法
聚类随机试验 同一集群内参与者相关 使用已校正的效应/SE,或按 ICC 调整有效样本量
同一队列多篇论文 参与者重复 链接报告,按研究 ID 去重

正式分析可使用多变量或多层 Meta 分析,或按研究聚类并带小样本修正的稳健方差估计。当前项目不安装相应扩展包,因此本页不以错误的独立性近似演示这些复杂模型。

8.2 观察性研究的调整估计

观察性医学研究常报告不同协变量集的 OR、HR 或 RR。合并前应预设优先调整集,并确认每项估计回答近似相同的条件或因果问题。把粗估计和过度调整估计混合,会产生难以解释的平均量;残余混杂不会被 Meta 分析消除。

9 风险偏倚、敏感性分析与证据确定性

9.1 偏倚风险不是总分

随机试验可按随机化过程、偏离干预、缺失结局、结局测量和选择性报告等领域评价;观察性研究还需深入考虑混杂和选择。简单把多个领域相加成“质量分数”会隐藏致命问题,且不适合作为机械逆方差修正。

建议把偏倚判断用于:解释方向与大小;预设排除高风险研究的敏感性分析;比较低风险证据;解释异质性;评价证据确定性。排除规则必须在看汇总结果前确定。

9.2 一套最小敏感性分析矩阵

决策 主分析 合理敏感性分析
合成模型 REML + mKH 共同效应;PM/DL;专业软件的其他稳健方法
效应尺度 医学 RR;心理学 gg RD/OR;同量表 MD;方向核查
零事件 预设罕见事件方法 连续性校正规则、双零研究处理
偏倚风险 全部合格研究 排除预设关键领域高风险研究
影响研究 全部研究 leave-one-out;核查后有依据的情景分析
缺失 SD/相关性 预设推算值 多个合理相关系数或 SD 假设
依赖效应 预设单一结局/时间 多变量、分层或研究聚类稳健方法

敏感性分析应回答结论对哪些可辩护决策敏感,而不是寻找最小 p 值。

9.3 证据确定性

统计精度只是确定性的一部分。还需考虑偏倚风险、不一致性、间接性、不精确性和发表偏倚等领域。大样本、窄 CI 的 Meta 分析若来自间接或高偏倚研究,仍可能低确定性。GRADE 等框架需要领域判断,不能从 I2I^2 或 p 值自动生成。

10 结果报告与可复现工作流

10.1 预注册分析清单

在提取结果前写明:

  • 每次 synthesis 的 PICO/PICOS、目标总体和 estimand;
  • 主要结局、量表方向、时间点和效应尺度;
  • 多篇报告去重、多个量表/时间点/干预臂选择规则;
  • 使用调整还是未调整估计以及调整集优先级;
  • 共同效应或随机效应目标及选择理由;
  • τ2\tau^2 估计器、平均效应 CI 方法和预测区间约定;
  • 零事件、缺失 SD、变化分数、聚类和 crossover 的处理;
  • 亚组、moderator、交互检验和多重性方案;
  • 偏倚风险、敏感性分析、缺失证据和证据确定性方法;
  • 软件、包版本、函数设置、随机种子和独立复核流程。

10.2 医学案例报告模板

纳入 12 项模拟平行随机试验,共 4733 名参与者。以感染为事件,REML 随机效应模型及 modified Knapp–Hartung 推断得到平均 RR 0.72(95% CI 0.57–0.91)。研究间方差 τ2=0.043\tau^2=0.043(log RR 尺度),I2=37.5%I^2=37.5\%;95% 预测区间为 0.43–1.21。平均结果提示相对风险降低,但预测区间跨过 1,故效应不应被假定为在所有相似场景中方向一致。所有数据为模拟结果,未进行真实偏倚风险或证据确定性评估。

10.3 心理学案例报告模板

纳入 14 项模拟 CBT 试验,共 2406 名参与者。统一量表方向后,REML 随机效应模型及 modified Knapp–Hartung 推断得到治疗结束时平均 Hedges’ g=−0.34g=-0.34(95% CI -0.50 至 -0.19;负值有利于 CBT)。τ2=0.048\tau^2=0.048,I2=68.3%I^2=68.3\%,95% 预测区间为 -0.85 至 0.16。平均症状差异有利于 CBT,但研究间差异较大,预测区间包含无效值,且 SMD 不对应单一量表的临床单位。

10.4 PRISMA 与可复现性

报告应使用适用的 PRISMA 2020 checklist 与 flow diagram,并说明每次 synthesis 的纳入研究、模型、效应尺度、τ2\tau^2 估计器、CI 方法、异质性指标、软件命令和敏感性分析。观察性研究综述可同时参考 MOOSE。

保存检索结果、去重记录、筛选决定、排除理由、数据字典、原始抽取、清洗日志、分析数据、脚本和软件环境。最好由第二位分析者从原始抽取表独立复算主要结果。

11 常见错误速查

错误做法 为什么有问题 更合适的做法
“做了 Meta 分析”就称系统综述 统计合成不等于系统方法 报告完整检索、筛选、偏倚和协议
按 QQ 的 p 值选择 fixed 或 random 检验效能依赖研究数且两模型问题不同 依据 estimand 与临床差异预设模型
把 I2=60%I^2=60\% 写成“60% 研究有异质性” I2I^2 不是研究比例 联合解释 τ2\tau^2、PI、尺度与场景
随机效应称为“已控制异质性” 未解释差异仍然存在 探索原因并报告预测区间
把 OR 当 RR 结局常见时差异可明显 按设计选尺度并准确命名
所有零格都自动加 0.5 可能产生偏差且双零信息不同 预设罕见事件方法并做敏感性分析
不同量表直接合并 MD 单位不可比 同一构念时用 SMD,或按量表分开
忘记翻转量表方向 有利与有害效应相互抵消 保存方向字段并双人核查
每个量表和时间点都当独立研究 重复计算参与者,SE 过小 预设选择规则或使用依赖效应模型
一亚组显著、另一亚组不显著就称有差异 显著性差异不是效应差异检验 直接检验 subgroup × effect 交互
Meta 回归斜率解释为个体因果效应 研究层生态谬误与混杂 写成探索性研究层关联
漏斗图不对称就断言发表偏倚 原因不唯一 结合注册、方案、异质性与选择机制
删除让结果变化的研究 结果驱动,破坏目标 核查、透明报告并保留主分析
只报告 pooled p 值 无大小、精度或可迁移性 报告效应、CI、τ2\tau^2、PI 和偏倚

12 练习与答案

12.1 练习 1:该不该合并?

五项研究都报告“焦虑”,但分别研究术前短期紧张、广泛性焦虑障碍和考试焦虑,干预和时间点也不同。能否因为都可转成 SMD 就直接合并?

查看答案 不能。数学上可标准化不代表临床问题可交换。应回到预设 PICO、构念和时间窗判断,必要时分开 synthesis 或不做统计合并,并解释差异。

12.2 练习 2:共同效应还是随机效应?

QQ 检验 p=0.18p=0.18,研究者因此选择共同效应模型。这个理由充分吗?

查看答案 不充分。少量研究时 QQ 检验发现异质性的能力较弱,模型选择也不应由一次检验控制。应先明确是估计共同真实效应,还是一组场景中真实效应分布的平均;同时结合临床和方法差异。

12.3 练习 3:平均 CI 与 PI

随机效应平均 RR 的 95% CI 为 0.70–0.88,而预测区间为 0.50–1.25。如何解释?

查看答案 平均真实效应估计较精确并提示获益,但研究间真实效应存在变异;一项相似新场景的真实 RR 可能跨过 1。不能用平均 CI 断言所有场景都获益。

12.4 练习 4:SMD 的方向

三项抑郁研究中两项量表高分更差,一项量表高分更好。直接计算“干预减对照”的 gg 会发生什么?

查看答案 第三项的效应方向与其他研究相反,合成可能错误抵消。必须在看结果前统一方向,例如全部定义负值为症状改善,并记录翻转规则。

12.5 练习 5:双零事件

一项小型安全性试验两组均无死亡。它对普通 log RR 合成提供什么信息?

查看答案 普通 log RR 无法由该表估计,双零研究不直接告诉我们相对风险,但说明该样本中事件稀少。是否以及如何保留信息取决于效应尺度和罕见事件模型;不能静默加 0.5 后当作常规研究。

12.6 练习 6:亚组显著性

成人研究 pooled p=0.01p=0.01,青少年研究 pooled p=0.20p=0.20。能否说年龄组修改疗效?

查看答案 不能。必须直接检验两组效应差异。即使交互显著,它仍是研究层比较,需考虑预设性、研究数、混杂和多重性。

12.7 练习 7:漏斗图

漏斗图右下角缺少小研究,是否已经证明存在发表偏倚?

查看答案 没有。不对称可能来自选择性发表,也可能来自真实异质性、实施质量、效应尺度、异常研究或偶然。应结合注册和方案、检索未发表研究、结局报告偏倚评估和敏感性分析。

12.8 练习 8:影响研究

排除一项大型研究后结果从不显著变显著。可以把它删掉吗?

查看答案 不能仅凭结果变化删除。应核查资格、数据、设计、偏倚和适用人群;若研究符合预设标准,保留主分析并透明报告敏感性结果。任何排除都需要独立于显著性的理由。

13 快速参考

13.1 关键公式与零效应值

量 计算或含义 零效应值
log RR log⁡[pT/pC]\log[p_T/p_C] 0(RR 为 1)
log OR log⁡[ad/(bc)]\log[ad/(bc)] 0(OR 为 1)
RD pT−pCp_T-p_C 0
MD X‾T−X‾C\bar X_T-\bar X_C 0
Hedges’ gg 小样本校正的标准化均值差 0
共同效应权重 1/vi1/v_i —
随机效应权重 1/(vi+τ2)1/(v_i+\tau^2) —
I2I^2 观察不一致的相对比例指标 0%
τ2\tau^2 模型中的研究间真实效应方差 0

最终检查清单

  • 每个 synthesis 都有清楚的 PICO/PICOS、时间点和 estimand;
  • 检索、筛选、数据抽取、去重和排除理由可复核;
  • 效应方向、单位、调整状态和结局定义已双人核对;
  • 研究而非论文或效应行被视为独立单位;
  • 模型、τ2\tau^2 估计器、CI 方法和 PI 公式已预设并记录;
  • 零事件、缺失 SD、多臂、聚类和重复结局得到合理处理;
  • 同时报告单项结果、平均效应、CI、τ2\tau^2、I2I^2 与预测区间;
  • 亚组和 Meta 回归直接检验差异且不过度作因果解释;
  • 漏斗图或 Egger 结果没有被等同为发表偏倚证明;
  • leave-one-out 和敏感性分析没有变成结果驱动的删除规则;
  • 风险偏倚、间接性、不精确性和缺失证据进入结论;
  • PRISMA 项目、代码、数据、版本与审计轨迹足以支持复现。
sessionInfo()
## R version 4.6.1 (2026-06-24)
## Platform: aarch64-apple-darwin23
## Running under: macOS Tahoe 26.5.1
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.6/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.6/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.1
## 
## locale:
## [1] C.UTF-8/C.UTF-8/C.UTF-8/C/C.UTF-8/C.UTF-8
## 
## time zone: America/Edmonton
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## loaded via a namespace (and not attached):
##  [1] digest_0.6.39   R6_2.6.1        fastmap_1.2.0   xfun_0.60       lattice_0.22-9 
##  [6] cachem_1.1.0    knitr_1.51      htmltools_0.5.9 rmarkdown_2.31  stats4_4.6.1   
## [11] lifecycle_1.0.5 cli_3.6.6       grid_4.6.1      sass_0.4.10     jquerylib_0.1.4
## [16] compiler_4.6.1  tools_4.6.1     nlme_3.1-169    evaluate_1.0.5  bslib_0.12.0   
## [21] yaml_2.3.12     rlang_1.3.0     jsonlite_2.0.0