perl模擬Illumina測序

走過了一路的坑,終于走完了這條路,寫下學習總結。

總體想法

要模擬Illumina測序,首先要了解的就必須是Illumina的測序原理和流程,不能憑空造輪子。之后才是代碼的編寫,還有對結果的檢測。所以首先了解下IIIumina測序原理。

IIIumina測序

對于IIIumina測序,概括起來可以分為以下幾個簡單的步驟,網(wǎng)上有很多我就稍微提下。

1、打斷

打斷是指將原本一條很長的DNA序列打斷為一些較短的序列,因為IIIumina讀長一般為100~200,不能對很長的DNA序列進行測序,所以要進行打斷操作

2、PCR

基本上高中的時候都有了解了,就是將一個DNA序列進行大量復制,然后目的是進行大規(guī)模測序,獲得大數(shù)據(jù),降低誤差等等原因

3、讀取

最后一步就是對DNA進行讀取,原理是用特殊處理的脫氧核糖核酸來進行基因的復制,然后這樣每次就只能增加一個堿基,然后根據(jù)不同堿基測出的顏色不同來進行讀取。

說的比較簡略,了解下大概就行。
再留幾個比較好的資料鏈接。
國外的一篇文章:http://thegenomefactory.blogspot.jp/2013/08/paired-end-read-confusion-library.html
20160405 illumina 測序原理介紹
陳巍學基因

相關名詞概念

SNP和Indel

SNP:基因上堿基的變異,原本是A,突變?yōu)镚、C或者T了。
Indel:基因上堿基的增添、刪除,原本是A,然后沒有了。

SE和PE

SE:single end 單端讀序,短于200的可以采用單端讀序,因為可以一次測完。
PE:paired end 雙端讀序,因為很長,無法從一側讀完,所以采用雙端讀,延長讀長。

coverage

coverage = 總堿基數(shù)/DNA長度
這里總堿基數(shù)是指的最后讀完所有堿基的和,DNA長度是原始DNA未打斷前的長度,coverage是人為設定的用于控制最后數(shù)據(jù)量大小的參數(shù)

5' 端和3' 端

DNA的復制是有方向的,必須從5' 端到3' 端進行復制,也就是說讀取DNA時也要從5' 端到3' 端。

開始模擬基因測序,雙端測序

1、隨機模擬DNA序列

這個隨便了,找真數(shù)據(jù)也無所謂,只是我這樣做的,好處是可以隨時獲得指定長度的DNA,方便。
這個很簡單就是使用隨機數(shù)隨機選取AGCT,生成偽隨機序列。

my @DNA;
my @Nucleotide = ("A", "G", "C", "T");
for(my $i = 0;$i <$len; $i++)
{   
    my $rand = int(rand(4));
    $DNA[$i] = $Nucleotide[$rand];

}

2、在隨機的DNA序列中模擬SNP和Indel

對于SNP,在代碼中設定一個叫SNP_rate的變量用于設定每個位點發(fā)生SNP的概率,根據(jù)概率決定是否發(fā)生SNP,發(fā)生則替換對應位點的堿基。
Indel也是同樣,只是將替換改為增加和刪除,一般隨機添加或刪除1~3個堿基(聽公司的前輩說的)。

# simulate the SNP and Indel problom
sub SNP_Indel{
    my ($ref, $sRate, $iRate) = @_;
    my $len = length $ref;
    my $sNum = int $sRate * $len;
    my $iNum = int $iRate * $len;
    my @array = ("A", "G", "C", "T");
    for(my $i=0; $i<$sNum; $i++) {
        substr($ref, int rand $sNum, 1) = $array[int rand 4];
    }
    for(my $i=0; $i<$iNum; $i++) {
        if(int rand 2 == 1) {
            substr($ref, int rand $iNum, int rand 3) = "";
        }
        else {
            my $position = int rand $iNum;
            for(my $i=0; $i<rand 3;$i++) {
                substr($ref, $position , 1) = @array[int rand 4];
            }
        }
    }
    return $ref;
}

3、模擬DNA打斷

這一步就是將DNA序列進行一個分割操作隨機提取一個長度,叫InsertSize,一般指定為500,但實際上不是100%的500,一般認為是根據(jù)正態(tài)分布,所以要有一個分布區(qū)間,可以設定為sd。
但,本人偷了個懶,沒寫那么復雜,直接隨機了。
PCR則感覺在模擬過程中不是很必要,當然也可以做,可以模仿在PCR中可能產(chǎn)生的SNP和Indel情況,在對根據(jù)大數(shù)據(jù)還原原始序列,說著貌似很有道理啊。

# simulate the option of PCR
sub cutSeq{
    my ($ref, $mean, $range) = @_;
    my $len = int($mean + rand 2 * $range - $range);
    my $PCR = substr $ref, int rand(length($ref) -$len), $len;
    return $PCR;
}

4、PCR

(我省略了。。。。)

5、最后,開始讀序

讀序操作實際上有一點要注意的是,假設變量A讀取的是DNA 5’端為始端的鏈,然后雙端讀序,變量B要讀的就是末端的序列,但因為末端為3' 端所以不能進行讀取,只有去讀5'端為末端的鏈,然后必須有一步的操作就是進行基因的互補反向,這個概念一定要清楚。
然后又一個我現(xiàn)在還不是非常理解但是能知道的就是,當打斷的序列大于1000時,會形成環(huán)來進行讀取,這是情況相反,變量A要進行互補反向操作。

# start read the DNA
sub getReads{
    my ($PCR, $rate, $read_len) = @_;
    my @array = ("A", "G", "C", "T");
    state $n = 0;
    my $len = length $PCR;
    my $read1 = substr($PCR, 0, $read_len);
    my $read2 = substr($PCR, -$read_len, $read_len);
    if($len > 1000){
        $read1 = &revcom($read1);
    }else{
        $read2 = &revcom($read2);
    }
    for(my $i=0; $i<$read_len; $i++) {
        if(rand(1) < $rate)
        {
            substr($read1, $i, 1) = @array[int rand 4];
        }
        if(rand(1)<$rate)
        {
            substr($read2, $i, 1) = @array[int rand 4];
        }
    }
    print READ1 ">reads_$n\_100 1\n$read1\n";
    print READ2 ">reads_$n\_100 2\n$read2\n";
    $n++;
}

你以為結束了嗎?沒呢

對結果進行檢驗

檢驗用的是kmer方法,統(tǒng)計長度為k的基因序列在所有讀取序列中的出現(xiàn)次數(shù)。結果與coverage相關,如coverage設定為20,則kmer最后的峰值也應該在16、7左右。這樣才正確。

介紹下kmer

kmer是指長度為k的所有可能的基因在所有讀取文件中出現(xiàn)的次數(shù),然后再統(tǒng)計出現(xiàn)相同次數(shù)的基因的數(shù)目。
舉例:

  • 我有1條reads:
    >read1
    ATGCAAA
    >read2
    AGTAGAA
    K取6,則得到四個k-mer, 它們各自出現(xiàn)了一次
    輸出1:
    ATGCAA 1
    TGCAAA 1
    AGTAGA 1
    GTAGAA 1
    則輸出的統(tǒng)計文件結果如下:
    輸出2:
    1 4

具體實現(xiàn)

首先是讀入reads文件,按行讀取,然后利用hash,用hash{key}++,來做,統(tǒng)計所有數(shù)據(jù),最后得到一個hash,在利用相同的方法得到最后的出現(xiàn)x次的有y中kmer這個結果。

# get frequence that length is k
sub k_frequence
{
    my ($seq, $kmer,$modelHash) = @_;
    my $model;
    for(my $j=0; $j < length($seq)-$kmer; $j++)
    {
        $model = substr($seq, $j, $kmer);
        if(!defined($modelHash->{$model})){
            $modelHash->{$model} = 0;
        }
        $modelHash->{$model}++;
    }
}

# get kmer,input values
sub kmer
{
    my @modelArr = @_;
    my %kmers;
    for(my $i=0; $i<@modelArr; $i++)
    {
        if(!defined($kmers{$modelArr[$i]})){
            $kmers{$modelArr[$i]} = 0;
        }
        $kmers{$modelArr[$i]}++;
    }
    return %kmers;
}

驗證結果

做完上述所有步驟后,現(xiàn)在只要打開你寫入的文件,查看峰值出現(xiàn)的位置,你就可以知道最后做的結果如何了。

結束語

坑還是可以填滿的,只要一直努力做下去。繼續(xù)努力。
倉庫地址:https://github.com/MyandMine/simulate_Illumina

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容