SAM/BAM相關的進階知識

目錄

  1. samtools和picard的排序問題
  2. SAM文件中FLAG值的理解
  3. SAM文件中那些未比對的reads
  4. 為什么一條read會有多條比對記錄?
  5. 同一份BAM文件samtools depth和samtools mpileup的結果不同?
  6. 為什么samtools flagstat與hisat2的mapping rate不同?

1. samtools和picard的排序問題

samtoolspicard都有對SAM/BAM文件進行排序的功能,一般都是基于坐標排序(還提供了-n選項來設定用reads名進行排序),先是對chromosome/contig進行排序,再在chromosome/contig內部基于start site從小到大排序,對start site排序很好理解,可是對chromosome/contig排序的時候是基于什么標準呢?

基于你提供的ref.fa文件中的chromosome/contig的順序。當你使用比對工具將fastq文件中的reads比對上參考基因組后會生成SAM文件,SAM文件包含頭信息,其中有以@SQ開頭的頭信息記錄,reference中有多少條chromosome/contig就會有多少條這樣的記錄,而且它們的順序與ref.fa是一致的。

SAM/BAM文件的頭信息:

@HD     VN:1.3  SO:coordinate
@SQ     SN:chr1 LN:195471971
@SQ     SN:chr2 LN:182113224
@SQ     SN:chr3 LN:160039680
@SQ     SN:chr4 LN:156508116
@SQ     SN:chr5 LN:151834684
@SQ     SN:chr6 LN:149736546
@SQ     SN:chr7 LN:145441459
@SQ     SN:chr8 LN:129401213
@SQ     SN:chr9 LN:124595110
@SQ     SN:chr10        LN:130694993
@SQ     SN:chr11        LN:122082543
@SQ     SN:chr12        LN:120129022
@SQ     SN:chr13        LN:120421639
@SQ     SN:chr14        LN:124902244
@SQ     SN:chr15        LN:104043685
@SQ     SN:chr16        LN:98207768
@SQ     SN:chr17        LN:94987271
@SQ     SN:chr18        LN:90702639
@SQ     SN:chr19        LN:61431566
@SQ     SN:chrX LN:171031299
@SQ     SN:chrY LN:91744698
@SQ     SN:chrM LN:16299
@RG     ID:ERR144849    LB:ERR144849    SM:A_J  PL:ILLUMINA

ref.fa中chromosome/contig的排列順序:

>chr1
>chr2
>chr3
>chr4
>chr5
>chr6
>chr7
>chr8
>chr9
>chr10
>chr11
>chr12
>chr13
>chr14
>chr15
>chr16
>chr17
>chr18
>chr19
>chrX
>chrY
>chrM

它們的順序一致

當使用samtools或picard對SAM/BAM文件進行排序時,這些工具就會讀取頭信息,按照頭信息指定的順序來排chromosome/contig。所以進行排序時需要提供包含頭信息的SAM/BAM文件。

那么普通情況下我們的chromosome/contig排序情況是什么樣的?

一般情況下我們獲取參考基因組序列文件的來源有三個:

  • NCBI
  • ENSEMBEL
  • UCSC Genome Browser

這里以UCSC FTP下載源為例:

這是一個壓縮文件,使用tar zxvf chromFa.tar.gz解壓后,會得到多個fasta文件,每條chromosome/contig一個fasta文件:chr1.fa, chr2.fa ...

之后我們會將它們用cat *.fa >ref.fa合并成一個包含多條chromosome/contig的物種參考基因組序列文件

grep ">" ref.fa可以查看合并后發ref.fa文件中染色體的排列順序為:

>chr10
>chr11
>chr12
>chr13
>chr14
>chr15
>chr16
>chr17
>chr18
>chr19
>chr1
>chr1_GL456210_random
>chr1_GL456211_random
>chr1_GL456212_random
>chr1_GL456213_random
>chr1_GL456221_random
>chr2
>chr3
>chr4

這和我們平時想象的染色體的排列順序是不是有一些出入?難道不應該是從chr1開始到chr22,最后是chrX和chrY這樣的順序嗎?

想象歸想象,實際上它是按照字符順序進行的,chr11就應該排在chr2前面

一般情況下在進行SAM文件的排序時,染色體的排序到底是按照哪種規則進行排序的,不是一個很重要的問題,也不會對后續的分析產生影響,但是在執行GATK流程時,GATK對染色體的排序是有要求的,必須按照從chr1開始到chr22,最后是chrX和chrY這樣的順序,否則會報錯

面對這樣變態的要求,我們怎么解決?

在構造ref.fa文件時,讓它按照從chr1開始到chr22,最后是chrX和chrY這樣的順序進行組織就可以了:

for i in $(seq 1 22) X Y M;
do cat chr${i}.fa >> hg19.fasta;
done

2. SAM文件中FLAG值的理解

FLAG列在SAM文件的第二列,這是一個很重要的列,包含了很多mapping過程中的有用信息,但很多初學者在學習SAM文件格式的介紹時,遇到FLAG列的說明,常常會一頭霧水

what?還二進制,這也太反人類的設計了吧!

不過如果你站在開發者的角度去思考這個問題,就會豁然開朗

在mapping過程中,我們想記錄一條read的mapping的信息包括:

  • 這條read是read1 (forward-read) 還是read2 (reverse-read)?
  • 這條read比對上了嗎?與它對應的另一頭read比對上了嗎?
  • ...

這些信息總結起來總共包括以下12項:

序號 簡寫 說明
1 PAIRED paired-end (or multiple-segment) sequencing technology
2 PROPER_PAIR each segment properly aligned according to the aligner
3 UNMAP segment unmapped
4 MUNMAP next segment in the template unmapped
5 REVERSE SEQ is reverse complemented
6 MREVERSE SEQ of the next segment in the template is reversed
7 READ1 the first segment in the template
8 READ2 the last segment in the template
9 SECONDARY secondary alignment
10 QCFAIL not passing quality controls
11 DUP PCR or optical duplicate
12 SUPPLEMENTARY supplementary alignment

而每一項又只有兩種情況,是或否,那么我可以用一個12位的二進制數來記錄所有的信息,每一位表示某一項的情況,這就是原始FLAG信息的由來,但是二進制數適合給計算機看,不適合人看,需要轉換成對應的十進制數,也就有了我們在SAM文件中看到的FLAG值

但是FLAG值所包含信息的解讀還是要轉換為12位的二進制數

3. SAM文件中那些未比對的reads

SAM格式文件的第3和第7列,可以用來判斷某條reads是否比對成功到了基因組的染色體,左右兩條reads是否比對到同一條染色體

有兩個方法可以提取未比對成功的測序數據:

  • SAM文件的第3列是*的(如果是PE數據,需要考慮第3,7列)
$ samtools view sample.bam | perl -alne '{print if $F[2] eq "*" or $F[6] eq "*" }' sample.unmapped.sam
  • 或者SAM文件的flag標簽包含0x4的
# 小寫的f是提取,大寫的F是過濾
$ samtools view -f4 sample.bam sample.unmapped.sam

雖然上面兩個方法得到的結果是一模一樣的,但是這個perl腳本運行速度遠遠比不上上面的samtools自帶的參數

對于PE數據,在未比對成功的測序數據可以分成3類:

  • 僅reads1沒有比對成功

該提取條件包括:

  • 該read是read1,對應于二進制FLAG的第7位,該位取1,其十進制值為64;
  • 該read未成功比對到參考基因組,對應于二進制FLAG的第3位,該位取1,其十進制值為4;
  • 另一配對read成功比對到參考基因組,對應于二進制FLAG的第4位,該位取0,其十進制值為8;
# 對于取1的位點采用提取的策略,用-f參數,值設為64+4=68
# 對于取0的位點采取過濾的策略,用-F參數,值設為8
$ samtools view -u -f 68 -F 8 alignments.bam >read1_unmap.bam
  • 僅reads2沒有比對成功

該提取條件包括:

  • 該read是read2,對應于二進制FLAG的第8位,該位取1,其十進制值為128;
  • 該read未成功比對到參考基因組,對應于二進制FLAG的第3位,該位取1,其十進制值為4;
  • 另一配對read成功比對到參考基因組,對應于二進制FLAG的第4位,該位取0,其十進制值為8;
# 對于取1的位點采用提取的策略,用-f參數,值設為128+4=132
# 對于取0的位點采取過濾的策略,用-F參數,值設為8
$ samtools view -u -f 132 -F 8 alignments.bam >read2_unmap.bam
  • 兩端reads都沒有比對成功

該提取條件包括:

  • 該read未成功比對到參考基因組,對應于二進制FLAG的第3位,該位取1,其十進制值為4;
  • 另一配對read未成功比對到參考基因組,對應于二進制FLAG的第4位,該位取1,其十進制值為8;
# 對于取1的位點采用提取的策略,用-f參數,值設為4+8=12
$ samtools view -u -f 12 alignments.bam >pairs_unmap.bam

看完這一部分,是不是有一個感覺:FLAG玩得溜,SAM文件可以處理得出神入化

4. 為什么一條read會有多條比對記錄?

首先,思考一個問題:對于PE數據,一條測序片段(fragment)有read1和read2兩條測序片段,它們倆的名字相同,那么對于這一條測序片段,對它進行mapping之后得到的SAM文件中會出現幾條記錄呢?

先聲明以下只對BWA比對得到的SAM文件進行討論,對其他比對工具輸出的SAM文件可能不適用

首先,基于經驗積累告訴我,它會得到有且只有兩條記錄,原因在于,BWA在對每條read執行比對時只會給出一個hit,若這條read是multiple mapping的情況,它會從中選擇MAPQ值最高的那個hit作為輸出,若存在多個hits的MAPQ值相等且最高,那么BWA會從中隨機選擇一個作為輸出

對于我的這個假設可以用以下的方法進行驗證:

# 將SAM文件的第一列提出來,排序去重,同時統計每個QNAME出現的次數
$ samtools view alignment.bam | cut -f1 | sort | uniq -c >record.count

得到的統計結果如下:
      2 ERR144849.1
      2 ERR144849.10
      2 ERR144849.100
      2 ERR144849.1000
      2 ERR144849.10000
      2 ERR144849.100000
      2 ERR144849.1000000
      2 ERR144849.10000000
      2 ERR144849.10000001
      2 ERR144849.10000002
      2 ERR144849.10000003
      2 ERR144849.10000004
      2 ERR144849.10000005
      ...

上面的測試結果與我們的假設吻合

但是在一次處理三代測序數據(三代測序數據是Single-End)中發現了不同:

在輸出中出現了一些不太和諧的結果:有極少部分的QNAME對應2條以上的記錄,這意味著存在一條read會有多條比對記錄的情況,why?

對這個與預期不完全相符的結果,嘗試去尋找里面的原因,其間進行了各種各樣的推理、假設、驗證,最終在 李恒的github 中找到了答案

2. Why does a read appear multiple times in the output SAM?

BWA-SW and BWA-MEM perform local alignments. If there is a translocation, a gene fusion or a long deletion, a read bridging the break point may have two hits, occupying two lines in the SAM output. With the default setting of BWA-MEM, one and only one line is primary and is soft clipped; other lines are tagged with 0x800 SAM flag (supplementary alignment) and are hard clipped.

這種情況容易在三代測序數據中出現

5. 同一份BAM文件samtools depth和samtools mpileup的結果不同?

如果你用的是Single-End的數據,那么差異應該比較小,不會太明顯,而在Pair-End上差異可能會比較大,之所以會產生這些差異,原因有兩點:

(1)mpileup會默認將PE reads中比對情況異常的那些reads(包括雙端都比上,但是兩條配對reads之間的比對距離明顯偏離了插入片段的長度分布,或者一端比對上而另一端沒比對上)丟棄,則在計算depth時,這些被丟棄的reads不參與統計,而depth則不會,depth默認不做任何過濾

mpileup中提供了一個-A選項來保留異常比對的reads,如果設置了這個選項,那么在這點上mpileup的depth統計就和samtools depth相同了

(2)從上圖的第二個紅框可以看出,在默認情況下,mpileup還會過濾掉測序質量值低于13的堿基,depth默認不過濾

從上面列出的兩點差異可以看出,mpileup默認輸出的是高質量的覆蓋深度,這是有歷史原因的:當場mpileup功能被開發出來就是為了與bcftools組合,將samtools mpileup的輸出作為bcftools的輸入用于下游的snp-calling,當然需要保證數據的質量

當然可以通過設置對應的參數使得它的屬于結果與depth的一致,但是不推薦這么做

6. 為什么samtools flagstat與hisat2的mapping rate不同?

下面是對同一個樣本的paired-end Fastaq文件比對結果(比對使用hisat2),hisat2和samtools分別給出的mapping rate的統計

hisat2:

39928651 reads; of these:
  39928651 (100.00%) were paired; of these:
    8439896 (21.14%) aligned concordantly 0 times
    30158798 (75.53%) aligned concordantly exactly 1 time
    1329957 (3.33%) aligned concordantly >1 times
    ----
    8439896 pairs aligned concordantly 0 times; of these:
      298072 (3.53%) aligned discordantly 1 time
    ----
    8141824 pairs aligned 0 times concordantly or discordantly; of these:
      16283648 mates make up the pairs; of these:
        11658022 (71.59%) aligned 0 times
        4210488 (25.86%) aligned exactly 1 time
        415138 (2.55%) aligned >1 times
85.40% overall alignment rate

samtools flagstat:

85207970 + 0 in total (QC-passed reads + QC-failed reads)
5350668 + 0 secondary
0 + 0 supplementary
0 + 0 duplicates
73549948 + 0 mapped (86.32% : N/A)
79857302 + 0 paired in sequencing
39928651 + 0 read1
39928651 + 0 read2
62977510 + 0 properly paired (78.86% : N/A)
63902424 + 0 with itself and mate mapped
4296856 + 0 singletons (5.38% : N/A)
173078 + 0 with mate mapped to a different chr
127302 + 0 with mate mapped to a different chr (mapQ>=5)

從上面可以看出,hisat2給出的mapping rate為85.40%,而samtools給出的為86.32%,兩個的統計結果不一樣,而且samtools的統計會大一些,what?

介四什么鬼?

我們來簡單地分析一下:

hisat2中,

\frac{(30158798 + 1329957 + 298072) \times 2 + 4210488 + 415138}{2\times 39928651} \times 100\%= \frac{68,199,280}{79,857,302} \times 100\%=85.40\%

samtools中,

\frac{73549948} {85207970} \times 100\%= 86.32\%

計算沒問題,那問題出在哪呢?

有沒有注意到上面的兩個式子中的分子和分母,計算它們的差值:

分子:73,549,948 - 68,199,280 = 5,350,668

分母:85,207,970 - 79,857,302 = 5,350,668

發現了沒有,它們的差值正好都等于samtools flagstat的輸出結果的第二行:

5350668 + 0 secondary

所以,hisat2和samtools計算mapping rate的公式實際上分別為:

  • hisat2

    \text{mapping rate}=\frac{\text{mapped reads number}}{\text{total reads number}} \times 100\%

  • samtools

    \begin{aligned}&\quad \text{mapping rate}\\&=\frac{\text{mapped recorder number}}{\text{total recorder number}} \times 100\%\\&=\frac{\text{(primary) mapped reads number + secondary mapped reads number}}{\text{total reads number + secondary mapped reads number}} \times 100\%\end{aligned}

    其中,recorder number表示SAM文件中除去頭信息部分的比對記錄數,每一行是一條比對記錄

一般來說,我們想得到的是hisat2計算公式所得到的統計結果,hisat2統計結果在比對結束后會以標準錯誤形式給出,我們可以將標準錯誤重定向到一個log文件中,但是如果我們忘了保持這個統計結果,怎么辦?

最簡單的辦法就是重新跑一遍hisat2,但是這樣太耗費時間和計算資源了,這時我們可以利用samtools flagstat對SAM文件的統計結果,以及它的部分統計值與hisat2計算公式的關系,快速地算出準確的mapping rate:

\begin{aligned} &\quad \text{mapping rate} \\ &= \frac{\text{mapped reads number}}{\text{total reads number}} \times 100\% \\ &= \frac{\text{mapped recorder number - secondary mapped reads number}}{\text{total recorder number - secondary mapped reads number}} \times 100\% \end{aligned}


參考資料:

(1) 【簡書】從零開始完整學習全基因組測序數據分析:第5節 理解并操作BAM文件

(2) 【生信技能樹】【直播】我的基因組(十五):提取未比對的測序數據

(3) BWA's README in github

(4) 【簡書】黃樹嘉《樣本量重要,還是測序深度重要? 生物信息工程師可以分為多少種類型? |《解螺旋技術交流圈》精華第3期》

(5) 生信媛《HISAT2的比對率計算結果和SAMTools flagstat不同,你想過原因嗎? 》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容