全流程
函数与默认值按 TwoSampleMR 0.7.12(2026-10-08 发布)与 ieugwasr 1.2.0 核对。
| 步骤 | TwoSampleMR / 工具 | 关键参数(默认值) | 论文里报告 |
|---|---|---|---|
| 1 取暴露工具变量 | extract_instruments(需令牌);离线用 format_data | p1 = 5e-8 | GWAS 来源、样本量、人群、阈值及理由 |
| 2 LD clump | clump_data / ieugwasr::ld_clump | clump_r2 = 0.001,clump_kb = 10000,pop = "EUR" | 参考面板与人群;clump 前后 SNP 数 |
| 3 工具强度 | 自算 F 与 R² | F = (β/SE)² | 每个 SNP 的 F、总 R² |
| 4 取结局数据 | extract_outcome_data(需令牌);离线用 format_data | proxies = TRUE,rsq = 0.8,maf_threshold = 0.3 | 缺失 SNP 数、代理 SNP 数 |
| 5 等位基因对齐 | harmonise_data | action = 2(回文 SNP 的 EAF 在 0.42–0.58 时剔除) | attr(dat, "log") 中交换与剔除的 SNP 数 |
| 6 主分析与敏感性 | mr、mr_heterogeneity、mr_pleiotropy_test、mr_leaveoneout、directionality_test、MRPRESSO::mr_presso | IVW 为乘性随机效应;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 |
| FinnGen | R13 于 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)分别给结果;GRCh37 | P 值列是 −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。
# 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 Requests | 10 分钟内点数用完 | 等到响应头 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。
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 索引,只取工具变量所在位置,不用下载整个 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 也纳入,对单位不敏感。
# 参考面板: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, ]# 单 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.001 | TwoSampleMR 与 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 输出确定等位基因的对应关系。
# 结局里缺某个工具变量时,在本地参考面板里找 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 一同报告。
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-Egger | InSIDE:多效性大小与工具强度无关 | 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 的 Q | Q、自由度、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 是基于登记数据的“主要冠心病事件”终点,人群为芬兰人,结局定义和人群都会改变效应大小。
# 同一暴露、两个独立结局来源的 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%- 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。
- 02
工具强度
单 SNP F 最小 27.8,中位数 58.4;总 R² 0.085;整体 F 201。
- 03
对齐
harmonise_data(action = 2) 交换 36 个 SNP 的等位基因,剔除 2 个中间频率回文 SNP,进入分析 77 个。
- 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,方向正确。
- 05
独立结局复现
用 tabix 从 FinnGen R13 远程取 77 个位置(4 分 26 秒),IVW OR 1.32;方向一致,效应较小。
| 方法 | SNP 数 | β(SE) | OR(95% CI) | P |
|---|---|---|---|---|
| IVW(乘性随机效应) | 77 | 0.412(0.051) | 1.51(1.37–1.67) | 6.7×10⁻¹⁶ |
| IVW(固定效应) | 77 | 0.412(0.023) | 1.51(1.44–1.58) | 7.6×10⁻⁷⁰ |
| MR-Egger | 77 | 0.503(0.078) | 1.65(1.42–1.93) | 1.0×10⁻⁸ |
| 加权中位数 | 77 | 0.396(0.044) | 1.49(1.36–1.62) | 3.1×10⁻¹⁹ |
| 加权众数 | 77 | 0.540(0.079) | 1.72(1.47–2.01) | 2.1×10⁻⁹ |
| MR-PRESSO 校正后(剔除 8 个) | 69 | 0.437(0.032) | 1.55(1.45–1.65) | 6.4×10⁻²¹ |
| FinnGen R13 复现(IVW) | 77 | 0.274(0.032) | 1.32(1.24–1.40) | 7.4×10⁻¹⁸ |
常见错误
效应等位基因列选错
各来源的效应等位基因列: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 方向检验;反向 MR | Steiger 结果与 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 API 文档:认证、用量与各接口点数 — 令牌 14 天有效;各档位 100,000 点/10 分钟;/tophits、/ld/clump、/gwasinfo/files 点数;429 封禁规则
- OpenGWAS 数据集页面(ieu-a-300) — 网站 VCF 下载每 24 小时 20 个数据集、链接 2 小时有效
- ieugwasr:Guide 与 Running local LD operations — OPENGWAS_JWT、get_opengwas_jwt、user;本地 ld_clump 的 bfile 与 plink_bin;1kg.v3.tgz
- TwoSampleMR 更新日志 — 0.7.12(2026-10-08);0.6.0 改用 CRAN 版 ieugwasr;0.6.20 要求 ieugwasr ≥ 1.1.0
- STROBE-MR 清单 — 20 项报告条目;本页引用第 5、7、9、10d、11、13 条
- Burgess S, et al. Guidelines for performing Mendelian randomization investigations: update for summer 2023. Wellcome Open Res — 样本重叠的偏倚方向、方法假设表、MR-PRESSO 假阳性、阳性对照与留一法
- FinnGen:Access results 与 R13 数据说明 — DF13 公开日期 2026-06-02;alt 为效应等位基因;GRCh38;manifest 与 tabix 索引
- Pan-UKB:Per-phenotype files — neglog10_pval 列、alt 为效应等位基因、GRCh37、low_confidence 标记
- Neale lab UK Biobank GWAS(GitHub) — round 2 用 Hail 线性回归
- GWAS Catalog 摘要统计 GCST003116(CARDIoGRAMplusC4D 2015) — 本页实测结局数据;协调后文件 hm_ 列
- GLGC 2013 血脂 GWAS 结果 — 本页实测暴露数据;A1 为效应等位基因
- MR-PRESSO(GitHub rondolab) — NbDistribution 与 SNP 数的约束、Outlier test unstable 警告(本页读源码核对)
- Burgess S, Davies NM, Thompson SG. Bias due to participant overlap in two-sample Mendelian randomization. Genet Epidemiol 2016 — 样本重叠偏倚与 F 统计量的关系
- Burgess S, Labrecque JA. Mendelian randomization with a binary exposure variable. Eur J Epidemiol 2018 — 二分类暴露估计值的解读与乘以 ln2 的换算
- Lloyd-Jones LR, et al. Transformation of summary statistics from linear mixed model association on all-or-none traits to odds ratio. Genetics 2018 — 线性模型 β 换算为 logOR
- 经验帖:CSDN《MR下载数据报错 Status code from OpenGWAS API: 401》 — 经验帖:401 报错与令牌重置
- 经验帖:CSDN《孟德尔随机化连锁不平衡跑不了!这里有本地连锁不平衡分析方法》 — 经验帖:本地 clump 列名与 bfile 路径
- 经验帖:CSDN《R语言复现一篇6分的孟德尔随机化文章》 — 经验帖:同数据同代码复现 P 值不同;旧参数 access_token
- 经验帖:CSDN《孟德尔随机化——踩一个大家都没踩过的坑》 — 经验帖:Excel 另存 CSV 后数值变 0
- 经验帖:CSDN《GWAS数据下载详解(1)》 — 经验帖:IEU VCF 的 ES/SE/LP/AF 字段