跳转至

群体遗传结构分析 — ADMIXTURE

一句话概述:ADMIXTURE 通过最大似然法将每个个体的基因组拆分成来自 K 个祖先群体的比例,画出经典的"彩色柱状图"揭示群体混合历史。


核心知识点速查表

概念白话解释
ADMIXTURE群体结构分析软件,类似 STRUCTURE 但速度快几十倍
K 值假设的祖先群体数目(K=2 表示假设有 2 个祖先群体)
CV error交叉验证误差,越小说明 K 值越合理
LD pruning去除连锁不平衡的 SNP,保证 SNP 独立
Q matrix每个个体属于各祖先群体的比例矩阵
PCA主成分分析,与 ADMIXTURE 互补验证群体结构
pongADMIXTURE 结果可视化工具,自动对齐多次运行
PopCluster2025 年新工具,支持百万级样本并行分析

一、什么是群体遗传结构?(白话版)

想象你面前有一堆颜料珠子(每个人的基因组),这些珠子其实是几种原色混合出来的。ADMIXTURE 就是帮你找出"有几种原色"(K 值)以及"每颗珠子里各原色的比例"(祖先成分)

比如:小明的基因组 = 60% 东亚祖先 + 30% 东南亚祖先 + 10% 南亚祖先。


二、分析流程

整体流程图

VCF文件 → PLINK格式转换 → LD pruning → ADMIXTURE运行(K=1~10) → CV error选最佳K → 可视化

第 1 步:环境准备与安装

# 安装 ADMIXTURE(下载二进制文件)
wget https://dalexander.github.io/admixture/binaries/admixture_linux-1.3.0.tar.gz  # 下载压缩包
tar -xzf admixture_linux-1.3.0.tar.gz  # 解压
chmod +x admixture  # 添加执行权限
export PATH=$PATH:$(pwd)  # 添加到环境变量

# 安装 PLINK(用于格式转换和LD pruning)
conda install -c bioconda plink  # 通过conda安装plink
# 将 VCF 转换为 PLINK 的 bed/bim/fam 格式
plink --vcf input.vcf.gz \       # 输入VCF文件
      --make-bed \                # 生成bed格式
      --allow-extra-chr \         # 允许非标准染色体名
      --set-missing-var-ids @:# \ # 给没有ID的SNP设置ID(染色体:位置)
      --out mydata                # 输出文件前缀

# 输出文件说明:
# mydata.bed — 基因型的二进制文件(核心数据)
# mydata.bim — 每个SNP的信息(染色体、位置、等位基因)
# mydata.fam — 每个样本的信息(家系、性别、表型)

第 3 步:LD pruning(去掉连锁的 SNP)

# 为什么要 LD pruning?
# ADMIXTURE 假设 SNP 之间是独立的,连锁的 SNP 会让结果偏差

# 第一步:标记要保留/删除的 SNP
plink --bfile mydata \            # 输入bed文件
      --indep-pairwise 50 10 0.1 \ # 窗口50个SNP,步长10,r²阈值0.1
      --out mydata_pruned          # 输出前缀

# 第二步:只保留独立的 SNP
plink --bfile mydata \            # 输入原始bed文件
      --extract mydata_pruned.prune.in \ # 只保留通过筛选的SNP
      --make-bed \                 # 生成新的bed文件
      --out mydata_ldpruned        # 输出前缀

# 检查保留了多少 SNP
wc -l mydata_ldpruned.bim  # 统计SNP数量
# 一般保留几万到几十万个SNP就够了

第 4 步:运行 ADMIXTURE(遍历 K 值)

# 对 K=1 到 K=10 分别运行 ADMIXTURE
for K in $(seq 1 10); do
    admixture --cv \              # 启用交叉验证(计算CV error)
              mydata_ldpruned.bed \ # 输入文件
              $K \                 # 当前K值
              -j4 \                # 使用4个线程
              | tee log_K${K}.out  # 同时输出到屏幕和日志文件
done

# 输出文件说明(以K=3为例):
# mydata_ldpruned.3.Q — Q矩阵,每行是一个个体,3列分别是3个祖先群体的比例
# mydata_ldpruned.3.P — P矩阵,每行是一个SNP在各祖先群体中的等位基因频率

第 5 步:选择最佳 K 值

# 提取所有K值的CV error
grep -h "CV" log_K*.out | awk '{print $3,$4}' > cv_errors.txt
# 输出格式:(K=1): 0.54321
# 输出格式:(K=2): 0.43210
# ...

# 用R画CV error曲线
cat << 'EOF' > plot_cv.R
# 读取CV error数据
cv <- read.table("cv_errors.txt")                # 读取文件
cv$K <- as.numeric(gsub("[^0-9]", "", cv$V1))    # 提取K值
cv$error <- as.numeric(cv$V2)                     # 提取CV error

# 画折线图
pdf("cv_error_plot.pdf", width=8, height=5)       # 保存为PDF
plot(cv$K, cv$error,                              # X轴K值,Y轴CV error
     type="b",                                     # 画线+点
     xlab="K (Number of ancestral populations)",   # X轴标签
     ylab="Cross-validation error",                # Y轴标签
     main="ADMIXTURE CV Error",                    # 标题
     pch=16, col="steelblue")                      # 点的样式和颜色
abline(v=cv$K[which.min(cv$error)],               # 在最小CV error处画竖线
       col="red", lty=2)                           # 红色虚线
dev.off()                                          # 关闭PDF设备
EOF
Rscript plot_cv.R  # 执行R脚本

# 最小 CV error 对应的 K 就是"最佳K"
# 但注意:如果多个K的CV error很接近,应该报告一个范围而不是单个K

第 6 步:可视化 ADMIXTURE 结果

# 方法1:用R画经典的ADMIXTURE柱状图
cat << 'EOF' > plot_admixture.R
# 读取最佳K的Q矩阵(假设K=3)
Q <- read.table("mydata_ldpruned.3.Q")    # 每行一个个体,每列一个祖先群体
fam <- read.table("mydata_ldpruned.fam")  # 读取样本信息

# 读取群体标签(需要自己准备)
# pop_info.txt 格式:样本ID  群体标签
pop <- read.table("pop_info.txt", header=FALSE)  # 读取群体信息

# 按群体排序(让同一群体的个体排在一起)
ord <- order(pop$V2)                       # 按群体名排序
Q_sorted <- Q[ord, ]                       # 排序Q矩阵
pop_sorted <- pop[ord, ]                   # 排序群体信息

# 画柱状图
pdf("admixture_K3.pdf", width=15, height=5)  # 创建宽PDF
barplot(t(as.matrix(Q_sorted)),               # 转置后画堆叠柱状图
        col=c("#E41A1C","#377EB8","#4DAF4A"), # 三种颜色对应三个祖先
        border=NA,                             # 不画柱子边框
        space=0,                               # 柱子之间无间距
        ylab="Ancestry proportion",            # Y轴标签
        main="ADMIXTURE K=3")                  # 标题

# 在底部标注群体名
# 用 tapply 计算每个群体的中间位置
mid <- tapply(1:nrow(Q_sorted), pop_sorted$V2, mean)  # 每个群体的中间位置
axis(1, at=mid, labels=names(mid), las=2, cex.axis=0.7)  # 添加X轴标签
dev.off()
EOF
Rscript plot_admixture.R  # 执行画图
# 方法2:用 pong 进行更专业的可视化(推荐)
# pong 可以自动对齐多次运行结果,避免颜色翻转问题
pip install pong  # 安装pong

# 准备pong需要的文件列表(filemap)
# 格式:K值  运行编号  Q文件路径
echo "3 1 mydata_ldpruned.3.Q" > pong_filemap.txt

# 运行pong
pong -m pong_filemap.txt \     # 输入filemap
     -i pop_info.txt \          # 群体标签文件
     -n pop_order.txt           # 群体排列顺序(可选)
# pong 会启动一个网页服务器,浏览器打开即可查看交互式结果

三、进阶操作

3.1 多次运行取稳定结果

# ADMIXTURE 使用随机种子,每次运行结果可能略有不同
# 建议每个K值运行5-10次,检查结果稳定性

for K in $(seq 1 10); do
    for rep in $(seq 1 5); do
        admixture --cv \
                  -s ${rep}${K} \     # 设置不同的随机种子
                  mydata_ldpruned.bed \
                  $K \
                  -j4
        # 重命名输出文件,避免覆盖
        mv mydata_ldpruned.${K}.Q mydata_ldpruned.K${K}.rep${rep}.Q  # 重命名Q矩阵
        mv mydata_ldpruned.${K}.P mydata_ldpruned.K${K}.rep${rep}.P  # 重命名P矩阵
    done
done

3.2 有监督模式(supervised mode)

# 如果你知道部分个体的群体归属(参考群体),可以用有监督模式
# 在 .fam 文件的第6列(表型列)标注群体编号
# 已知群体标为 1, 2, 3...;未知个体标为 -

admixture --supervised \          # 启用有监督模式
          mydata_ldpruned.bed \   # 输入文件
          3                        # K值等于已知群体数

3.3 evaladmix 评估拟合质量

# evaladmix 检查 ADMIXTURE 结果是否很好地拟合了数据
# 如果某些群体对之间的残差很大,说明模型拟合不好

# 安装 evaladmix
git clone https://github.com/GenisGE/evalAdmix.git  # 克隆仓库
cd evalAdmix && make                                  # 编译

# 运行评估
./evalAdmix -plink mydata_ldpruned \  # 输入PLINK文件前缀
            -fname mydata_ldpruned.3.P \  # P矩阵
            -qname mydata_ldpruned.3.Q \  # Q矩阵
            -o evaladmix_K3.corres        # 输出相关性残差矩阵

四、常见报错与解决

报错信息原因解决方法
Error: Invalid bed filebed/bim/fam 文件不匹配重新用 plink --make-bed 生成
SNPs with unknown positionsbim 文件中有 0 染色体--allow-extra-chr 参数
Segmentation fault内存不足或数据量太大先做 LD pruning 减少 SNP 数量
NaN in Q matrixSNP 太少或样本太少增加 SNP 数量,检查数据质量
CV error 在 K 增大时持续下降样本结构复杂或数据噪声结合 PCA 和生物学知识选择 K
多次运行结果不一致随机种子不同导致多次运行 + 用 pong/CLUMPAK 对齐
Too few SNPsLD pruning 后 SNP 太少放宽 r² 阈值(如 0.1→0.2)

五、面试高频问题

Q1:ADMIXTURE 和 STRUCTURE 有什么区别?

ADMIXTURE 用最大似然法,STRUCTURE 用贝叶斯 MCMC。ADMIXTURE 快几十倍,适合大数据;STRUCTURE 可以处理小数据但非常慢。结果解读方式类似。

Q2:怎么选择最佳 K 值?

看 CV error 最低点。但注意:(1) 如果多个 K 的 CV error 接近,报告范围而非单个 K;(2) K 值不等于"真实群体数",它受抽样、LD 结构、缺失值影响;(3) 结合 PCA、D-statistics 等交叉验证。

Q3:为什么要做 LD pruning?

ADMIXTURE 假设 SNP 之间独立。如果不做 LD pruning,高度连锁的 SNP 会让某些基因组区域的权重过大,导致结果偏向这些区域的结构信号。

Q4:ADMIXTURE 能处理低深度测序数据吗?

标准 ADMIXTURE 需要确定的基因型(hard call)。低深度数据应该用 ngsAdmix 或 PCAngsd,它们基于基因型似然值(genotype likelihoods)而不是确定基因型。


六、速查表

# === ADMIXTURE 完整流程速查 ===

# 1. VCF → PLINK
plink --vcf input.vcf.gz --make-bed --allow-extra-chr --out mydata

# 2. LD pruning
plink --bfile mydata --indep-pairwise 50 10 0.1 --out pruned
plink --bfile mydata --extract pruned.prune.in --make-bed --out data_ld

# 3. 运行 ADMIXTURE(K=1~10)
for K in $(seq 1 10); do admixture --cv data_ld.bed $K -j4 | tee log_K${K}.out; done

# 4. 提取 CV error
grep "CV" log_K*.out

# 5. 可视化
# R: barplot(t(Q), col=colors, border=NA, space=0)
# pong: pong -m filemap.txt -i pop_info.txt

参考资料:ADMIXTURE v1.3.0 官方文档、Speciation Genomics Tutorial、PopCluster (2025, Molecular Ecology Resources)、CD Genomics Workflow Guide