加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

K-mer Index问题

发布时间:2020-12-15 23:45:40 所属栏目:大数据 来源:网络整理
导读:问题: 给定一个 DNA 序列,这个系列只含有4 个字母ATCG,如 S = “CTGTACTGTAT ”。给定一个整数值 k ,从 S 的第一个位置开始,取一 连续 k 个字母的短串,称之 为 k- mer (如 = 5 , 则此短串为 CTGTA ),然后从 的第二个位置,取另一 ( 如 TGTAC ),

问题:给定一个DNA序列,这个系列只含有4个字母ATCG,如 S =“CTGTACTGTAT”。给定一个整数值k,从S的第一个位置开始,取一连续k个字母的短串,称之k-mer(如= 5则此短串为CTGTA),然后从的第二个位置,取另一TGTAC),直至的末端,就得一个集合,包含全部 如对序列S来说,所有5-mer为GTACTTACTGACTGTTGTAT通常这些k-mer需一种数据索引方法,可被后面的操作快速访问。例如,对5-mer来说,当查询CTGTA,通过这种数据索引方法,可返回其在DNA序列S中的位置为{1,6}。

现在以文件形式给定 多个 DNA序列,要求对给定k, 给出并实现一种数据索引方法,可返回任意一个k-mer所在的DNA序列编号和相应序列中出现的位置。

思路:

1、首先采用命A=0,C=1,G=2,T=3. 就相当于4进制数字,然后采用karp-Rabin算法转换成唯一十进制数字。由于用此算法的哈希函数为:hash(value)=value*(4^(k-q-1));

value是该字符对应的值,k是kmer长度,q是此字符在字符串的位置范围在[0-(q-1)]。然后把一个kmer里面所有字符的hash值求和就行了。

2、那么很容易看出来,对于连续的下一个Kmer,就有推理公式了?hashNew=addValue+(hashOld-deleteValue*(4^(k-1)))*4; hashNew就是往右平移一个字符的kmer hash值,hashOld就是平移之前的值,addValue就是平移后右边多的一个字符,deleteValue就是平移后左边少的一个字符。这样整个hash表建立的时间复杂度约为O(m+k),m是整个文本长度。

3、由于kmer长度如果过长,其hash值过大,会造成内存不够溢出的现象,所以kmer内部定死为10 。那么问题就来了,如何应对不同的kmer值。分三种情况。

第一种:q>10?

这种可以将kmer以10为单位,将hash表中对应值取出,然后对结果进行分析,这边分析方法为建立两个数组一个二维数组unionName储存位置关系,一个一维数组unionScore,计数用。 思路就是首先第一轮初始化unionName[Name][Pos]全部赋值Pos?并初始化unionScore,然后再第二轮匹配如果[Name][Pos-cycle]=Pos-1则将其赋值为当前Pos,cycle为当前循环次数。并将当前循环数存入unionScore[NAME]中。最后当unionScore[NAME]值也就是循环数为k-1,即我们需要的交集了。

第二种:q=10

直接求出hash值,取出相应的值即可。

第三种:q<10

可以用前缀种子+后缀种子交集产生。

前缀种子:在字符串后面补字符直到长度等于K,这个很容易看出来 最小是全补A,最大是全补T,然后将最小值到最大值之间的hash值即为所求。

后缀种子:后缀种子和前缀种子不同就是在字符串左边补齐字符。所以此时需要进行变换。只要对前置种子产生的值变化下就行了。(preValue-minValue)*(4^(K-q))+hash(p) 。其中preValue就是对应的前置种子的hash值,minValue就是前置种子中最小值也就是全补A的情况,hash(p)就是字符串长度为p时候的hash值。?

交集就是先求后缀种子所有的值,再加上 前缀种子中起始位置在[0-(k-1)]中的值。

代码如下:

#usr/bin/perl -w
use strict;
my $myFileName="test.txt";#需要找寻的文件
my $searchKey="GGGA";#找寻的字符

my $myKmerInput=length $searchKey;#K-mer值
my $myKmer=2;
my @name={};
my $tempLength=0;
my $i=0;
my $j=0;
my @Add={};
my @temp={};
my $newHashValue=0;
my $myHashOld=0;
my $flag=0;
my $nameCycle=0;
my $finaNameFlag=0;
if($myKmerInput<=$myKmer){

$flag=1;
}
open(myFile,$myFileName)||die("cannot open $myFileName");
while(my $myLine=<myFile>){
chomp($myLine);
     if($myLine=~/>/){
     if($myLine=~/>(S+) /){
      $name[$nameCycle]=$1;
     }
     }
     elsif($myLine=~/[A-Z]/){
       @temp=split//,$myLine;
       $tempLength=scalar @temp;
       if($tempLength-$myKmer+1 <= 0){
       die("Kemer Length is too long");
       }

       $myHashOld=&myHash($myKmer,@temp);
       $Add[$myHashOld].="@1&$nameCycle";

       for($i=1;$i<$tempLength-$myKmer+1;$i++){
       $j=$i+1;
       $newHashValue=&rehash($myHashOld,$temp[$i-1],$temp[$i+$myKmer-1]);

                                $Add[$newHashValue].="@$j&$nameCycle";
                                $myHashOld=$newHashValue;

       }
       $nameCycle++;

     }
     else{
     next;
     }

}
close(myFile);
@temp=split//,$searchKey;
if($flag==0){
my @addTemp={};

 $tempLength=scalar @temp;
       if($tempLength-$myKmer+1 <= 0){
       die("Kemer Length is too long");
       }
       $myHashOld=&myHash($myKmer,@temp);
       $addTemp[0]=$Add[$myHashOld];

       for($i=1;$i<$tempLength-$myKmer+1;$i++){
       $j=$i+1;
       $newHashValue=&rehash($myHashOld,$temp[$i+$myKmer-1]);
                      if($Add[$newHashValue]=~/[0-9]/){
                             $addTemp[$i]=$Add[$newHashValue];
                           }
                             $myHashOld=$newHashValue;
       }


if((scalar @addTemp)!=($tempLength-$myKmer+1)){

  die("cannot findn");
}

     @addTemp=&unionValue(@addTemp);

      for($i=0;$i<$finaNameFlag;$i++)
      {

       if($addTemp[$i]=~/(S+)&;(S+)/){
           my $posEnd=$2+$myKmerInput-1;
           print "myDNAName=$name[$1]tposBegin=$2tposEnd=$posEndn";
       }
      }

}
elsif($flag==1){
my $resultFalg=0;
my $minValue=&myHash($myKmerInput,@temp);

my $nextMinValue=$minValue;
if(($myKmer-$myKmerInput)>=1){

for($i=0;$i<$myKmer-$myKmerInput;$i++){
$temp[($i+$myKmerInput)]="A";
 }

 $minValue=&myHash($myKmer,@temp);

 for($i=0;$i<$myKmer-$myKmerInput;$i++){
$temp[($i+$myKmerInput)]="T";
 }

 }
my $maxValue=&myHash($myKmer,@temp);

my $myNowValue=$minValue;

for($myNowValue;$myNowValue<=$maxValue;$myNowValue++){

my @addTemp={};
@addTemp=split/@/,$Add[$myNowValue];

my $addTempLength=scalar @addTemp;

if($addTempLength==0){

  next;
}
for($i=0;$i<$addTempLength;$i++){
 if($addTemp[$i]=~/(S+)&;(S+)/){
         if($1>$myKmer&&($myKmer!=$myKmerInput)){
                 next;
                 }
                 else{
  my $posEnd=$1+$myKmerInput-1;

print "myDNAName=$name[$2]tposBegin=$1tposEnd=$posEndn";
$resultFalg=1;
}
}
}
}

if(($myKmer-$myKmerInput)>=1){

$myNowValue=$minValue;
my $nextMaxValue=($maxValue-$minValue)*(4**($myKmer-$myKmerInput))+$nextMinValue;
for($myNowValue;$myNowValue<=$maxValue;$myNowValue++){

my @addTemp={};
my $nextNowValue=($myNowValue-$minValue)*(4**$myKmerInput)+$nextMinValue;

@addTemp=split/@/,$Add[$nextNowValue];
my $addTempLength=scalar @addTemp;

if($addTempLength==0){

  next;
}

for($i=0;$i<$addTempLength;$i++){
 if($addTemp[$i]=~/(S+)&;(S+)/){
         if($1==1){
                 next;
                 }
                 else{
  my $nextPosBegin=$1+$myKmer-$myKmerInput;
        my $nextPosEnd=$nextPosBegin+$myKmerInput-1;
print "myDNAName=$name[$2]tposBegin=$nextPosBegintposEnd=$nextPosEndn";
$resultFalg=1;
}
}
}
}
}
if(!$resultFalg){
        die("cannot findn");
        }
}


#  for($i=0;$i<scalar @Add;$i++){
#  if(!($Add[$i] eq "")){
#  print $i."t".$Add[$i]."n";
#  }
#  }
sub unionValue{

my(@unionTemp)=@_;

my $unionTempLength=scalar @unionTemp;
my $unionCycle=0;
my $unionNameBefore=0;
my $unionNameNext=0;
my $unionPosBefore=0;
my $unionPosNext=0;
my @unionTempBefore={};
my @unionTempName=();
my @unionScoreName={};
my @finalName={};
my $myDNAName="";
my $unionTempCycle=0;


@unionTempBefore=split/@/,$unionTemp[0];
my $unionTempBeforeLength=scalar @unionTempBefore;
for($unionTempCycle=1;$unionTempCycle<$unionTempBeforeLength;$unionTempCycle++){

if($unionTempBefore[$unionTempCycle]=~/(S+)&;(S+)/){
                $unionNameBefore=$2;
                $unionPosBefore=$1;

                $unionTempName[$unionNameBefore][$unionPosBefore]= $unionPosBefore;
                $unionScoreName[$unionNameBefore]=0;
              }
  }


for($unionCycle=1;$unionCycle<$unionTempLength;$unionCycle++){
@unionTempBefore=split/@/,$unionTemp[$unionCycle];
$unionTempBeforeLength=scalar @unionTempBefore;

for($unionTempCycle=1;$unionTempCycle<$unionTempBeforeLength;$unionTempCycle++){
        if($unionTempBefore[$unionTempCycle]=~/(S+)&;(S+)/){
                $unionNameBefore=$2;
                $unionPosBefore=$1;
              }
             
if($unionPosBefore<$unionCycle){

        next;
        }

              if($unionTempName[$unionNameBefore][$unionPosBefore-$unionCycle]==($unionPosBefore-1)&&(($unionPosBefore-1)!=0)){

              $unionTempName[$unionNameBefore][$unionPosBefore-$unionCycle]=$unionPosBefore;

                 $unionScoreName[$unionNameBefore]=$unionCycle;
                 if($unionScoreName[$unionNameBefore]==$unionTempLength-1){

                       $finalName[$finaNameFlag++]=$unionNameBefore."&".($unionPosBefore-$unionCycle);


                 }

              }


    }
    
    }
     if($finaNameFlag==0){
           die("cannot findn");
     }
    return @finalName;

}

sub rehash{
        my ($myOldValue,$deleteChar,$addChar) = @_;
        my $myNewValue=0;

        $myNewValue=&testChar($addChar)+($myOldValue-&testChar($deleteChar)*(4**($myKmer-1)))*4;

        return $myNewValue;
        }
sub myHash{
     my ($myLength,@list) = @_;
     my $result=0;

     for(my $k=0;$k<$myLength;$k++){

      $result+= &testChar($list[$k])*(4**($myLength-$k-1));

     }

     return  $result;

}
sub testChar{
      my ($myChar) = @_;

      if($myChar eq 'A')
      {
        return 0;
      }
      elsif($myChar eq 'C'){
        return 1;

      }
        elsif($myChar eq 'G'){
        return 2;

      }
        elsif($myChar eq 'T'){
        return 3;

      }
      else{

      die("wrong DNA");
      }

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读