Edit Distance编辑距离(NM tag)- sam/bam格式解读进阶
sam格式很精煉,幾乎包含了比對的所有信息,我們平常用到的信息很少,但特殊情況下,我們會用到一些較為生僻的信息,關于這些信息sam官方文檔的介紹比較精簡,直接看估計很難看懂。
今天要介紹的是如何通過bam文件統計比對的indel和mismatch信息
首先要介紹一個非常重要的概念--編輯距離
定義:從字符串a變到字符串b,所需要的最少的操作步驟(插入,刪除,更改)為兩個字符串之間的編輯距離。
(2016年11月17日:增加,有點誤導,如果一個插入有兩個字符,那編輯距離變了幾呢?1還是2?我又驗證了一遍:確實是2)
這也是sam文檔中對NM這個tag的定義。
?
編輯距離是對兩個字符串相似度的度量(參見文章:Edit Distance)
舉個栗子:兩個字符串“eeba”和“abca”的編輯距離是多少?
根據定義,通過三個步驟:1.將e變為a 2.刪除e 3.添加c,我們可以將“eeba”變為“abca”
所以,“eeba”和“abca”之間的編輯距離為3
?
回到序列比對的問題上
下面是常見的二代比對到ref的結果(bwa):
D00360:96:H2YLYBCXX:1:2110:18364:84053 353 seq1_len154_cov5 1 1 92S59M8I17M1D6M1D67M seq30532_len2134_cov76 1 0 AAAAAAAAAAAAAAAAAAAAAAAACCCTGTCTCTAATAAAATACAAACAATTAGCCGGGCATGGTGGCACGCGCCTTTAGTCCCAGCTACTAGGGAGGCTGAGGCAGGGGAATTGTTTGAACCCGGGAGGTGGAGGTTGCAGTGAGCGGAGTTTTTTTCACTGCACTCCAGCCTGGTGACAAATCAAAAATCCATTTCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAACAACAAA DDDDDHIIIIIIII<EHHII?EHH0001111111<11<DEH1D1<FH1D<<<C<@GEHD</<11<101<1D<<C<E0D11<<1<D?1F1CC1DE110C0D1011100////0DD<1=@1=FGHCDHH<FG<D0<<<EF?CE<00<<0<D//0;<:D/;///;8F.;/.8.8......88.9........-8BBGADHIIHD?>D?HH<,>=HHDD,5CHDCDHD><,,,--8----8-8-- NM:i:25 MD:Z:16A21C16C0A3T15^A6^G1G0T0G3C2T0G1C41A4A2A3 AS:i:49 XS:i:42 SA:Z:seq13646_len513_cov63,125,-,103S125M21S,1,11; RG:Z:chr22這是ref序列
>seq1_len154_cov5 GGGAGGCTGAGGCAGGAGAATTGTTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCAAGATTGCACTCCAGCCTGGATGACAAGAGTGAAACTCTGTCTCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcigar字段包含了序列比對的簡化信息,M(匹配比對,包含match和mismatch),=(純match),X(純mismatch),I(插入),D(刪除),還有N、P和S、H。(注:目前只在blasr比對結果中見過=和X)
根據cigar字段可以統計indel信息,但是無法統計mismatch。
這個時候就可以用到NM tag了,mismatch = NM – I - D = 25 – 8 – 1 – 1 = 15
有興趣的可以對著cigar數一遍,下面是我無聊數著的結果,也是15個
?
使用python的pysam模塊可以很容易的提取出每個比對結果的NM信息
參見之前的帖子:pysam - 多種數據格式讀寫與處理模塊(python)
?
再次驗證一遍:證明NM=len(mismatch) + len(insertion) + len(deletion), 而不是 count(mismatch) + count(insertion) + count(deletion) (count的意思是三個堿基的insertion算一個)
>>> bam_file = pysam.AlignmentFile(infile, "rb") >>> for line in bam_file: ... if 300 < line.query_alignment_length < 500: ... break ... >>> line.query_alignment_length 321 >>> line.seq 'CTCTTCATCACGTCACTTGTCCATGTCAATGGCTACAGGTTGGAAGTTTGGCCGCGGAGGGTGGGCAGGCAAGAGAAAGAAATCAGATAGGGCAGATGGTAGGGTAAAAGGAGGGGGTTAAGTGCAAATTGTCTACTGTTTGCAAATGGGAAGCATGTGATTGTTAAAATTTATACGATAAACCTTCTCATCATGTTGAGTCTCATGCTTGCGCCAAGAAGATCGGGTTCGGCGGGTCAAGCTGATAAGCAACTTGGGCAGCAAAGTCGTTCAGTGATACAAAATCATGTGCAAAAATCACAAGCATTCTTATAAACACCA' >>> line.cigarstring '5148H3M1I2M1I4M2I3M3I3M1D2M1I4M3I1M1I4M1D10M1D5M4I4M3D1M3I18M1I1M1I1M1I4M4D2M1I2M2I4M2I4M1I4M5I4M1I9M1I14M3I1M1I2M2I7M2I7M3I2M1I5M2I1M1I2M1I1M1I4M5I3M1I2M3I1M1I4M4I3M4I2M2I1M3I19M3I10M2I4M1I11M1D27M2I6M25212H' >>> line.reference_name 'Backbone_1' >>> line.reference_start 7164 >>> line.reference_end 7413 >>> line.get_tag('NM') 100取出了一條長度適中的比對結果,cigar字段比較全面。
取出了比對上的ref:
>>> ref = 'CTCTCTCACCACTCCTATTCAACACAGTGTTGGAAGTTCTGGACAGGGCAATCAGGCAAGAGAAAGAAATAAAGGGTATTCAATTAGGAAAAGAGGAAGTCAAATTGTCCCCGTTTGCAGATGACATGATTGTATATTTAGAAAACCCCACTGTTTCAGCCCCAAATCTCCTTAAGCTGATAAGCAACTTCAGCAAAGTCTCAGGATACAAAATCAATGTGCAAAAATCACAAGCATTCTTATACACCA'先通過我自己寫的cigar校正函數校正:
def formatSeqByCigar(seq, cigar):'''Input: query_alignment_sequence and cigar from sam fileOutput: formatSeqPurpose: make sure the pos is one to one correspondence(seq to ref)'''formatSeq = ''pointer = 0; qstart = 0; qend = -1; origin_seq_len = 0if cigar[0][0] == 4 or cigar[0][0] == 5:qstart = cigar[0][1]if cigar[-1][0] == 4 or cigar[-1][0] == 5:qend = - cigar[-1][1] - 1 # fushu countfor pair in cigar:operation = pair[0]cigar_len = pair[1]if operation == 0: # 0==MformatSeq += seq[pointer:(pointer+cigar_len)]pointer += cigar_lenorigin_seq_len += cigar_lenelif operation == 1: # 1==Ipointer += cigar_lenorigin_seq_len += cigar_lenelif operation == 2: # 2==DformatSeq += 'D'*cigar_lenelif operation == 4 or operation == 5: # 5==Horigin_seq_len += cigar_lencontinueelse:print (cigar)raise TypeError("There are cigar besides S/M/D/I/H\n")return formatSeq, qstart, qend, origin_seq_len然后分別計算deletion和mismatch:
>>> i = 0 >>> count = 0 >>> while i < len(ref):if formatSeq[i] != ref[i]:count += 1i += 1>>> count 17 >>> formatSeq.count('D') 11可以看出deletion有11個,退出mismatch有6個。
隨手一推insertion有83個。
而
>>> cigarstring = '5148H3M1I2M1I4M2I3M3I3M1D2M1I4M3I1M1I4M1D10M1D5M4I4M3D1M3I18M1I1M1I1M1I4M4D2M1I2M2I4M2I4M1I4M5I4M1I9M1I14M3I1M1I2M2I7M2I7M3I2M1I5M2I1M1I2M1I1M1I4M5I3M1I2M3I1M1I4M4I3M4I2M2I1M3I19M3I10M2I4M1I11M1D27M2I6M25212H' >>> cigarstring.count('I') 41 >>> cigarstring.count('D') 6用count計算顯然不對。
驗證成功
?
真切的明白了計算機有多么偉大,如果要是你肉眼去比對去數的話,我估計你會立馬崩潰。
總結
以上是生活随笔為你收集整理的Edit Distance编辑距离(NM tag)- sam/bam格式解读进阶的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xcode 8 去除无用打印信息
- 下一篇: C#泛型对类型参数的推断