BioF3 组学数据分析

基因组学实践手册

BioF3 基因组学专栏导出版

导出日期:2026年6月27日

01 基因组学实践教程

基因组学研究的是 DNA 序列本身:谁的基因组里有什么变异,这些变异是否落在功能区域,以及在群体里如何分布。即便今天大多数湿实验都在转录组或单细胞这一层,基因组重测序仍然是找到疾病相关变异、做 GWAS、做群体遗传分析的起点。

本专栏打算把"拿到一批测序数据之后怎么走到变异列表"这条主线讲清楚。重点放在重测序和短读长小变异,其他方向(长读长、结构变异、甲基化等)会作为延伸而不是主干。

基因组学项目的三条典型主线

新手容易把"基因组学"当成一回事,其实它是三种很不同的项目类型:

项目类型 核心问题 数据特点 关键工具
胚系变异检测 这个人有什么遗传缺陷 单/几个样本、深度 30-50x GATK HaplotypeCaller + ClinVar
肿瘤体细胞变异 肿瘤里有什么驱动突变 配对 tumor + normal Mutect2 + maftools
群体遗传 / GWAS 这个变异在群体里怎么分布 几千-几十万样本 PLINK 2

这三条主线分析流程差很多:胚系关注致病性、肿瘤关注 VAF 和驱动基因、群体关注频率和 LD。先想清楚自己在做哪一种,再选工具,比闷头跑流水线效率高。

一个项目大致是什么样子

一个典型的 WES 或 WGS 项目会拿到若干个体的双端 FASTQ 数据。从这里到"一份可以注释、可以过滤、可以做关联分析的 VCF"之间,要走的步骤大致是:

步骤 典型产物 常用工具
质控与接头剪切 清洗后的 FASTQ FastQC、fastp、Trim Galore
参考基因组比对 sorted.bam + 索引 BWA-MEM、minimap2
重复序列标记与 BQSR 校正后的 BAM GATK MarkDuplicates、BQSR
变异检测 原始 VCF / gVCF GATK HaplotypeCaller、DeepVariant
联合基因分型 多样本 VCF GATK GenotypeGVCFs
变异过滤 高置信变异集 GATK VQSR、硬过滤
变异注释 带功能注释的 VCF VEP、ANNOVAR、SnpEff
下游分析 关联、群体结构、可视化 PLINK、R

"BWA + GATK" 是短读长小变异的事实标准,文献、社区和官方 best practices 都围绕它展开。如果只做基因型分型而不做科研级变异检测,bcftools mpileup + bcftools call 也能跑出可用结果,代码更短。

常见工具栈

这套组合在教学和小到中等规模真实项目里基本够用:

阶段 工具 运行环境
质控 FastQC、fastp、MultiQC bash
比对 BWA-MEM、minimap2 bash
BAM 处理 samtools、GATK bash
变异检测 GATK HaplotypeCaller、DeepVariant bash
变异过滤 GATK VQSR、bcftools bash
注释 VEP、ANNOVAR、SnpEff bash
群体与统计 PLINK 2、vcftools、R bash + R

长读长(PacBio、ONT)和结构变异会用到另一套工具链(minimap2、Sniffles、CuteSV 等),这里暂不展开。

推荐公开数据集

学这个专栏可以从三类数据入手:

数据集 规模 适合 入口
NA12878 / HG001 单样本,广泛验证 流程搭建、variant calling 基准 Genome in a Bottle
1000 Genomes 人群规模 群体结构、LD、祖源分析 1000 Genomes Project
GnomAD 汇总等位基因频率 变异注释、罕见变异过滤参考 gnomAD

NA12878 有 GIAB 发布的"黄金标准" VCF,可以直接用来评估你自己跑出的结果是否合理,是练习 variant calling 流程最方便的参照物。

最小可跑的例子

下面用 Bioconductor 的 VariantAnnotation 包做一次最简单的 VCF 读取和浏览。它自带一份 chr22.vcf.gz 示例,不需要联网下载:

if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager")
BiocManager::install(c("VariantAnnotation", "TxDb.Hsapiens.UCSC.hg19.knownGene"))

library(VariantAnnotation)
library(TxDb.Hsapiens.UCSC.hg19.knownGene)

# 读入包里自带的 chr22 示例 VCF
fl <- system.file("extdata", "chr22.vcf.gz", package = "VariantAnnotation")
vcf <- readVcf(fl, "hg19")
vcf

# 看一下 VCF 结构
header(vcf)
rowRanges(vcf)[1:5]

# 提取基因型信息
geno(vcf)$GT[1:5, 1:5]

# 把变异定位到基因区域
txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene
loc <- locateVariants(vcf, txdb, CodingVariants())
head(loc)

# 统计每类变异的数量(内含子、外显子、UTR 等)
all_loc <- locateVariants(vcf, txdb, AllVariants())
table(all_loc$LOCATION)

locateVariants 会把每个 VCF 记录映射到最近的基因和区域类型。table(all_loc$LOCATION) 的输出是典型的"变异区域分布"结果——UTR、外显子、内含子、基因间各多少——这也是 variant calling 报告里必写的一栏。

真实重测序项目比这段要多两件事:前半段的 BWA 比对 + GATK 变异检测流水线(要跑几个小时、要有足够磁盘)、后半段的过滤策略和多样本联合分型。但 VCF 拿到手之后的操作思路,和上面这段是一致的。

专栏模块规划

模块 主题 状态
01 数据类型:WGS vs WES vs Panel 已上线
02 BWA / GATK 比对与变异检测 已上线
03 VCF 注释与可视化 已上线
04 maftools 肿瘤突变分析(WES) 已上线
05 变异过滤与质量评估 已上线
06 群体遗传:PCA / 祖源 / LD 已上线
07 GWAS 入门 已上线
08 临床变异解读与报告 已上线

所有 8 个模块已上线。03 和 04 带可跑脚本和真实数据图。

推荐前置知识

常见误区

误区 1:以为变异越多越好

WGS 跑出来 5M 变异,99% 是已知 SNP,对你研究问题毫无意义。真正有价值的是罕见变异 + 致病变异,需要靠 ClinVar / gnomAD 过滤。"我的样本有 5M 个变异" 不是亮点。

误区 2:用 SNV-only 思路做肿瘤分析

肿瘤里 CNV、SV、染色体重排同样关键 — 漏掉这些等于半残。WGS 项目要补 Manta / GRIDSS(SV)和 ASCAT / FACETS(CNV)

误区 3:把胚系变异工具用在肿瘤上

HaplotypeCaller 假设变异在 50% 或 100% 的 reads 里(杂合或纯合)。肿瘤是异质性群体,VAF 可以是 5%、20%、80% 等任意值,必须用 Mutect2 或类似肿瘤专用 caller。

误区 4:不做 BQSR 直接 call 变异

BQSR 校正测序仪系统偏差,不做的话假阳性率提高 10-30%。GATK best practices 里这是必须步骤,不要图省事跳过。

误区 5:群体遗传项目不做 LD pruning 直接 PCA

PCA 会被高 LD 区域(HLA、着丝粒等)主导,主成分变成"局部 LD 模式"而不是真实的群体结构。PCA 前必须 LD prune(PLINK --indep-pairwise 50 5 0.2

参考资源

02 数据类型:WGS vs WES vs Panel

基因组测序有三种主要策略,选择取决于研究目的和预算:

策略 覆盖范围 数据量/样本 适用场景
WGS 全基因组 ~3Gb 30-60x, ~90GB FASTQ 结构变异、非编码区、群体遗传
WES 外显子区 ~60Mb 100-200x, ~6GB FASTQ 肿瘤体细胞突变、遗传病诊断
Panel 几十~几百个基因 500-1000x, ~1GB 临床检测、已知热点突变

WGS vs WES 的分析差异

维度 WGS WES
变异类型 SNV + Indel + SV + CNV 主要 SNV + Indel
参考区域 全基因组 需要 BED 文件定义 target 区域
覆盖度均匀性 受捕获效率影响,边缘区域覆盖低
数据分析工具 GATK / DeepVariant GATK + Mutect2(肿瘤)
下游重点 群体遗传、GWAS、SV 肿瘤驱动突变、maftools、OncoKB

肿瘤 WES 的特殊性

肿瘤样本通常配对测序(tumor + matched normal),用 Mutect2 做体细胞突变检测。输出的 MAF 文件是 maftools 的标准输入。

# Mutect2 典型调用
gatk Mutect2 \
  -R reference.fa \
  -I tumor.bam \
  -I normal.bam \
  -normal normal_sample_name \
  -O somatic.vcf.gz

# VCF -> MAF 转换
vcf2maf.pl --input-vcf somatic.vcf.gz --output-maf somatic.maf \
  --tumor-id tumor --normal-id normal --ref-fasta reference.fa

怎么选:WGS / WES / Panel 的判断逻辑

实务上的选择标准比 textbook 里复杂。一份决策表:

你的目标 选哪个 理由
找已知热点突变(EGFR、KRAS、BRAF) Panel 最便宜,深度最高(>1000x),灵敏度最好
找未知驱动突变(新癌种、罕见癌) WES 编码区全覆盖,能发现新基因
找结构变异 / CNV 整体重排 WGS Panel/WES 看不到非编码区断点
临床遗传病诊断 WES 大部分孟德尔病在编码区
群体遗传研究 WGS (或 SNP 芯片) 需要全基因组覆盖看 LD 和稀有变异
预算有限但样本量大 Panel 单价低,能多测样本
给非编码 GWAS 信号做精细定位 WGS 启动子 / 增强子区域 panel/WES 没覆盖

新人最常见错误:用 WES 找结构变异。WES 的捕获 enrichment 让 break point 上的 reads 严重不均匀,CNV / SV 在 WES 上几乎不可靠。

常见坑

坑 1:tumor-only 没有 matched normal

没有配对正常样本时,无法区分体细胞突变和胚系变异。tumor-only 模式可以跑(Mutect2 --tumor-only),但要严格用 gnomAD 频率过滤掉所有 AF > 0.001 的位点,否则结果是肿瘤 + 胚系混合。

坑 2:WES 的 BED 文件版本不一致

不同 WES 试剂盒(Agilent SureSelect / Twist / IDT xGen)有自己的 target BED,用错 BED 会让 70% 的覆盖度统计是假的。BED 必须从厂商网站下载和试剂盒版本对应的那一份。

坑 3:Panel 数据用 WGS 的过滤参数

Panel 测序深度 500-2000x,WGS 30-50x。用 WGS 的 GQ ≥ 20 阈值在 Panel 上会几乎不过滤(Panel 的 GQ 普遍很高),需要用更严格的标准比如 VAF + 链平衡。

坑 4:用错 reference fasta

GATK 要求 reference 必须有 .dict.fai 索引,且染色体顺序匹配。hg19 和 hg38 不能混用,混用会让所有变异坐标错位。

坑 5:Mutect2 跑 tumor-only 不加 PoN

Panel of Normals (PoN) 是从一批正常样本里收集的"看上去像变异但其实是测序伪影"的位点。没 PoN 的 Mutect2 假阳性率会很高,至少要做一份 50-100 个正常样本的 PoN。

下一步

接着深入

横向延伸

参考资源

03 比对与变异检测流程

从 FASTQ 到 VCF 的标准流水线。这一章给出完整的 bash 命令序列,适合在服务器上跑。

BWA-MEM 比对

# 建索引(一次性)
bwa index reference.fa

# 比对(每个样本)
bwa mem -t 8 -R "@RG\tID:sample1\tSM:sample1\tPL:ILLUMINA" \
  reference.fa sample1_R1.fq.gz sample1_R2.fq.gz \
  | samtools sort -@ 4 -o sample1.sorted.bam

samtools index sample1.sorted.bam

-R 参数加 read group 信息,GATK 后续步骤必须有。

去重复 + BQSR

# 标记 PCR 重复
gatk MarkDuplicates \
  -I sample1.sorted.bam \
  -O sample1.dedup.bam \
  -M sample1.dedup_metrics.txt

# Base Quality Score Recalibration
gatk BaseRecalibrator \
  -R reference.fa \
  -I sample1.dedup.bam \
  --known-sites dbsnp.vcf.gz \
  --known-sites mills_indels.vcf.gz \
  -O sample1.recal_table

gatk ApplyBQSR \
  -R reference.fa \
  -I sample1.dedup.bam \
  --bqsr-recal-file sample1.recal_table \
  -O sample1.recal.bam

HaplotypeCaller(胚系变异)

# 单样本模式(输出 gVCF)
gatk HaplotypeCaller \
  -R reference.fa \
  -I sample1.recal.bam \
  -O sample1.g.vcf.gz \
  -ERC GVCF

# 多样本联合分型
gatk CombineGVCFs -R reference.fa \
  -V sample1.g.vcf.gz -V sample2.g.vcf.gz \
  -O cohort.g.vcf.gz

gatk GenotypeGVCFs -R reference.fa \
  -V cohort.g.vcf.gz \
  -O cohort.vcf.gz

Mutect2(体细胞变异)

gatk Mutect2 \
  -R reference.fa \
  -I tumor.recal.bam \
  -I normal.recal.bam \
  -normal normal_sample \
  --germline-resource gnomad.vcf.gz \
  -O somatic_unfiltered.vcf.gz

gatk FilterMutectCalls \
  -R reference.fa \
  -V somatic_unfiltered.vcf.gz \
  -O somatic_filtered.vcf.gz

流水线工具

手动跑上面这些命令容易出错。推荐用 nf-core/sarek:

nextflow run nf-core/sarek \
  --input samplesheet.csv \
  --genome GRCh38 \
  --tools mutect2,haplotypecaller \
  --outdir results/

为什么 GATK Best Practices 这么麻烦

新手第一次跑这套常常想问"为什么要这么多步?" 每一步都是为了解决一个具体的假阳性来源:

步骤 解决什么 跳过会怎样
MarkDuplicates PCR 扩增产生的重复 reads duplicate 让 VAF 估计偏高,假阳性 ↑
BQSR 测序仪 quality score 系统偏差 假阳性 ↑10-30%,漏报 ↑
HaplotypeCaller local assembly 重复区域 / indel 处比对错误 indel 假阴性高
gVCF + GenotypeGVCFs 多样本联合分型校准信息 "我有变异但只在一个样本里" 漏报
VQSR / hard filter 工具固有假阳性 报告里 90% 是噪声

每一步都不是装饰。理解每一步在防什么,比死记参数更有价值。

常见坑

坑 1:忘了 read group 信息

GATK 后续步骤强制要求 BAM 里有 @RG 标签。bwa mem -R "@RG\tID:..." 一开始就要加。否则 MarkDuplicates 直接报错。后期补 RG 用 gatk AddOrReplaceReadGroups

坑 2:BWA 用了 -M 标志

老教程用 -M 让多比对 reads 标记为 secondary,但新版 GATK + Picard 期望 supplementary。用 -M 在新版 pipeline 里会让 MarkDuplicates 行为异常。不加 -M 是默认正确

坑 3:GVCF 文件多样本时手动 cat

GVCF 是结构化文件,不能直接 cat必须用 gatk CombineGVCFsGenomicsDBImport,否则下游报错。

坑 4:Mutect2 不指定 germline-resource

--germline-resource gnomad.vcf.gz 让 Mutect2 把已知胚系变异从体细胞结果里去掉。不加这个参数 tumor-normal 配对的结果还能凑合,tumor-only 模式直接错

坑 5:BAM 文件没 sort 就 dedup

MarkDuplicates 要求 BAM 已按坐标排序。bwa mem 输出的 SAM 是 read-name 顺序,要先 samtools sort -@ 4。直接 dedup 会报错或给出错误结果。

下一步

接着深入

横向延伸

参考资源

04 VCF 注释与可视化

VCF 文件拿到手之后,第一步是"每个变异落在什么基因、什么区域、有什么功能影响"。本章用 R 的 VariantAnnotation 包在内置 chr22 VCF 上演示。

真实示例

配套脚本 genome03_variant_anno_sci.R 输出 6 张图:

Rscript scripts/genomics/genome03_variant_anno_sci.R

每张图看什么

Variant type 图 1:SNV vs Indel 的数量分布。WGS/WES 里 SNV 通常占 90%+。

Region annotation 图 2:变异落在哪些基因组区域。大部分在内含子和基因间区(非编码区占基因组 98%+)。

Ti/Tv 图 3:转换/颠换比。WGS 期望 ~2.0-2.1,WES 编码区 ~3.0。偏低可能说明假阳性多。

AF spectrum 图 4:等位基因频率谱。经典 L 形:大部分变异是稀有的(低频)。

Density 图 5:chr22 上的变异密度分布。某些区域密集可能对应基因密集区或重复序列。

Coding consequence 图 6:编码区变异的功能后果(同义/错义/无义)。

下载资源

genome03_variant_anno_sci.R
8 KB
下载 VCF 注释可视化完整脚本

常见坑

坑 1:用错了 TxDb 物种 / 版本

TxDb.Hsapiens.UCSC.hg19.knownGeneTxDb.Hsapiens.UCSC.hg38.knownGene 不能混用。VCF header 里 ##reference 字段告诉你版本,先看再选 TxDb。

坑 2:变异类型只看 SNP / INDEL,忽略 MNP / SV

VCF 里还有 MNP(连续多碱基替换)、symbolic alleles(<DEL> / <INS> / <DUP> 这种 SV)等。isSNV(vcf) 只筛 SNP,简单脚本会漏掉一半。要按需判断每种类型。

坑 3:Ti/Tv 全队列算一个值

不同基因组区域 Ti/Tv 不一样:编码区高(~3.0),非编码区低(~2.0)。应该分区域看,混在一起的 Ti/Tv 没诊断价值。

坑 4:等位基因频率谱用 INFO/AF 直接画

VCF 的 INFO/AF 是 caller 估计值,不是真实群体频率。要看群体 AF 必须从 gnomAD / 1KG 数据库查,不能用 VCF 自带的 AF 当群体频率用。

坑 5:locateVariants 把 NA 当成"基因间"

部分变异 LOCATION 是 NA(坐标超出 TxDb 覆盖范围、未知 transcript),不是"基因间"。统计时要单独处理 NA,不然分布图被 NA 拉偏。

下一步

接着深入

横向延伸

参考资源

05 maftools 肿瘤突变分析

maftools 是肿瘤外显子组(WES)分析里最常用的 R 包。它读入 MAF 格式的体细胞突变文件,一套函数出完整的突变景观图、驱动基因分析、突变签名等。

本章用 maftools 自带的 TCGA LAML(急性髓系白血病,193 个样本)数据演示。

MAF 格式

MAF(Mutation Annotation Format)是 TCGA 定义的标准格式,每行一个突变,关键列:

含义
Hugo_Symbol 基因名
Chromosome / Start_Position / End_Position 基因组坐标
Variant_Classification Missense / Nonsense / Frame_Shift 等
Variant_Type SNP / INS / DEL
Tumor_Sample_Barcode 样本 ID
Protein_Change 蛋白变化(如 p.R882H)

从 VCF 转 MAF 用 vcf2maf.pl(需要 VEP 注释)。

真实示例

配套脚本 genome04_maftools_sci.R 输出 6 张图:

Rscript scripts/genomics/genome04_maftools_sci.R

每张图看什么

MAF summary 图 1:MAF 总览 dashboard。左上:每个样本的突变数;右上:变异分类分布;左下:变异类型;右下:SNV 碱基替换类型。一张图看完整个队列的突变概况。

Oncoplot 图 2:Oncoplot(突变景观图)。每列一个样本,每行一个基因(按突变频率排序)。颜色代表突变类型。这是肿瘤基因组文章里最核心的一张图 —— 一眼看出哪些基因在队列里反复突变。

LAML 里 FLT3、DNMT3A、NPM1 是 top 3 驱动基因,和文献完全一致。

Lollipop DNMT3A 图 3:DNMT3A 的 lollipop 图。横轴是蛋白结构域,每个棒棒糖代表一个突变位点,高度代表该位点在队列里出现的次数。R882 是 DNMT3A 的热点突变,在 AML 里反复出现。

Somatic interactions 图 4:基因间的共突变 / 互斥关系。绿色 = 共现(co-occurrence),粉色 = 互斥(mutual exclusivity)。互斥的基因对可能在同一条通路上(突变一个就够了)。

TMB distribution 图 5:肿瘤突变负荷(TMB)分布。AML 是低 TMB 肿瘤(中位 ~10 个突变/样本),和黑色素瘤、肺癌(几百个)形成对比。TMB 是免疫治疗响应的预测指标之一。

Ti/Tv 图 6:转换/颠换比(按样本)。Ti/Tv 偏离正常范围可能提示特定的突变过程(如 APOBEC 活性会增加 C>T 转换)。

核心代码

library(maftools)

laml <- read.maf(
  maf = system.file("extdata", "tcga_laml.maf.gz", package = "maftools"),
  clinicalData = system.file("extdata", "tcga_laml_annot.tsv", package = "maftools")
)

plotmafSummary(laml, dashboard = TRUE)
oncoplot(laml, top = 10)
lollipopPlot(laml, gene = "DNMT3A", AACol = "Protein_Change")
somaticInteractions(laml, top = 15)

套到自己数据上

read.maf() 的路径换成自己的 MAF 文件即可。如果只有 VCF:

# VCF -> MAF(需要 VEP + vcf2maf)
vcf2maf.pl --input-vcf somatic.vcf.gz --output-maf somatic.maf \
  --tumor-id TUMOR --normal-id NORMAL --ref-fasta hg38.fa \
  --vep-path /path/to/vep --vep-data /path/to/vep_cache

下载资源

不想本地装环境?在 BioF3 上跑

常见坑

坑 1:MAF 文件 Variant_Classification 列里有 "Unknown"

部分 vcf2maf 输出会有 Unknown 这一类。maftools 默认会算 TMB 时把它纳入,让 TMB 虚高。read.maf(vc_nonSyn = c("Missense", "Nonsense", ...)) 显式指定哪些类型算入。

坑 2:oncoplot top N 全是热点已知基因

如果队列样本量大、TMB 高,top = 10 出来的可能全是 TP53、KRAS、PIK3CA 这种泛癌驱动。真正的发现要看 top = 50 之外的"队列特异"基因,配合 OncoKB 注释看新意。

坑 3:lollipop 图找不到结构域注释

某些少见基因 maftools 找不到 protein domain 数据库。可以用 lollipopPlot(refSeqID = "NM_xxx") 显式指定 isoform;或换 MutationMapper(cBioPortal 在线工具)。

坑 4:somaticInteractions 跑完没显著结果

somaticInteractions 默认 Fisher test + BH 校正,小队列(< 50 样本)几乎不可能显著。这不是分析错,是统计学限制。报告时把 p < 0.1 的也列出来,标"待验证"。

坑 5:把 MAF 直接转 VCF 做下游

MAF → VCF 不是无损:MAF 里有些列(VAF、读数分配)VCF 没有;VAF 在 VCF 里要看 FORMAT/AD。做肿瘤分析始终保持 MAF 为主,VCF 只在过滤步骤用

下一步

接着深入

横向延伸

参考资源

06 变异过滤与质量评估

原始 VCF 里有大量假阳性。过滤策略决定了最终结果的可靠性。

VQSR vs 硬过滤

方法 适用 原理
VQSR 样本量 > 30、WGS 用已知变异集训练机器学习模型
硬过滤 样本量少、WES、Panel 手动设阈值(QD、FS、MQ 等)

硬过滤典型参数

# SNP 过滤
gatk VariantFiltration -R ref.fa -V raw.vcf.gz \
  --filter-expression "QD < 2.0" --filter-name "LowQD" \
  --filter-expression "FS > 60.0" --filter-name "HighFS" \
  --filter-expression "MQ < 40.0" --filter-name "LowMQ" \
  --filter-expression "MQRankSum < -12.5" --filter-name "LowMQRS" \
  --filter-expression "ReadPosRankSum < -8.0" --filter-name "LowRPRS" \
  -O filtered_snps.vcf.gz

# Indel 过滤
gatk VariantFiltration -R ref.fa -V raw.vcf.gz \
  --filter-expression "QD < 2.0" --filter-name "LowQD" \
  --filter-expression "FS > 200.0" --filter-name "HighFS" \
  --filter-expression "ReadPosRankSum < -20.0" --filter-name "LowRPRS" \
  -O filtered_indels.vcf.gz

质量评估指标

一份 VCF 的诊断 checklist

拿到一份新 VCF 时,按这个顺序快速判断质量:

  1. 总变异数:WGS ~4-5M,WES ~50-100k,Panel <1000。数量异常意味着流水线有问题
  2. Ti/Tv:上面已说,偏离正常意味着假阳性
  3. dbSNP 重叠率:> 95% 健康,< 90% 有问题
  4. Het/Hom:偏离 1.5-2.0 可能样本污染或近交
  5. Singleton 比例:单次出现的变异比例。WGS 应 < 5%,过高说明假阳性
  6. 覆盖度均匀性:变异 DP 分布的 CV 应该 < 0.5

这 6 个 5 分钟能查完,比单纯看 padj 信息量大得多。

常见坑

坑 1:VQSR 对小样本量直接套

VQSR 需要 30+ 样本才能学出可靠模型。< 30 样本必须用硬过滤,硬上 VQSR 结果不可信。

坑 2:硬过滤参数照搬 GATK 推荐值

GATK 推荐值是 WGS 的经验值,对 WES、Panel、低深度数据不一定合适。先看自己数据 QD / FS / MQ 的分布,再选阈值。

坑 3:过滤了 PASS 之外的所有

GATK Best Practices 把过滤标记写进 FILTER 列(PASS 或具体过滤名),不是删除bcftools view -f PASS 才能拿到只有 PASS 的子集。直接读完整 VCF 后忘了筛 FILTER 列是常见错误。

坑 4:用 GQ 阈值过滤 INDEL

GQ(genotype quality)对 SNP 比较合理,INDEL 的 GQ 经常很低(call indel 本身难),用 GQ ≥ 20 会丢一半真 INDEL。INDEL 用 QD + FS 过滤更合适。

坑 5:trio 项目不查 Mendelian error

有父母和子代的 trio 数据,子代不符合孟德尔遗传的位点几乎都是假阳性vcftools --mendel 可以查这个错误率,超过 1% 说明数据质量有问题。

下一步

接着深入

横向延伸

参考资源

07 群体遗传:PCA / 祖源 / LD

群体遗传分析用大量个体的基因型数据回答"这些人从哪来、彼此什么关系、哪些位点受到选择"。

常用工具

工具 用途
PLINK 2 数据管理、QC、PCA、关联分析
ADMIXTURE 祖源成分估计(K 群体)
vcftools VCF 统计(Fst、pi、Tajima's D)
EIGENSOFT PCA + 群体结构

PCA 分析

# VCF -> PLINK 格式
plink2 --vcf cohort.vcf.gz --make-bed --out cohort

# LD pruning(去掉高 LD 的 SNP,避免 PCA 被局部 LD 主导)
plink2 --bfile cohort --indep-pairwise 50 5 0.2 --out pruned
plink2 --bfile cohort --extract pruned.prune.in --make-bed --out cohort_pruned

# PCA
plink2 --bfile cohort_pruned --pca 10 --out cohort_pca

输出 cohort_pca.eigenvec 就是每个样本的 PC1~PC10 坐标,用 R 画散点图。

ADMIXTURE 祖源分析

# 跑 K=2 到 K=6
for K in 2 3 4 5 6; do
  admixture --cv cohort_pruned.bed $K | tee log_K${K}.out
done

# 选最优 K:看 CV error 最低的那个
grep "CV error" log_K*.out

LD 衰减

# 计算 LD(r²)随距离的衰减
plink2 --bfile cohort --ld-window-r2 0 --ld-window 1000 --ld-window-kb 500 \
  --out ld_decay

LD 衰减速度反映群体的有效群体大小和重组率。

群体遗传分析的核心问题

在跑工具之前先想清楚要回答什么。这类项目大致是三类问题:

问题 关键分析 解读重点
这个群体有几个亚群? PCA + ADMIXTURE PC1/PC2 分布 + K 选择
我的样本祖源混杂吗? ADMIXTURE 每个个体的成分比例
哪些区域受到自然选择? Fst / iHS / nSL 极端值区域
群体何时分化? PSMC / SMC++ 时间序列推断
人口规模怎么变化? PSMC / Stairway Plot 历史 Ne 曲线

新人最常见错误:跑了 PCA 看到分群就完事,没思考"为什么这样分群"。PCA 只给坐标,不给解释。

常见坑

坑 1:PCA 不做 LD pruning

不 prune 时 PCA 会被 HLA、着丝粒等高 LD 区域主导,PC1 变成 "HLA 单体型聚类" 而不是真实群体结构--indep-pairwise 50 5 0.2 是必须步骤。

坑 2:ADMIXTURE 跑一个 K 就报告

K 选择不是凭感觉。至少跑 K=2 到 K=10,看 CV error 最低的那个。CV error 平的话说明数据本身就没明显结构,硬选 K 没意义。

坑 3:用相关样本做群体遗传

第一代亲属的样本会扭曲所有群体结构估计。先用 PLINK --king-cutoff 0.0884 删掉 2 度以内亲属,再做下游分析。

坑 4:全样本一起 PCA 后才发现混杂

不同祖源的样本应该分别先做 QC,再一起跑分析。混在一起做 QC 时 MAF 阈值会被群体结构干扰。

坑 5:Fst 计算用了 SNV 全集

Fst 应该排除单态位点(MAF = 0)和高缺失率位点。vcftools --maf 0.05 --max-missing 0.95 是标准过滤。不过滤直接算 Fst 噪声很大。

下一步

接着深入

横向延伸

参考资源

08 GWAS 入门

全基因组关联分析(GWAS)找的是"哪些基因组位点和某个表型(疾病、身高、药物响应)有统计学关联"。

基本流程

基因型数据(PLINK 格式)+ 表型文件
  → QC(MAF、HWE、缺失率、亲缘关系)
  → 关联检验(线性/逻辑回归,校正 PC)
  → Manhattan plot + QQ plot
  → 显著位点注释
# 二分类表型(case/control)
plink2 --bfile cohort \
  --pheno phenotype.txt \
  --covar covariates.txt \
  --glm \
  --out gwas_results

# 输出 gwas_results.PHENO1.glm.logistic.hybrid

Manhattan plot

library(qqman)

results <- read.table("gwas_results.PHENO1.glm.logistic.hybrid",
                      header = TRUE)
manhattan(results, chr = "CHROM", bp = "POS", p = "P", snp = "ID",
          suggestiveline = -log10(1e-5), genomewideline = -log10(5e-8))

QQ plot

QQ plot 检查 p 值的整体膨胀(genomic inflation factor λ)。λ > 1.1 说明有群体分层或其他混杂没控制好。

qq(results$P)

常见坑

补充几条常见误判:

坑:样本量不足直接跑 GWAS

GWAS 需要大样本量(至少几千,理想几万)才能稳定检测到 OR ~1.1 的弱效应。< 1000 样本跑 GWAS 几乎不可能找到 5e-8 显著位点,先评估 power 再决定要不要做。

坑:不做 HWE 过滤

显著偏离 Hardy-Weinberg 平衡的位点通常是基因型分型错误。case/control 设计中只在 control 样本里检查 HWE(case 因为关联本身可能偏离 HWE)。

坑:QQ plot 严重 inflation 直接发表

λ > 1.05 通常说明群体分层没控制好。多加几个 PC 做协变量,重新跑直到 λ 回归 1.0 附近。

坑:找到一个显著 SNP 就当成 causal variant

一个显著信号可能对应一个 LD block 里的几十个相关 SNP,**真正的 causal 变异需要 fine-mapping(FINEMAP / SUSIE)**或功能验证(eQTL、CRISPR)。

坑:忽略 imputation 质量

INFO score < 0.3 的 imputed 变异不可信。imputation 后必须 --info 0.3 过滤,不然假阳性堆积。

下一步

接着深入

横向延伸

参考资源

09 临床变异解读与报告

从"一份 VCF"到"能给临床医生看的报告",中间需要变异分级、数据库查询和标准化报告格式。

ACMG 变异分级

美国医学遗传学学会(ACMG)把胚系变异分为 5 级:

级别 含义 行动
Pathogenic 致病 报告 + 临床干预
Likely pathogenic 可能致病 报告
VUS 意义未明 报告但不做临床决策
Likely benign 可能良性 通常不报告
Benign 良性 不报告

常用注释数据库

数据库 内容
ClinVar 变异-疾病关联(NCBI 维护)
gnomAD 人群等位基因频率
OncoKB 肿瘤驱动突变 + 药物靶点
COSMIC 肿瘤体细胞突变数据库
InterVar 自动化 ACMG 分级工具

VEP 注释 + ClinVar

vep --input_file variants.vcf \
    --output_file annotated.vcf \
    --cache --dir_cache /path/to/vep_cache \
    --assembly GRCh38 \
    --everything \
    --plugin ClinVar,/path/to/clinvar.vcf.gz

报告模板

临床报告通常包含:

  1. 患者信息 + 检测方法
  2. 阳性发现(Pathogenic / Likely pathogenic 变异)
  3. VUS 列表
  4. 质量指标(覆盖度、Ti/Tv)
  5. 方法学描述
  6. 局限性声明

肿瘤报告的特殊性

肿瘤报告额外需要:

临床报告 vs 科研分析的关键差异

科研分析容易把"显著"或"有趣"当成结论,临床报告则要回答"这个发现能不能影响治疗 / 诊断决策"。差异:

维度 科研 临床
假阳性容忍度 中(5% FDR 即可) 极低(VUS 都要谨慎报告)
重复实验 多数情况下可以补 一份样本一次报告
VUS 处理 列出来供后续研究 报告但明确标"意义未明"
肿瘤 VAF 通常不强调 必须报告,影响治疗决策
数据库版本 用最新即可 必须冻结,可追溯

报告里最重要的句子:明确局限性。"本检测使用 ABC 试剂盒,覆盖 X 个基因 Y% 的 coding region,对 SV / CNV / 重复扩增不敏感"。这种话说清楚,临床医生才能正确解读"阴性结果"的含义。

常见坑

坑 1:把 dbSNP 收录当成"良性"

dbSNP 包含所有报道过的变异,不代表良性。判断良性要看 ClinVar 的 Benign / Likely benign 等明确分级 + gnomAD 群体高频。

坑 2:用错版本的 ClinVar

ClinVar 月更,临床报告必须冻结使用日期。不要每次跑都用 latest,那样无法回溯历史结论。

坑 3:VUS 当成"基本没事"沟通

VUS 字面意思是 "意义未明",但实务上很多临床医生当成"良性偏倾向"。报告里要明确写"VUS 不应影响临床决策",避免误解。

坑 4:不区分胚系和体细胞

有些肿瘤变异其实是胚系(如 BRCA1 致病变异),漏掉胚系判断会让患者亲属错过预防性筛查。Tumor + Normal 配对是必须的。

坑 5:报告里没有 raw QC 信息

只给变异列表不给覆盖度 / Ti/Tv / 比对率,复核者没法判断阴性结果是否可靠。报告附录至少包含每个基因的 mean coverage 和 callable region 比例。

下一步

基因组学专栏 9 篇到这里完成。

接着深入

横向延伸

参考资源