跳转至

群体分化分析 — Fst 计算与解读

一句话概述:Fst 衡量群体间遗传分化程度(0=无分化,1=完全分化),是群体遗传学中最基本、最常用的统计量,可用 VCFtools、PLINK 和 PopGenome 计算。


核心知识点速查表

概念白话解释
Fst(固定指数)群体间遗传变异占总变异的比例
Fst = 0两个群体无分化(像一个群体)
Fst = 1两个群体完全分化(无共享等位基因)
Weir & Cockerham Fst校正了样本量偏差的 Fst 估计方法
Hudson Fst另一种 Fst 估计,适合不等样本量
滑动窗口 Fst沿基因组滑动计算局部 Fst,检测分化区域
Fst outlierFst 异常高的基因组区域,可能受歧化选择
PBS群体分支统计量,基于 Fst 检测特定谱系的选择

一、Fst 的概念(白话版)

比喻:假设有两个学校(群体),每个学生有不同的手环颜色(等位基因)。如果两个学校的手环颜色分布一样(红色30%、蓝色70%),那 Fst=0。如果学校A全是红色、学校B全是蓝色,那 Fst=1。

Fst 的经验解读: - Fst < 0.05 → 分化很小(同一物种不同群体) - 0.05~0.15 → 中等分化 - 0.15~0.25 → 大分化 - Fst > 0.25 → 非常大的分化(可能不同亚种)


二、方法 1:VCFtools 计算 Fst

# VCFtools 是计算 Fst 最简单的方法

# 安装
conda install -c bioconda vcftools  # conda安装

# 准备群体标签文件(每行一个样本名)
echo -e "sample1\nsample2\nsample3" > pop1.txt   # 群体1样本列表
echo -e "sample4\nsample5\nsample6" > pop2.txt   # 群体2样本列表

# 计算全基因组平均 Fst(Weir & Cockerham方法)
vcftools --gzvcf input.vcf.gz \        # 输入VCF
         --weir-fst-pop pop1.txt \     # 群体1
         --weir-fst-pop pop2.txt \     # 群体2
         --out pop1_vs_pop2            # 输出前缀

# 输出文件:pop1_vs_pop2.weir.fst
# 格式:CHROM  POS  WEIR_AND_COCKERHAM_FST
# 最后一行显示全基因组加权平均Fst

# 滑动窗口 Fst(检测高分化区域)
vcftools --gzvcf input.vcf.gz \
         --weir-fst-pop pop1.txt \
         --weir-fst-pop pop2.txt \
         --fst-window-size 50000 \     # 窗口大小50kb
         --fst-window-step 25000 \     # 步长25kb
         --out pop1_vs_pop2_window     # 输出前缀

# 输出文件:pop1_vs_pop2_window.windowed.weir.fst
# 格式:CHROM  BIN_START  BIN_END  N_VARIANTS  WEIGHTED_FST  MEAN_FST

# PLINK 2.0 支持 Fst 计算

# 准备群体信息(在 .fam 文件的 FID 列标注群体)
# 或使用 --within 参数指定群体分组

# 生成群体分配文件
cat << 'EOF' > clusters.txt
sample1  sample1  pop1
sample2  sample2  pop1
sample3  sample3  pop2
sample4  sample4  pop2
EOF

# 计算 Fst
plink2 --vcf input.vcf.gz \
       --fst CATPHENO \              # 分类表型(群体分组)
       --within clusters.txt \        # 群体分配文件
       --out fst_result               # 输出前缀

# PLINK 1.9 版本
plink --bfile mydata \
      --fst \                          # 计算Fst
      --within clusters.txt \
      --out fst_result

四、Fst Manhattan 图可视化

# ========== R脚本:Fst Manhattan plot ==========

# 读取滑动窗口Fst结果
fst <- read.table("pop1_vs_pop2_window.windowed.weir.fst",
                   header=TRUE)                      # 读取VCFtools输出

# 处理负值(Weir & Cockerham Fst 可以为负,设为0)
fst$WEIGHTED_FST[fst$WEIGHTED_FST < 0] <- 0         # 负值设为0

# 为每条染色体分配颜色
fst$CHR <- as.numeric(gsub("chr", "", fst$CHROM))    # 染色体编号

# 计算全基因组位置
fst$cum_pos <- 0                                     # 初始化
chr_sizes <- tapply(fst$BIN_END, fst$CHR, max)       # 每条染色体的大小
offset <- cumsum(c(0, chr_sizes[-length(chr_sizes)])) # 偏移量
for(i in seq_along(unique(fst$CHR))) {
    chr <- unique(fst$CHR)[i]
    fst$cum_pos[fst$CHR == chr] <- fst$BIN_START[fst$CHR == chr] + offset[i]
}

# 画 Manhattan plot
pdf("Fst_manhattan.pdf", width=14, height=5)
plot(fst$cum_pos / 1e6,                             # X轴:位置(Mb)
     fst$WEIGHTED_FST,                                # Y轴:Fst
     pch=20, cex=0.5,                                # 小点
     col=ifelse(fst$CHR %% 2 == 0,                  # 奇偶染色体不同颜色
                "steelblue", "gray50"),
     xlab="Genomic position (Mb)",                    # X轴标签
     ylab=expression(F[ST]),                          # Y轴标签(下标ST)
     main="Genome-wide Fst: Pop1 vs Pop2")           # 标题

# 添加 top 1% 阈值线
threshold <- quantile(fst$WEIGHTED_FST, 0.99, na.rm=TRUE)  # top 1%
abline(h=threshold, col="red", lty=2)                       # 红色虚线
dev.off()

五、成对 Fst 矩阵与热图

# 当有多个群体时,计算成对 Fst 矩阵
# 假设已经用 VCFtools 计算了所有群体对的 Fst

# 构建 Fst 矩阵
pops <- c("PopA", "PopB", "PopC", "PopD", "PopE")    # 群体名列表
n <- length(pops)
fst_matrix <- matrix(0, n, n, dimnames=list(pops, pops))  # 初始化矩阵

# 填入 Fst 值(从 VCFtools 输出中提取加权平均 Fst)
fst_matrix["PopA", "PopB"] <- 0.05
fst_matrix["PopA", "PopC"] <- 0.12
fst_matrix["PopA", "PopD"] <- 0.08
fst_matrix["PopB", "PopC"] <- 0.15
fst_matrix["PopB", "PopD"] <- 0.10
fst_matrix["PopC", "PopD"] <- 0.03
# ... 填入所有成对 Fst
fst_matrix <- fst_matrix + t(fst_matrix)               # 对称化

# 画热图
library(pheatmap)                                        # 加载pheatmap包
pdf("Fst_heatmap.pdf", width=8, height=7)
pheatmap(fst_matrix,                                     # Fst矩阵
         display_numbers=TRUE,                           # 显示数值
         number_format="%.3f",                           # 3位小数
         color=colorRampPalette(c("white","orange","red"))(50),  # 颜色
         main="Pairwise Fst between populations")        # 标题
dev.off()

六、PBS(群体分支统计量)

# PBS 基于三个群体的 Fst 计算特定谱系的分化
# PBS 高值 → 该谱系经历了强选择

# PBS 计算公式:
# T_AB = -log(1 - Fst_AB)    # 分化时间的代理
# PBS_A = (T_AB + T_AC - T_BC) / 2

# 用R计算PBS
cat << 'EOF' > calc_pbs.R
# 读取三个群体对的窗口 Fst
fst_AB <- read.table("popA_vs_popB.windowed.weir.fst", header=TRUE)
fst_AC <- read.table("popA_vs_popC.windowed.weir.fst", header=TRUE)
fst_BC <- read.table("popB_vs_popC.windowed.weir.fst", header=TRUE)

# Fst 负值设为 0
fst_AB$WEIGHTED_FST[fst_AB$WEIGHTED_FST < 0] <- 0
fst_AC$WEIGHTED_FST[fst_AC$WEIGHTED_FST < 0] <- 0
fst_BC$WEIGHTED_FST[fst_BC$WEIGHTED_FST < 0] <- 0

# 确保 Fst < 1(避免 log(0))
cap_fst <- function(x) pmin(x, 0.9999)              # 限制最大值
T_AB <- -log(1 - cap_fst(fst_AB$WEIGHTED_FST))      # 转换为T
T_AC <- -log(1 - cap_fst(fst_AC$WEIGHTED_FST))
T_BC <- -log(1 - cap_fst(fst_BC$WEIGHTED_FST))

# 计算 PBS(以群体A为焦点)
PBS_A <- (T_AB + T_AC - T_BC) / 2                    # PBS公式

# 输出结果
result <- data.frame(CHROM=fst_AB$CHROM,
                     BIN_START=fst_AB$BIN_START,
                     BIN_END=fst_AB$BIN_END,
                     PBS=PBS_A)
write.table(result, "PBS_popA.txt", row.names=FALSE, quote=FALSE, sep="\t")
EOF
Rscript calc_pbs.R

七、常见报错与解决

报错信息原因解决方法
Fst 为负值Weir & Cockerham 方法在分化极小时可以为负正常现象,分析时设为 0
No individuals in population群体文件中的样本名与VCF不匹配检查样本名拼写
全基因组 Fst 接近 0两个群体实际没什么分化正常结果,不是错误
滑动窗口中有大量 NA某些窗口中 SNP 太少减小窗口大小或用更密的SNP
Fst > 0.5 但物种一样群体确实分化很大或数据有问题检查是否有批次效应

八、面试高频问题

Q1:Fst 和遗传距离的区别?

Fst 衡量群体间分化比例,遗传距离(如 Nei's D)衡量两个群体间的绝对差异。Fst 受群体大小和迁移率影响,遗传距离更多反映分化时间。Fst 适合比较同一物种的群体,遗传距离适合物种间比较。

Q2:怎么用 Fst 检测自然选择?

Fst outlier 方法:在全基因组计算 Fst,找出 Fst 异常高的区域。这些区域可能受歧化选择(不同群体适应不同环境)。常用工具:BayeScan、OutFLANK、pcadapt。

Q3:Weir & Cockerham Fst 为什么可以是负数?

这是统计估计量,当群体内变异大于群体间变异时(即实际无分化),估计值可以为负。负值应解读为 Fst=0(无分化)。


九、速查表

# === Fst 计算速查 ===

# VCFtools 单SNP Fst
vcftools --gzvcf in.vcf.gz --weir-fst-pop pop1.txt --weir-fst-pop pop2.txt --out fst

# VCFtools 滑动窗口 Fst
vcftools --gzvcf in.vcf.gz --weir-fst-pop pop1.txt --weir-fst-pop pop2.txt \
         --fst-window-size 50000 --fst-window-step 25000 --out fst_window

# 多群体成对 Fst(批量计算)
for p1 in popA popB popC; do
  for p2 in popA popB popC; do
    if [ "$p1" \< "$p2" ]; then
      vcftools --gzvcf in.vcf.gz --weir-fst-pop ${p1}.txt --weir-fst-pop ${p2}.txt --out ${p1}_${p2}
    fi
  done
done

# Fst 解读标准:
# < 0.05  → 很小分化
# 0.05~0.15 → 中等分化
# 0.15~0.25 → 大分化
# > 0.25 → 非常大分化

参考资料:Weir & Cockerham 1984、VCFtools文档、PLINK 2.0文档、Yi et al. 2010 PBS方法