跳转至

连锁不平衡(LD)分析与可视化

一句话概述:连锁不平衡(LD)衡量两个遗传位点等位基因间的非随机关联程度,通过 PLINK 和 PopLDdecay 计算 r² 和 D',绘制 LD 衰减曲线揭示群体历史。


核心知识点速查表

概念白话解释
LD(连锁不平衡)两个位点的等位基因"抱团"出现,不是随机组合
LD 的常用度量(0~1),越大表示两个位点越"绑定"
D'另一种 LD 度量(0~1),更敏感但受样本量影响大
LD 衰减随距离增大 r² 逐渐降到背景水平的过程
LD pruning去掉高 LD 的 SNP(用于 PCA、ADMIXTURE 等)
LD block一段 LD 很高的基因组区域(单倍型块)
PopLDdecay专门计算 LD 衰减的工具,直接读 VCF
半衰距离r² 衰减到一半时的物理距离,反映群体大小

一、LD 的原理(白话版)

比喻:想象两副扑克牌(两个基因位点),如果你总是同时抽到红心A和黑桃K(特定等位基因组合出现得比随机多),这就是"连锁不平衡"。

LD 产生的原因: 1. 物理连锁:两个位点在染色体上离得近,很少被重组打断 2. 群体事件:瓶颈效应、建立者效应会在无关位点间产生 LD 3. 自然选择:正向选择会在选择位点周围产生高 LD 4. 群体结构:不同群体混合会产生 LD

LD 衰减的含义:自交物种(如水稻)LD 衰减慢(LD block 大),异交物种(如玉米)LD 衰减快(LD block 小)。


二、方法 1:PopLDdecay(推荐)

# PopLDdecay:直接从VCF计算LD衰减,速度快、存储省
# 安装
git clone https://github.com/BGI-shenzhen/PopLDdecay.git  # 克隆仓库
cd PopLDdecay
make                                                         # 编译

# 或 conda 安装
conda install -c bioconda popldecay  # conda安装

# 基本用法:计算全基因组 LD 衰减
PopLDdecay -InVCF input.vcf.gz \     # 输入VCF文件(支持gz压缩)
           -OutStat LDdecay_all \    # 输出统计结果
           -MaxDist 500 \             # 最大距离500kb(默认300kb)
           -MAF 0.05 \                # 最低等位基因频率过滤
           -Miss 0.1                   # 最大缺失率

# 输出文件:LDdecay_all.stat.gz — 压缩的LD统计结果

# 按亚群分别计算(需要样本列表)
# 准备样本列表文件(每行一个样本名)
echo -e "sample1\nsample2\nsample3" > group_A.list

PopLDdecay -InVCF input.vcf.gz \
           -OutStat LDdecay_groupA \
           -SubPop group_A.list \     # 指定亚群样本列表
           -MaxDist 500

# 可视化:单群体 LD 衰减曲线
perl PopLDdecay/bin/Plot_OnePop.pl \
     -inFile LDdecay_all.stat.gz \   # 输入统计文件
     -output LD_figure                 # 输出图片前缀
# 输出 LD_figure.png 和 LD_figure.pdf

# 可视化:多群体比较
# 准备群体列表文件(每行:群体名  统计文件路径)
cat << 'EOF' > pop_list.txt
GroupA  LDdecay_groupA.stat.gz
GroupB  LDdecay_groupB.stat.gz
GroupC  LDdecay_groupC.stat.gz
EOF

perl PopLDdecay/bin/Plot_MutiPop.pl \
     -inList pop_list.txt \           # 输入群体列表
     -output LD_comparison             # 输出图片

# PLINK 适合计算特定区域的 LD 或 LD block

# 3.1 计算成对 SNP 的 r²
plink --vcf input.vcf.gz \         # 输入VCF
      --r2 \                         # 计算r²
      --ld-window 100 \             # 最多比较100个SNP的窗口
      --ld-window-kb 1000 \         # 最大物理距离1Mb
      --ld-window-r2 0 \            # 输出所有r²(包括0)
      --out ld_pairwise              # 输出前缀

# 输出文件:ld_pairwise.ld
# 格式:CHR_A BP_A SNP_A CHR_B BP_B SNP_B R2

# 3.2 LD pruning(为其他分析准备独立SNP集)
# 标记高LD的SNP对
plink --vcf input.vcf.gz \
      --indep-pairwise 50 10 0.2 \  # 窗口50 SNP,步长10,r²阈值0.2
      --out pruned                   # 输出前缀
# 输出:pruned.prune.in(保留的SNP)、pruned.prune.out(移除的SNP)

# 提取独立SNP
plink --vcf input.vcf.gz \
      --extract pruned.prune.in \   # 只保留通过筛选的SNP
      --make-bed \
      --out data_ldpruned

# 3.3 计算 LD block(Haploview 算法)
plink --bfile mydata \
      --blocks no-pheno-req \        # 不要求表型数据
      --blocks-max-kb 200 \          # 最大block大小200kb
      --out ld_blocks                 # 输出前缀
# 输出:ld_blocks.blocks.det — LD block 详细信息

四、用 R 自定义 LD 衰减图

# ========== R脚本:LD衰减曲线 ==========

# 读取PLINK的LD输出
ld <- read.table("ld_pairwise.ld", header=TRUE)  # 读取LD结果

# 计算SNP对之间的距离
ld$dist_kb <- abs(ld$BP_B - ld$BP_A) / 1000      # 距离转为kb

# 按距离分组计算平均r²
breaks <- seq(0, 500, by=10)                       # 0~500kb,每10kb一组
ld$bin <- cut(ld$dist_kb, breaks=breaks)           # 分组
avg_r2 <- tapply(ld$R2, ld$bin, mean, na.rm=TRUE) # 每组平均r²
mid_dist <- (breaks[-length(breaks)] + breaks[-1]) / 2  # 组中值

# 画 LD 衰减曲线
pdf("LD_decay_custom.pdf", width=10, height=6)     # 创建PDF
plot(mid_dist, avg_r2,                              # 画散点
     type="l", lwd=2, col="steelblue",             # 蓝色线
     xlab="Distance (kb)",                          # X轴
     ylab=expression(r^2),                          # Y轴(r²上标)
     main="LD Decay Curve",                         # 标题
     ylim=c(0, max(avg_r2, na.rm=TRUE)))           # Y轴范围

# 标注半衰距离
half_r2 <- max(avg_r2, na.rm=TRUE) / 2             # r²最大值的一半
abline(h=half_r2, col="red", lty=2)                # 水平虚线
# 找到半衰距离
half_dist <- mid_dist[which.min(abs(avg_r2 - half_r2))]
abline(v=half_dist, col="red", lty=2)              # 垂直虚线
text(half_dist + 20, half_r2 + 0.02,               # 标注文字
     paste0("Half-decay: ", half_dist, " kb"),
     col="red")
dev.off()

五、LD 热图(Heatmap)

# 用 LDheatmap R包画特定区域的LD热图
# install.packages("LDheatmap")
library(LDheatmap)                                 # 加载包

# 从PLINK输出构建LD矩阵
# 先提取特定区域的LD
# plink --bfile mydata --chr 1 --from-bp 1000000 --to-bp 2000000 --r2 square --out region_ld

# 读取方形LD矩阵
ld_matrix <- as.matrix(read.table("region_ld.ld"))  # 读取r²矩阵
snp_pos <- read.table("region_ld.bim")$V4           # SNP位置

# 画LD热图
pdf("LD_heatmap.pdf", width=10, height=10)
LDheatmap(ld_matrix,                                # LD矩阵
          genetic.distances=snp_pos/1e6,             # 位置(Mb)
          color=heat.colors(20),                     # 颜色方案
          title="LD Heatmap (r²)",                   # 标题
          add.map=TRUE)                              # 添加基因组位置
dev.off()

六、常见报错与解决

报错信息原因解决方法
PopLDdecay Segmentation fault内存不足分染色体计算
PLINK LD 输出文件太大成对比较数量爆炸限制 --ld-window-kb--ld-window
r² 在短距离就接近 0MAF 过滤太严或样本太少放宽 MAF 阈值,增加样本
LD 衰减曲线不平滑SNP 密度太低或分组太粗增加 SNP 密度或调整 bin 大小
No variants remaining过滤条件太严检查 MAF、缺失率等过滤参数

七、面试高频问题

Q1:r² 和 D' 的区别?

r² 范围 0~1,受等位基因频率影响,适合 GWAS 设计和 LD 衰减分析。D' 范围 0~1,在样本量小时容易被高估(向 1 偏倚),适合 LD block 定义。一般 LD 衰减用 r²,LD block 用 D'。

Q2:LD 衰减快慢说明什么?

LD 衰减快 → 有效群体大、重组率高(如玉米,衰减距离 ~1kb)。LD 衰减慢 → 有效群体小或自交(如水稻,衰减距离 ~100-200kb)。GWAS 中 LD 衰减快需要更密的标记。

Q3:为什么做 PCA/ADMIXTURE 前要 LD pruning?

因为这些方法假设 SNP 独立。如果不做 LD pruning,基因组中某个高 LD 区域(如着丝粒附近)的 SNP 权重会被放大,导致群体结构被某些区域的信号主导而非全基因组信号。


八、速查表

# === LD 分析速查 ===

# PopLDdecay:全基因组LD衰减(推荐)
PopLDdecay -InVCF input.vcf.gz -OutStat LDdecay -MaxDist 500 -MAF 0.05
perl Plot_OnePop.pl -inFile LDdecay.stat.gz -output fig

# PLINK:LD计算与pruning
plink --vcf in.vcf.gz --r2 --ld-window-kb 1000 --out ld_result  # 计算r²
plink --vcf in.vcf.gz --indep-pairwise 50 10 0.2 --out pruned   # LD pruning
plink --vcf in.vcf.gz --extract pruned.prune.in --make-bed --out data_pruned

# PLINK:LD block
plink --bfile mydata --blocks no-pheno-req --out blocks

# r² 经验阈值:
# r² > 0.8 → 强LD(两个SNP几乎等价)
# r² > 0.2 → 有意义的LD
# r² < 0.1 → 基本独立

参考资料:PopLDdecay (Zhang et al. 2019, Bioinformatics)、PLINK 1.9 LD文档、GWLD R包 (2023)、Speciation Genomics Tutorial