孟德尔随机化 / TwoSampleMR

孟德尔随机化分析怎么做:从 GWAS 数据到敏感性分析

这页写给用 TwoSampleMR 做两样本 MR 论文的医学研究生。内容按分析顺序排列:三大假设怎么论证、GWAS 数据从哪里拿、工具变量怎么筛、等位基因怎么对齐、主分析和敏感性分析怎么跑和怎么解读、审稿人常问什么。所有命令在本机用公开数据(LDL-C→冠心病)跑过,软件版本与数据库状态于 2026-10-10 核实。

直接答案

两样本孟德尔随机化的标准做法是:从暴露 GWAS 取 P<5×10⁻⁸ 的 SNP,用 r²=0.001、10,000 kb 做 LD clump(不用 OpenGWAS 时用 plink 加 1000 Genomes 参考面板在本地做),用 harmonise_data 对齐效应等位基因并处理回文 SNP,以乘性随机效应 IVW 为主分析,用 MR-Egger、加权中位数、加权众数和 MR-PRESSO 检验多效性,用 Cochran Q、留一法和 Steiger 检验报告异质性与方向,并按 STROBE-MR 写清三大假设的论证。OpenGWAS 自 2024 年 5 月起需要 14 天有效的 JWT 令牌;GWAS Catalog、FinnGen、Pan-UKB 的摘要统计可直接下载,在本地完成全部分析。

全流程

函数与默认值按 TwoSampleMR 0.7.12(2026-10-08 发布)与 ieugwasr 1.2.0 核对。

步骤TwoSampleMR / 工具关键参数(默认值)论文里报告
1 取暴露工具变量extract_instruments(需令牌);离线用 format_datap1 = 5e-8GWAS 来源、样本量、人群、阈值及理由
2 LD clumpclump_data / ieugwasr::ld_clumpclump_r2 = 0.001,clump_kb = 10000,pop = "EUR"参考面板与人群;clump 前后 SNP 数
3 工具强度自算 F 与 R²F = (β/SE)²每个 SNP 的 F、总 R²
4 取结局数据extract_outcome_data(需令牌);离线用 format_dataproxies = TRUE,rsq = 0.8,maf_threshold = 0.3缺失 SNP 数、代理 SNP 数
5 等位基因对齐harmonise_dataaction = 2(回文 SNP 的 EAF 在 0.42–0.58 时剔除)attr(dat, "log") 中交换与剔除的 SNP 数
6 主分析与敏感性mr、mr_heterogeneity、mr_pleiotropy_test、mr_leaveoneout、directionality_test、MRPRESSO::mr_pressoIVW 为乘性随机效应;MR-PRESSO 的 NbDistribution = 1000各方法估计值、OR 与 95% CI;Q、截距、PRESSO 全局检验
7 作图mr_scatter_plot、mr_forest_plot、mr_leaveoneout_plot、mr_funnel_plot—散点图、单 SNP 森林图、留一法图、漏斗图

三大假设

三条假设中只有相关性能直接检验。独立性和排他性只能部分检验,论文里需要结合敏感性分析和生物学知识论证。STROBE-MR 第 5 条要求在方法中明确写出这三条假设。

STROBE-MR(20 项,JAMA 2021 与 BMJ 解释文件)中,审稿人最常对照的是:第 5 条写出三大假设;第 7 条说明评估假设的方法;第 9 条给出软件、包版本与设置,以及是否预注册;第 10d 条对两样本 MR 说明暴露与结局样本的相似性和重叠人数;第 11 条在可解释的尺度上报告结果(例如每 1 SD 的 OR);第 13 条报告敏感性分析与方向性检验。按这些条目逐项写,可以减少大部分“方法描述不完整”的意见。

Burgess 等 2023 年更新的 MR 指南还建议使用阳性对照结局:选择一个因果关系已确定的结局,检验工具变量能否复现。本页实测用 LDL-C→冠心病,它本身就是公认的阳性对照,适合用来检查流程是否正确。

假设含义能做的检验论文里怎么论证
相关性(relevance)工具变量与暴露强相关P<5e-8;单 SNP F 与总 R²;整体 F报告 R² 与 F;阈值放宽时报告 5e-8 下的敏感性结果
独立性(independence)工具变量与混杂因素无关无法直接检验;暴露与结局 GWAS 是否用主成分校正了人群结构;同一人群来源写明两份 GWAS 的人群和主成分校正;社会经济类暴露考虑家系内 MR
排他性(exclusion restriction)工具变量只通过暴露影响结局MR-Egger 截距、Cochran Q、MR-PRESSO 全局与离群检验、加权中位数和众数法与 IVW 比较多种对多效性假设不同的方法方向一致;剔除离群或已知多效基因座后结果稳定

数据来源

下表按 2026-10-10 实际访问结果整理。方法中对每个来源写清:数据集 ID 或文件名、版本、人群、样本量、基因组版本和效应等位基因列。

样本重叠的影响方向:没有重叠时,弱工具偏倚把估计值拉向零,不会产生假阳性;有重叠时,偏倚指向观察性关联的方向,大小随重叠比例线性变化(Burgess 等 2023 指南)。F 约为 30 时,即使完全重叠,相对偏倚也只有约 1/F,约 3%。常用的避免办法是暴露取欧洲联盟或 UKB,结局取 FinnGen;无法避免时报告重叠比例,并用 MRlap 等方法做校正。

来源2026-10 现状使用经验常见错误
IEU OpenGWAS自 2024-05-01 起大部分 API 请求需要 JWT 令牌,令牌 14 天有效;所有用户档位为 100,000 点/10 分钟,新账号先为 Trial,需按账号页提示升级到 Standard;网站下载 VCF 每 24 小时限 20 个数据集,链接 2 小时有效;gwas.mrcieu.ac.uk 已跳转到 opengwas.io/tophits 用预计算 clump 时每个数据集 1 点,需要重新 clump 时 30 点;/ld/clump 每次 12 点;/gwasinfo/files 每次 50 点。批量跑几十个暴露时,先估算点数连续触发 429 后账号和 IP 可能被封最长一周;令牌过期后报 401
FinnGenR13 于 2026-06-02 公开:500,186 人,2,755 个终点,超过 2,100 万个变异;GRCh38;alt 为效应等位基因官方要求填表获取下载说明;manifest(finngen_R13_manifest.tsv)列出每个终点的病例数、对照数和 https 下载地址。文件带 tabix 索引,可远程只取需要的位置OpenGWAS 里的 finn-b-* 是较早的 R5;芬兰人群与其他欧洲人群 LD 结构不同;新的大型联盟 meta 分析可能已纳入 FinnGen,用作结局时核对重叠
UK Biobank(Neale lab round 2)361,194 人,4,203 个表型;Hail 线性回归二分类表型也用线性回归,β 是概率尺度,用作 MR 前换算为近似 logOR:β/[u(1−u)],u 为病例比例;变异 ID 为 chr:pos:ref:alt,需要 variants.tsv.bgz 对应 rsID;GRCh37暴露和结局都来自 UKB 时样本完全重叠
Pan-UKB按祖先人群(EUR、CSA、AFR、EAS、AMR、MID)分别给结果;GRCh37P 值列是 −log10 P(neglog10_pval_EUR),读入时设 log_pval = TRUE;low_confidence_EUR 为 TRUE 的变异先去掉把 neglog10 当作 P 值,阈值筛选结果全错
GWAS Catalog 摘要统计FTP 可直接下载;协调后文件为 *.h.tsv.gz,GRCh38,hm_ 前缀列已按统一方向整理优先用协调后文件的 hm_rsid、hm_effect_allele、hm_beta;原始文件列名各不相同,先读 readme混用 hm_beta 与原始 beta 列,方向不一致

OpenGWAS

TwoSampleMR 从 0.6.0(2024-04)起依赖带新认证系统的 ieugwasr,0.6.20 起要求 ieugwasr ≥ 1.1.0。旧版本即使设置了令牌也无法访问。

本页实测(ieugwasr 1.2.0):没有令牌时调用 extract_instruments 返回上表第一行的 401 报错原文;ld_clump 不传 bfile 时走 API,同样需要令牌。中文帖里流传的环境变量名 IUEUGWAS_TOKEN 是错的,ieugwasr 只读取 OPENGWAS_JWT。

设置与核对令牌r
# 1. 在 https://api.opengwas.io/profile 登录并生成令牌(有效期 14 天)
# 2. 写入 ~/.Renviron(或项目目录下的 .Renviron),变量名必须是 OPENGWAS_JWT
usethis::edit_r_environ()
# 在打开的文件里加一行:OPENGWAS_JWT=eyJhbGciOi...(不加引号,末尾留一个换行)

# 3. 重启 R 后核对
ieugwasr::get_opengwas_jwt()   # 返回一长串字符说明已读到
ieugwasr::user()               # 返回账号信息说明令牌有效;401 说明过期或复制错

# 4. 当前版本的参数名是 opengwas_jwt;旧教程里的 access_token 已不存在
exp <- TwoSampleMR::extract_instruments("ieu-a-300", p1 = 5e-8, r2 = 0.001, kb = 10000)
报错原文原因处理
Status code from OpenGWAS API: 401 … From 1st May 2024 you must provide a token (JWT)没有读到令牌,或令牌已超过 14 天重新生成令牌,写入 .Renviron 后重启 R,用 user() 核对
unused argument (access_token = NULL)照抄 2023 年前的教程,参数已改为 opengwas_jwt删掉 access_token 参数,令牌由环境变量自动读取
Error in if (nrow(d) == 0) return(NULL) : 参数长度为零API 返回为空:令牌失败、数据集 ID 错误或阈值下没有 SNP先运行 user() 排除令牌问题,再用 gwasinfo(id) 核对 ID
429 Too Many Requests10 分钟内点数用完等到响应头 Retry-After 给出的时间;批量任务改为本地文件

离线数据

离线做法适合批量分析和需要复现的论文:数据文件、参考面板和脚本都在本地,结果不随 OpenGWAS 数据库更新而变化。

本页实测发现:GLGC 2013 LDL-C 文件中有 3 个 P 值低于 double 的最小值(1.24e-652、6.56e-397、3.85e-326),fread 因此把整个 P 值列读成字符。此时 pval < 5e-8 按字符比较,2,437,751 行中有 2,435,913 行“通过”筛选,clump 后得到 1,837 个工具变量,全程不报错。读入后先用 class() 检查 P 值列;as.numeric 会把这 3 个值变成 0,format_data 再按 min_pval = 1e-200 截断。

format_data 遇到重复 rsID 时只保留第一条并给出警告。FinnGen 等文件中的多等位位点会产生重复 rsID(本页实测 rs7534572),先按 ref/alt 与暴露等位基因匹配,再交给 format_data。

读取文本摘要统计、GWAS Catalog 协调后文件与 IEU VCFr
library(TwoSampleMR); library(data.table)   # fread 读 .gz 还需要 R.utils

## A. 暴露:作者网站或 GWAS Catalog 下载的文本摘要统计(以 GLGC 2013 LDL-C 为例)
ldl <- fread("jointGwasMc_LDL.txt.gz")
setnames(ldl, c("P-value", "Freq.A1.1000G.EUR"), c("pval", "eaf"))
class(ldl$pval)              # 本页实测为 "character":文件里有 1.24e-652 这类超出 double 范围的值
ldl[, pval := as.numeric(pval)]                 # 不转换时 pval < 5e-8 是字符比较,筛选失效
ldl[, `:=`(A1 = toupper(A1), A2 = toupper(A2))] # GLGC 的等位基因是小写,A1 为效应等位基因
exp_dat <- format_data(as.data.frame(ldl[pval < 5e-8]), type = "exposure",
  snp_col = "rsid", beta_col = "beta", se_col = "se", eaf_col = "eaf",
  effect_allele_col = "A1", other_allele_col = "A2", pval_col = "pval", samplesize_col = "N")

## B. 结局:GWAS Catalog 协调后文件(*.h.tsv.gz,GRCh38,hm_ 前缀列已统一方向)
# 先用 awk 只保留工具变量的行,370 MB 文件约 80 秒,R 里不用读 860 万行
#   gzip -dc GCST003116.h.tsv.gz | awk -F'\t' 'NR==FNR{a[$1];next} FNR==1 || ($2 in a)' snps.txt - > cad_subset.tsv
cad <- fread("cad_subset.tsv")
out_dat <- format_data(as.data.frame(cad), type = "outcome", snps = exp_dat$SNP,
  snp_col = "hm_rsid", beta_col = "hm_beta", se_col = "standard_error",
  eaf_col = "hm_effect_allele_frequency", effect_allele_col = "hm_effect_allele",
  other_allele_col = "hm_other_allele", pval_col = "p_value", chr_col = "hm_chrom", pos_col = "hm_pos")

## C. IEU OpenGWAS 的 VCF:FORMAT 为 ES:SE:LP:AF:SS:ID,LP 是 -log10(P),效应等位基因是 ALT
#   bcftools query -f '%ID\t%CHROM\t%POS\t%ALT\t%REF\t[%ES]\t[%SE]\t[%LP]\t[%AF]\t[%SS]\n' ieu-a-300.vcf.gz > ieu-a-300.tsv
v <- fread("ieu-a-300.tsv", col.names = c("SNP","chr","pos","effect_allele","other_allele","beta","se","lp","eaf","samplesize"))
exp_vcf <- format_data(as.data.frame(v), type = "exposure", pval_col = "lp", log_pval = TRUE)

## D. Pan-UKB:P 值列是 neglog10_pval_EUR,同样用 log_pval = TRUE;效应等位基因是 alt,坐标 GRCh37
FinnGen:用 tabix 远程只取工具变量所在位置bash
# FinnGen 文件带 tabix 索引,只取工具变量所在位置,不用下载整个 810 MB 文件
# regions_hg38.tsv 两列:染色体(1-23,不带 chr)与 GRCh38 位置;可从 GWAS Catalog 协调后文件的 hm_chrom、hm_pos 得到
tabix -h -R regions_hg38.tsv \
  https://storage.googleapis.com/finngen-public-data-r13/summary_stats/finngen_R13_I9_CHD.gz \
  > finngen_chd_subset.tsv
# 列:#chrom pos ref alt rsids nearest_genes pval mlogp beta sebeta af_alt ...(alt 为效应等位基因)
# 本页实测:77 个位置,4 分 26 秒,返回 79 行(含多等位位点);当前目录会留下 .tbi 索引文件

工具变量

阈值、clump 参数和参考面板在看结果前定下来,并在方法中写明。

F > 10 的含义:在单样本或样本重叠的情形中,F 约为 10 时 2SLS 估计相对观察性方向的偏倚约为 10%;它是经验界限,不保证没有偏倚。单 SNP F 近似等于 z²,因此 P<5e-8 时 F 自动大于 29.7,P<5e-6 时大于 20.8,P<1e-5 时大于 19.5。按这些阈值筛选后,“所有 SNP 的 F 都大于 10”不提供额外信息;更有用的是报告总 R² 和整体 F,以及在放宽阈值时比较弱 SNP 的影响。

R² 公式 2·EAF·(1−EAF)·β² 只在 β 为标准差单位时成立,β 必须平方。部分中文教程漏掉平方,或把单位为 mg/dL 的 β 直接代入,算出的 R² 会差几个数量级。上面代码中的写法把 SE 和 N 也纳入,对单位不敏感。

本地 clump:plink + 1000 Genomes 参考面板r
# 参考面板:http://fileserve.mrcieu.ac.uk/ld/1kg.v3.tgz(1.57 GB,含 EUR/EAS/AFR/AMR/SAS)
# 只解压需要的人群:tar -xzf 1kg.v3.tgz EUR.bed EUR.bim EUR.fam
# plink 1.9 可用 conda 安装(bioconda::plink)或 genetics.binaRies::get_plink_binary()
library(ieugwasr)
# 先看有多少显著 SNP 不在参考面板里:这些 SNP 会被 ld_clump 直接删除
bim <- data.table::fread("ref/EUR.bim", select = 2)
miss <- exp_dat[!exp_dat$SNP %in% bim$V2, ]
nrow(miss); min(miss$pval.exposure)   # 本页实测 132 个,最小 P 为 4.3e-127

clumped <- ld_clump(
  dplyr::tibble(rsid = exp_dat$SNP, pval = exp_dat$pval.exposure, id = exp_dat$id.exposure),
  clump_kb = 10000, clump_r2 = 0.001, clump_p = 1,
  bfile = "ref/EUR",                  # 写到文件名前缀,不带 .bed
  plink_bin = Sys.which("plink"))
exp_dat <- exp_dat[exp_dat$SNP %in% clumped$rsid, ]
F 统计量与 R²r
# 单 SNP F 统计量(近似式)
exp_dat$F <- (exp_dat$beta.exposure / exp_dat$se.exposure)^2

# 解释方差 R2(含 SE 与 N 的写法;beta 为 SD 单位时可直接用于连续性状)
b <- exp_dat$beta.exposure; s <- exp_dat$se.exposure
f <- exp_dat$eaf.exposure;  N <- exp_dat$samplesize.exposure
exp_dat$R2 <- 2*b^2*f*(1-f) / (2*b^2*f*(1-f) + 2*s^2*N*f*(1-f))

# 整体 F:k 个 SNP、总 R2
k <- nrow(exp_dat); R2 <- sum(exp_dat$R2, na.rm = TRUE)
F_all <- R2 * (median(N) - k - 1) / (k * (1 - R2))
# 本页实测(79 个 SNP):单 SNP F 最小 27.8,中位 58.4;总 R2 0.085;整体 F 201
设置常见取值依据风险与本页实测
P 阈值5e-8全基因组显著性标准本页实测 LDL-C:3,078 个 SNP,clump 后 79 个
放宽 P 阈值5e-6 或 1e-5(肠道菌群等 SNP 很少的暴露常用 1e-5)5e-8 下少于 3 个 SNP 时无法做 MR-Egger 等敏感性分析工具更弱,赢家诅咒更明显,多效性 SNP 更多。本页实测 5e-6 时 clump 后 114 个,新增 36 个 SNP 的最小 F 为 20.2。放宽时同时报告 5e-8 的结果
clump r²0.001TwoSampleMR 与 ieugwasr 默认值,保证工具变量近似独立放宽到 0.01 或更高时,SNP 之间相关,要用带 LD 矩阵的相关 IVW(MendelianRandomization::mr_ivw(correl = TRUE))
clump 窗口10,000 kb默认值窗口过小会在长 LD 区域保留相关 SNP
参考面板1000 Genomes EUR(503 人,8,550,156 个变异)与暴露 GWAS 人群一致;东亚人群用 EAS面板中没有的 SNP 被直接删除。本页实测 3,060 个显著 SNP 中缺 132 个,其中 38 个 P<1e-20

等位基因对齐

对齐的目的是让暴露和结局的 β 指向同一个效应等位基因。本页实测中,79 个 SNP 有 36 个需要交换等位基因,不对齐时近一半 SNP 的方向是反的。

回文 SNP 指等位基因为 A/T 或 C/G 的 SNP,换链后等位基因不变,只能靠频率判断方向。harmonise_data 源码中的容差为 0.08,对应 0.42–0.58 的区间。被剔除的 SNP 不会从数据框删除,只是 mr_keep 为 FALSE;mr() 会自动忽略它们,但导出补充表时如果不过滤,表中 SNP 数会和结果中的 nsnp 对不上。

代理 SNP:extract_outcome_data 默认 proxies = TRUE、rsq = 0.8,按 LD 自动对齐代理 SNP 的等位基因,这一步依赖 OpenGWAS API。离线时用 plink 在参考面板中找代理,并用 in-phase 输出确定等位基因的对应关系。

本地查找代理 SNPbash
# 结局里缺某个工具变量时,在本地参考面板里找 r2 >= 0.8 的代理 SNP
plink --bfile ref/EUR --r2 in-phase with-freqs \
  --ld-snp rs646776 --ld-window-kb 500 --ld-window 99999 --ld-window-r2 0.8 \
  --out proxy_rs646776
# 输出 PHASE 列如 CG/TA:目标 SNP 的 C 等位基因与代理 SNP 的 G 等位基因在同一单倍型上
# 用代理 SNP 的结局效应时,按这个对应关系把效应等位基因换回目标 SNP 的等位基因
# 本页实测:单个 SNP 约 5 秒,rs646776 找到 10 个代理(含 r2=1 的 rs12740374)
action做法适用情形本页实测(结局为 CARDIoGRAMplusC4D)
1假设两份数据都在正链上,回文 SNP 不做推断两份数据都已按参考基因组正链协调(如 GWAS Catalog 协调后文件与 FinnGen)79 个全部保留
2(默认)用等位基因频率推断回文 SNP 的链;EAF 在 0.42–0.58 之间的回文 SNP 无法推断,标记为 mr_keep = FALSE大多数情形保留 77 个,剔除 rs2954029、rs964184;同样的工具变量在 FinnGen 结局下没有剔除
3剔除所有回文 SNP结局没有 EAF,或想做最保守的敏感性分析保留 76 个

主分析与敏感性

各方法对多效性的假设不同。主分析选 IVW,其余方法用来检查 IVW 的结论在不同假设下是否成立。

MR-PRESSO 的运行时间随 SNP 数和 NbDistribution 增加。本页实测 77 个 SNP:NbDistribution = 1000 时 66 秒并出现“Outlier test unstable … The current precision is <0.077”警告;改为 2000 后 138 秒,警告消失。离群检验的 P 值按 SNP 数做了 Bonferroni 校正,所以 NbDistribution 至少取 SNP 数的 20 倍。

Burgess 等的指南指出,存在多个无效工具变量时,MR-PRESSO 等剔除离群值的方法假阳性率很高。剔除离群 SNP 后的结果宜作为敏感性分析,与未剔除的 IVW 一同报告。

主分析、敏感性分析与作图r
dat <- harmonise_data(exp_dat, out_dat, action = 2)
attr(dat, "log")                      # 记录交换、剔除的 SNP 数,写进补充材料
dat <- dat[dat$mr_keep, ]             # 被剔除的行仍在数据框里,导出补充表前先过滤

res <- mr(dat, method_list = c("mr_ivw", "mr_ivw_fe", "mr_egger_regression",
                               "mr_weighted_median", "mr_weighted_mode"))
generate_odds_ratios(res)
mr_heterogeneity(dat)                 # Cochran Q
mr_pleiotropy_test(dat)               # MR-Egger 截距
Isq(dat$beta.exposure, dat$se.exposure)   # I2GX,低于 0.9 时 MR-Egger 有回归稀释
loo <- mr_leaveoneout(dat); ss <- mr_singlesnp(dat)

# Steiger:结局为二分类时先算 r.outcome,否则按连续性状近似
dat$r.outcome  <- get_r_from_lor(dat$beta.outcome, dat$eaf.outcome,
                                 ncase = 60801, ncontrol = 123504, prevalence = 0.05)
dat$r.exposure <- get_r_from_bsen(dat$beta.exposure, dat$se.exposure, dat$samplesize.exposure)
directionality_test(dat)

# MR-PRESSO:NbDistribution 至少为 SNP 数的 20 倍,否则离群检验精度不足
library(MRPRESSO)
nb <- max(1000, ceiling(nrow(dat) * 20 / 1000) * 1000)
pr <- mr_presso(BetaOutcome = "beta.outcome", BetaExposure = "beta.exposure",
  SdOutcome = "se.outcome", SdExposure = "se.exposure", data = dat,
  OUTLIERtest = TRUE, DISTORTIONtest = TRUE, NbDistribution = nb, seed = 2026)

# 作图
mr_scatter_plot(res, dat); mr_forest_plot(ss); mr_leaveoneout_plot(loo); mr_funnel_plot(ss)
方法成立条件TwoSampleMR 的实现细节报告什么
IVW(乘性随机效应)所有 SNP 有效,或多效性平均为零mr_ivw:SE 除以 min(1, 残差标准误),异质性大时放宽,异质性小时不会比固定效应更窄主分析的 β、OR 与 95% CI
IVW(固定效应)所有 SNP 有效且无异质性mr_ivw_fe:SE 除以残差标准误Q 检验不显著时可作补充;异质性显著时置信区间过窄
MR-EggerInSIDE:多效性大小与工具强度无关mr_egger_regression;至少 3 个 SNP斜率与截距;I²GX < 0.9 时存在回归稀释,需用 SIMEX 校正或谨慎解读
加权中位数按权重计超过 50% 的 SNP 有效mr_weighted_median,bootstrap 1,000 次估计值与 IVW 方向是否一致
加权众数权重最大的一组 SNP 有效mr_weighted_mode同上;该法偏保守,置信区间较宽
MR-PRESSO离群 SNP 是多效性来源至少 4 个 SNP;NbDistribution 必须大于 SNP 数;SNP 数/NbDistribution 大于 0.05 时警告 Outlier test unstable全局检验 P、离群 SNP、校正后估计值与扭曲检验 P
Cochran Q—mr_heterogeneity 给出 IVW 和 Egger 的 QQ、自由度、P;I² = (Q − df)/Q
留一法—mr_leaveoneout逐个剔除后估计值是否跨过零;SNP 很多时意义有限
Steiger 方向检验SNP 对暴露的解释方差大于对结局的解释方差directionality_test;二分类结局需先用 get_r_from_lor 计算 r.outcome方向是否正确与 P 值;steiger_filtering 可逐 SNP 剔除方向相反者

结果解读

MR-Egger 和众数法的统计效能比 IVW 低,置信区间更宽,单独不显著很常见。判断时先看方向和点估计,再看 P 值。

情形解读报告写法
IVW 显著,其他方法方向一致但不显著多数情况是效能不足,本页实测 Egger 的 SE(0.078)约为 IVW(0.051)的 1.5 倍写明各方法方向一致,点估计接近;以 IVW 为主要结论
Egger 截距 P<0.05存在定向多效性,IVW 有偏以 Egger、加权中位数和众数的结果为主;查找并说明离群 SNP;结论降级为提示性
Q 检验显著,截距不显著存在异质性,多效性可能是平衡的使用乘性随机效应 IVW(TwoSampleMR 默认),报告 Q 与 I²
MR-PRESSO 校正前后差异显著(扭曲检验 P<0.05)离群 SNP 明显改变估计值同时报告两者;说明离群 SNP 所在基因座的已知关联
不同方法方向相反因果效应无法确定检查等位基因对齐与单位;不下因果结论
只有 1–3 个 SNP只能用 Wald 比值或 IVW,Egger 需要至少 3 个,MR-PRESSO 需要至少 4 个说明敏感性分析受限;考虑放宽阈值作为补充分析或寻找更大的暴露 GWAS

本页实测

运行条件:macOS arm64,8 核,16 GB 内存;R 4.5.3、TwoSampleMR 0.7.12、ieugwasr 1.2.0、MRPRESSO 1.0、MendelianRandomization 0.10.0、meta 8.5.0、PLINK 1.9、htslib 1.24。暴露为 GLGC 2013 LDL-C(2,437,751 个 SNP,N 最大约 17.3 万);结局为 CARDIoGRAMplusC4D 2015(GWAS Catalog GCST003116 协调后文件,60,801 例病例与 123,504 例对照),并用 FinnGen R13 I9_CHD(90,714 例病例与 409,472 例对照)复现。全程不用 OpenGWAS 令牌。

这组结果说明了三点。第一,Q 检验高度显著时固定效应 IVW 的 SE 只有随机效应的 46%,P 值相差 54 个数量级,报告固定效应会夸大精度。第二,MR-PRESSO 找到的离群 SNP 包括 SH2B3(rs3184504)和 ABO(rs579459)等已知多效基因座,剔除后估计值从 0.412 变为 0.437,扭曲检验不显著,结论不变。第三,同一组工具变量在两个结局来源中的 OR 分别为 1.51 和 1.32,两者的异质性检验 P = 0.022;FinnGen 的 I9_CHD 是基于登记数据的“主要冠心病事件”终点,人群为芬兰人,结局定义和人群都会改变效应大小。

合并两个结局来源的估计值并画森林图r
# 同一暴露、两个独立结局来源的 IVW 估计合并(meta 包 8.5)
library(meta)
m <- metagen(TE = c(0.4123, 0.2741), seTE = c(0.0511, 0.0318),
             studlab = c("CARDIoGRAMplusC4D 2015", "FinnGen R13 I9_CHD"),
             sm = "OR", common = TRUE, random = TRUE)
forest(m)
# 本页实测:共同效应 OR 1.37 (1.30-1.44);随机效应 1.40 (1.22-1.60);Q = 5.28,P = 0.022,I2 = 81%
  1. 01

    筛选与 clump

    P<5e-8 得到 3,078 个 SNP,去重后 3,060 个;本地 plink clump(r²=0.001,10,000 kb,1000G EUR)耗时 3 秒,保留 79 个。读入和 clump 合计 22 秒,内存峰值约 2 GB。

  2. 02

    工具强度

    单 SNP F 最小 27.8,中位数 58.4;总 R² 0.085;整体 F 201。

  3. 03

    对齐

    harmonise_data(action = 2) 交换 36 个 SNP 的等位基因,剔除 2 个中间频率回文 SNP,进入分析 77 个。

  4. 04

    主分析与敏感性

    IVW 显示 LDL-C 每升高 1 SD,冠心病 OR 1.51;Egger 截距 P = 0.13;Q 检验高度显著;MR-PRESSO 找到 8 个离群 SNP,剔除后估计值几乎不变。留一法估计值范围 0.386–0.455,最大 P 为 1.4×10⁻¹³。Steiger 检验:SNP 对暴露的 R² 为 0.083,对结局为 0.0058,方向正确。

  5. 05

    独立结局复现

    用 tabix 从 FinnGen R13 远程取 77 个位置(4 分 26 秒),IVW OR 1.32;方向一致,效应较小。

方法SNP 数β(SE)OR(95% CI)P
IVW(乘性随机效应)770.412(0.051)1.51(1.37–1.67)6.7×10⁻¹⁶
IVW(固定效应)770.412(0.023)1.51(1.44–1.58)7.6×10⁻⁷⁰
MR-Egger770.503(0.078)1.65(1.42–1.93)1.0×10⁻⁸
加权中位数770.396(0.044)1.49(1.36–1.62)3.1×10⁻¹⁹
加权众数770.540(0.079)1.72(1.47–2.01)2.1×10⁻⁹
MR-PRESSO 校正后(剔除 8 个)690.437(0.032)1.55(1.45–1.65)6.4×10⁻²¹
FinnGen R13 复现(IVW)770.274(0.032)1.32(1.24–1.40)7.4×10⁻¹⁸
异质性:IVW 的 Q = 363.8(df 76,P = 3.8×10⁻³⁹,I² = 79.1%);Egger 截距 −0.0070(SE 0.0046,P = 0.13);I²GX 为 0.986(TwoSampleMR Isq)与 97.9%(MendelianRandomization,加权算法不同);MR-PRESSO 全局检验 P < 5×10⁻⁴,扭曲检验 P = 0.44。

常见错误

效应等位基因列选错

各来源的效应等位基因列:GLGC 2013 为 A1;FinnGen、Pan-UKB、Neale 为 alt;GWAS Catalog 协调后文件为 hm_effect_allele;IEU VCF 为 ALT。把 ref 当效应等位基因,β 符号会和对齐后的结局相反,因果估计方向随之反转。

暴露与结局人群不同

工具变量来自欧洲人群、结局来自东亚人群时,LD 结构和等位基因频率不同,回文 SNP 推断和代理 SNP 都会出错。参考面板的人群也要与暴露 GWAS 一致,东亚数据用 EAS 面板。

二分类暴露的 OR 解读

暴露为疾病时,MR 估计值对应暴露对数优势每增加 1 个单位的效应。乘以 ln2 = 0.693 得到暴露优势加倍时的效应(Burgess 与 Labrecque 2018)。写成“患病者比未患病者风险高 X 倍”是错误的解读。

线性模型给出的二分类 β

Neale lab 的 UKB 结果对二分类表型用线性回归,β 在概率尺度上。直接当 logOR 使用,OR 会接近 1。用 β/[u(1−u)] 近似换算,u 为病例比例。

多重检验

一次检验多个暴露或结局时,按检验次数做 Bonferroni 校正(例如 20 个暴露的界值为 0.05/20 = 0.0025)或报告 FDR。介于 0.05 与校正界值之间的结果写为“提示性”。

Excel 中转数据

在 Excel 中整理 GWAS 结果再另存 CSV,数值列格式不对时 β、SE 会丢失或变成 0,极小的 P 值被截断。全程用 R 或命令行读写原始文件。

审稿意见

质疑应对的分析写进论文的内容
水平多效性MR-Egger 截距、MR-PRESSO 全局检验、加权中位数和众数;查询离群 SNP 所在基因座的已知关联,剔除后重跑多种方法方向一致;剔除已知多效基因座后的结果;必要时做多变量 MR 校正主要的多效通路
弱工具变量总 R²、整体 F;阈值放宽时比较 5e-8 的结果报告每个 SNP 的 F 和总 R²;说明两样本无重叠时弱工具偏向零
样本重叠核对两份 GWAS 的队列名单;换用不重叠的结局来源复现;MRlap 校正重叠人数或比例;独立数据源的复现结果
人群分层两份 GWAS 是否用主成分校正;暴露与结局来自同一祖先人群写明主成分数与人群;社会经济类暴露讨论家系内 MR 的可能性
反向因果Steiger 方向检验;反向 MRSteiger 结果与 steiger_filtering 后的估计值
只用公开数据、结论缺少新意阳性对照结局;独立结局来源复现;与 RCT 或观察性研究比较复现结果的森林图;与已有证据的比较

国内经验

以下来自 CSDN,只收录带报错原文或作者实测、并与官方文档或本页实测一致的内容。2026 年大量“避坑指南”类文章是模板化文本,其中把令牌变量名写成 IUEUGWAS_TOKEN、称 action = 2 会“保留所有 SNP”,这两点都与源码不符。

401 报错与令牌重置

一位作者(2025 年 11 月)记录了 “Status code from OpenGWAS API: 401” 报错,解决办法是注册后把 OPENGWAS_JWT 写入 .Renviron,并指出令牌有时限、过期后在账号页重置。这与官方 14 天有效期一致,本页复现了同一报错。

本地 clump 的列名和路径

一位作者(2024 年 4 月)在线 clump 频繁超时后改用 plink 本地 clump,指出数据框列名必须改为 rsid 和 pval,bfile 写到参考文件名前缀。与 ieugwasr 文档一致,本页实测通过。

同样的数据和代码,P 值和原文不同

一位作者(2023 年 6 月,9 千余次阅读)用原文作者提供的数据和代码复现一篇 MR 论文,OR 和置信区间接近,P 值不同。OpenGWAS 数据集和包版本都会更新,论文里写明包版本和数据下载日期,并保存所用的数据文件。该文代码中的 access_token 参数在当前版本已报错。

Excel 另存 CSV 导致 F 值全部相同

一位作者(2023 年 4 月)发现所有 SNP 的 F 值相同,排查两天后确认是 Excel 中“常规”格式的数值列另存 CSV 时变成 0。该文给出的 R² 公式漏掉了 β 的平方,使用时按本页的公式。

IEU VCF 的字段含义

一位作者(2023 年 6 月,2.7 万次阅读)给出 IEU VCF 的 FORMAT 字段:ES 为 β,SE 为标准误,LP 为 −log10(P),AF 为效应等位基因频率。与 GWAS-VCF 规范一致;用 bcftools query 导出比 vcfR 读整个文件快,内存占用也小。

交给 Agent

可以用一句话描述分析任务,由 Scientify 的科学智能体在云电脑中完成。

指令示例:“用 GLGC 2013 的 LDL-C 摘要统计作暴露、GWAS Catalog GCST003116 的冠心病作结局做两样本 MR:P<5e-8,用 1000G EUR 本地 clump(r²=0.001,10,000 kb),计算 F 和 R²,harmonise 用 action=2,跑 IVW、Egger、加权中位数、加权众数、MR-PRESSO、Q 检验、留一法和 Steiger,再用 FinnGen R13 I9_CHD 复现,按 STROBE-MR 输出方法段和结果表。”

智能体在云电脑中安装 TwoSampleMR、MRPRESSO 和 plink,下载摘要统计和参考面板,检查 P 值列类型、效应等位基因列和基因组版本,完成筛选、clump、对齐和全部分析,输出结果表、散点图、森林图、留一法图、漏斗图和方法段草稿。工作区保留脚本、参数、日志和数据文件,可以复现;智能体会对结果做对抗审阅,例如核对对齐后被交换的 SNP 数、固定效应与随机效应的选择是否与 Q 检验一致、离群 SNP 是否为已知多效基因座。关闭本机后任务继续运行。

你仍需要自己核对:暴露和结局 GWAS 的人群与样本重叠情况,阈值和方法是否在看结果前确定,二分类暴露的效应尺度是否换算正确,结论的措辞是否与敏感性分析的结果相符。

资料来源

常见问题

没有 OpenGWAS 令牌还能做孟德尔随机化吗?

能。从 GWAS Catalog、FinnGen、Pan-UKB 或原论文网站下载摘要统计,用 format_data 读入,用 plink 加 1000 Genomes 参考面板在本地 clump,之后的 harmonise_data、mr 和敏感性分析都不需要令牌。本页的 LDL-C→冠心病实测全程没有使用令牌。

P<5e-8 时工具变量太少,可以放宽到 5e-6 吗?

可以作为主分析或补充分析,但要在方法里说明理由,并同时报告 5e-8 下的结果。放宽后新增的 SNP 更弱、更容易受赢家诅咒和多效性影响。按 5e-6 筛选的 SNP 的 F 会自动大于约 20.8,所以“F>10”不能证明放宽是安全的。

IVW 应该用固定效应还是随机效应?

TwoSampleMR 的 mr_ivw 默认是乘性随机效应,异质性小时与固定效应相同,异质性大时放宽置信区间。Q 检验显著时报告随机效应;本页实测中两者的 SE 分别为 0.051 和 0.023,固定效应会夸大精度。

MR-Egger 截距不显著,就能说明没有多效性吗?

不能。截距检验效能低,只能检测定向多效性,并依赖 InSIDE 假设。应同时报告 Q 检验、MR-PRESSO 全局检验和加权中位数、众数法的结果,并说明离群 SNP。

harmonise_data 的 action 选 1、2 还是 3?

一般用默认的 2,它用等位基因频率推断回文 SNP,EAF 在 0.42–0.58 的回文 SNP 被剔除。两份数据都已协调到正链时可用 1;结局没有频率信息或要做最保守的分析时用 3。

暴露和结局都来自 UK Biobank 可以吗?

可以做,但两份数据样本完全重叠,弱工具偏倚会指向观察性关联方向。工具变量较强(F 约 30 以上)时偏倚较小。更稳妥的做法是用 FinnGen 等不重叠的结局来源复现,并在论文中报告重叠情况。

把孟德尔随机化分析交给 Scientify

科学智能体在隔离云电脑中运行本页流程:下载摘要统计和参考面板、本地 clump、等位基因对齐、主分析与全部敏感性分析、独立结局复现和作图,保留全部脚本、参数和日志。新注册用户免费获得 5 美元等值额度。