bedtools区间操作:intersect/merge/coverage/closest

1579 字
8 分钟
bedtools区间操作:intersect/merge/coverage/closest

ChIP-seq 的 peak 落在哪些基因的 promoter 上?两个 peak set 有多少重叠?每个外显子的覆盖深度是多少?这些问题都一个答案:bedtools

bedtools 的官方文档有 20+ 个子命令,但日常 90% 的场景只需要 5 个。本文覆盖最常用的 5 个子命令:intersectmergecoverageclosestgenomecov,附带输出解读和常见坑。

实测环境:Debian 13,bedtools v2.31.1,Conda bioconda 安装。

1. BED 格式——先搞懂你操作的对象#

BED(Browser Extensible Data)是 bedtools 的默认输入格式,最简单:

chr1 100 500 geneA 0 +
chr1 600 900 geneB 0 -

BED 最少 3 列(chrom, start, end),常见到 6 列:

字段注意
1chrom染色体名,跟参考基因组一致
2start0-based(第一个碱基的位置是0)
3end0-based,不包含该位置
4name基因名/peak ID
5score0-1000,可忽略
6strand+-

最重要的一点——BED 是 0-based,跟人类直觉的 1-based 不同:

坐标系统第1个碱基区间 [1,10] 的含义工具
0-based位置0第1到第10个碱基bedtools, BAM, bigWig
1-based位置1第1到第10个碱基SAM, GFF, VCF

踩坑: 如果你从 GFF(1-based)手动转 BED,需要把 start 减 1:bed_start = gff_start - 1

2. intersect——求交集,最核心的功能#

2.1 基础用法#

Terminal window
# 基因A(genes.bed)和peak(peaks.bed)在哪些区域重叠?
bedtools intersect -a genes.bed -b peaks.bed

输出:genes.bed 中与 peaks.bed 有重叠的行。

2.2 控制重叠策略——最容易被忽略的参数#

默认情况下,只要有 1bp 重叠就算 hit。但生信中常常需要”至少 50% 重叠”:

Terminal window
# 要求基因区域至少50%被peak覆盖
bedtools intersect -a genes.bed -b peaks.bed -f 0.5
# 要求重叠>=100bp
bedtools intersect -a genes.bed -b peaks.bed -F 0.5 -e

-f 的含义是:重叠区域占 -a 区域的至少 1bp。具体公式:

overlap_ratio=overlap_lengthlength_of_aoverlap\_ratio = \frac{overlap\_length}{length\_of\_a}

-f 0.5 即要求 overlap_ratio ≥ 50%。

几个常用组合:

参数含义场景
-f 0.5overlap占A的≥50%peak注释到基因
-F 0.5overlap占B的≥50%基因筛选被peak完全覆盖的
-uA中至少有1个B重叠即输出去重模式,A每行最多输出一次
-v反向:输出没重叠的找”没被peak覆盖的基因”
-wa -wb同时输出A和B的行想知道”哪个peak落在哪个基因”

2.3 实战:peak 注释到基因 promoter#

Terminal window
# 先扩展promoter区域(TSS±2000bp作为promoter)
bedtools slop -i genes.bed -g chrom.sizes -b 2000 > promoters.bed
# 求peak和promoter的交集
bedtools intersect -a peaks.bed -b promoters.bed -wa -wb > peak_promoter.txt

2.4 输出解读#

实测运行 intersect -wa -wb 的输出:

chr1 150 450 peak1 100 chr1 100 500 geneA 0 +
chr1 580 850 peak2 80 chr1 600 900 geneB 0 -

每一行前几列是 peak 信息(-wa),后面是基因信息(-wb)。如果想知道 overlap 的精确区间,用 -wo 额外输出重叠长度:

Terminal window
bedtools intersect -a genes.bed -b peaks.bed -wa -wb -wo

3. merge——合并重叠区域#

ChIP-seq 的原始 peak 经常有多个相邻 peak 实际上来自同一个结合事件。merge 把它们合起来:

Terminal window
# 基础合并
bedtools merge -i peaks.bed
# 合并时要求重叠≥100bp才算连接
bedtools merge -i peaks.bed -d 100
# 合并并保留统计信息(如:合并了多少个原始peak)
bedtools merge -i peaks.bed -c 4,5 -o count,sum

-c 4,5 表示对第4列做 count(多少个原始peak)、第5列做 sum(总信号强度)。

4. coverage——计算覆盖度#

这在 RNA-seq 中用于计算每个基因的 reads 覆盖情况:

Terminal window
bedtools coverage -a genes.bed -b reads.bed

输出解读(每列含义):

chr1 100 500 geneA 0 + 1 300 400 0.7500000
│ │ │ │
reads数 ───────┘ │ │ │
covered bases ──────────┘ │ │
gene length ───────────────┘ │
coverage ratio ────────────────────────┘

coverage_ratio=covered_basesgene_lengthcoverage\_ratio = \frac{covered\_bases}{gene\_length}

如果 coverage_ratio = 0.75,说明该基因 75% 的区域有 reads 覆盖。

生信场景: RNA-seq 的基因表达量化(老的 featureCounts 前身就是类似逻辑),或者 ChIP-seq 的 peak 富集度评估。

5. closest——找最近邻#

“每个基因 TSS 最近的 ChIP-seq peak 是哪个?”

Terminal window
bedtools closest -a genes.bed -b peaks.bed -d

-d 输出额外一列:两个区间之间的距离(bp)。如果重叠则为 0。

6. slop——扩展/收缩区间#

Terminal window
# 每个基因上下游各扩展200bp
bedtools slop -i genes.bed -g chrom.sizes -b 200
# 只向上游扩展(5'方向)
bedtools slop -i genes.bed -g chrom.sizes -l 500 -r 0
# 对于正链基因,-l 代表上游(5'端);对于负链基因,自动翻转
# 用 -s 参数根据 strand 自动判断方向:
bedtools slop -i genes.bed -g chrom.sizes -l 2000 -r 500 -s

注意: -g chrom.sizes(染色体大小文件)是必须的——否则 slop 不知道染色体边界在哪里,可能导致区间超出染色体范围。

chrom.sizes 文件制作:

Terminal window
samtools faidx ref.fa
cut -f1,2 ref.fa.fai > chrom.sizes

7. genomecov——生成覆盖轨迹#

生成全基因组的覆盖度 bedGraph,之后可转为 bigWig 上传到 UCSC:

Terminal window
bedtools genomecov -i reads.bed -g chrom.sizes -bg > coverage.bedgraph
# -bg 输出 bedGraph 格式
# -bga 连零覆盖区域也输出(文件更大但更完整)
# -split 对包含N>CIGAR的BAM输入时,避免把intron区域也算进去

转 bigWig:

Terminal window
bedGraphToBigWig coverage.bedgraph chrom.sizes coverage.bw

8. 踩坑记录#

坑1:BED 坐标 0-based vs 1-based 搞混#

症状:注释时发现偏移了 1bp。

排查:检查你的输入是 BED(0-based)还是 GFF(1-based)。不确定就用 head 看区间长度是否等于 end-start。对 BED 来说这是对的,对 GFF 来说 end-start+1 才是实际长度。

坑2:染色体名不匹配#

症状:intersect 输出为空,明明两个文件都有 chr1。

原因:BED A 写的是 chr1,BED B 写的是 1。bedtools 把它们当不同染色体。

Terminal window
# 查看双方用了什么染色体名
cut -f1 genes.bed | sort -u
cut -f1 peaks.bed | sort -u

坑3:sort-buffer-size 不够导致运行极慢#

bedtools 处理大型 BED 文件时,如果没排序且没指定 sort 参数会巨慢:

Terminal window
# 先排序再操作
sort -k1,1 -k2,2n genes.bed > genes_sorted.bed
bedtools intersect -a genes_sorted.bed -b peaks_sorted.bed -sorted

-sorted 参数跳过 bedtools 内部的排序,处理 GB 级文件时速度提升 5-10 倍。

坑4:merge 后原始信息丢失#

merge 默认只保留染色体和坐标,其他列全部丢弃。要用 -c-o 把关键信息保留下来。

9. 小结#

子命令功能核心参数
intersect求交集-f(重叠比例), -v(反向), -wa -wb(输出双方)
merge合并重叠-d(最大间距)
coverage覆盖度-d(逐碱基覆盖)
closest最近邻-d(输出距离)
slop扩展区间-l(左), -r(右), -s(按链)
genomecov覆盖轨迹-bg(bedGraph输出)

本文于 2025-03-18 在 Debian 13 上实测完成。bedtools v2.31.1,测试数据均为模拟 BED 文件。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

bedtools区间操作:intersect/merge/coverage/closest
https://fg.ink/posts/bedtools-interval-operations/
作者
风观
发布于
2025-09-01
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
风观
风有来路,观有所思
分类
标签
站点统计
文章
50
分类
1
标签
29
总字数
61,837
运行时长
0
最后活动
0 天前

文章目录