【问题标题】:Perl: Removing duplicates from a large set of dataPerl:从大量数据中删除重复项
【发布时间】:2011-08-08 04:58:42
【问题描述】:

我正在使用 Perl 生成一个独特的外显子列表(它们是基因的单位)。

我已经生成了这种格式的文件(有几十万行):

chr1 1000 2000 基因1

chr1 3000 4000 基因2

chr1 5000 6000 基因3

chr1 1000 2000 基因4

位置1是染色体,位置2是外显子的起始坐标,位置3是外显子的结束坐标,位置4是基因名称。

由于基因通常由不同排列的外显子构成,因此您在多个基因中具有相同的外显子(参见第一组和第四组)。我想删除这些“重复” - 即删除gene1或gene4(删除哪个并不重要)。

我已经把头撞在墙上好几个小时了,试图做(我认为)是一项简单的任务。谁能指出我正确的方向?我知道人们经常使用哈希来删除重复的元素,但这些并不完全是重复的(因为基因名称不同)。重要的是我也不会丢失基因名称。否则这会更简单。

这是我尝试过的完全没有功能的循环。 “外显子”数组将每一行存储为标量,因此是子例程。不要笑。我知道它不起作用,但至少你可以看到(我希望)我正在尝试做的事情:

for (my $i = 0; $i < scalar @exons; $i++) {
my @temp_line = line_splitter($exons[$i]);                      # runs subroutine turning scalar into array
for (my $j = 0; $j < scalar @exons_dup; $j++) {
    my @inner_temp_line = line_splitter($exons_dup[$j]);        # runs subroutine turning scalar into array
    unless (($temp_line[1] == $inner_temp_line[1]) &&           # this loop ensures that the the loop
            ($temp_line[3] eq $inner_temp_line[3])) {           # below skips the identical lines
                if (($temp_line[1] == $inner_temp_line[1]) &&   # if the coordinates are the same
                    ($temp_line[2] == $inner_temp_line[2])) {   # between the comparisons
                        splice(@exons, $i, 1);                  # delete the first one
                    }
            }
}

}

【问题讨论】:

    标签: perl duplicates bioinformatics


    【解决方案1】:

    您可以使用散列来对 passant 进行重复数据删除,但您需要一种方法将要用于检测重复项的部分连接到一个字符串中。

    sub extract_dup_check_string {
        my $exon = shift;
        my @parts = line_splitter($exon);
        # modify to suit:
        my $dup_check_string = join( ';', @parts[0..2] );
        return $dup_check_string;
    }
    
    my %seen;
    @deduped_exons = grep !$seen{ extract_dup_check_string($_) }++, @exons;
    

    【讨论】:

      【解决方案2】:

      您可以使用哈希来跟踪您已经看到的重复项,然后跳过它们。此示例假定输入文件中的字段以空格分隔:

      #!/usr/bin/env perl                                                                                                                                                                                                                   
      
      use strict;
      use warnings;
      
      my %seen;
      while (my $line = <>) {
      
        my($chromosome, $exon_start, $exon_end, $gene) = split /\s+/, $line;
        my $key = join ':', $chromosome, $exon_start, $exon_end;
      
        if ($seen{$key}) {
          next;
        }
        else {
          $seen{$key}++;
          print $line;
        }
      
      }
      

      【讨论】:

      • 如果您喜欢简洁而不是清晰,我的解决方案可以重写为 perl 单行:perl -lanF"\s" -e 'print unless $seen{join(":", @F[0-2])}++' input_file
      • 感谢 ysth 和 Sam 的回复。我正在自学 Perl,所以我还不太了解哈希,因为到目前为止我还没有在我的斗争中看到实际用途。在我对哈希进行更多阅读之后,我将使用你们两个编写的代码,以便更好地理解你们所写的内容。
      【解决方案3】:
      my @exons = (
          'chr1 1000 2000 gene1',
          'chr1 3000 4000 gene2',
          'chr1 5000 6000 gene3',
          'chr1 1000 2000 gene4'
      );
      
      my %unique_exons = map { 
          my ($chro, $scoor, $ecoor, $gene) = (split(/\s+/, $_));
          "$chro $scoor $ecoor" => $gene
      } @exons;
      
      print "$_ $unique_exons{$_} \n" for keys %unique_exons;
      

      这将为您提供唯一性,并且将包括最后一个基因名称。这导致:

      chr1 1000 2000 gene4 
      chr1 5000 6000 gene3 
      chr1 3000 4000 gene2
      

      【讨论】:

      • 嗯,这似乎行得通。我说好像是因为我没有亲眼看过它——现在我要去了解更多关于“地图”和哈希的信息。
      • 现在我已经更仔细地观察了它,我想我明白它在做什么——而且它很优雅。我正在考虑使用基因名称作为键,其余作为值,但这是一种(简洁)相反的方式。由于您不能拥有相同的密钥,因此会删除重复项。所以保留的基因名称是“最后一个”,对吧?
      【解决方案4】:

      就这么简单。我尽量少用魔法。

      my %exoms = ();
      my $input;
      
      open( $input, '<', "lines.in" ) or die $!;
      
      while( <$input> )
      {
          if( $_ =~ /^(\w+\s+){3}(\w+)$/ ) #ignore lines that are not in expected format
          {
              my @splits = split( /\s+/, $_ ); #split line in $_ on multiple spaces
      
              my $key = $splits[1] . '_' . $splits[2];
      
              if( !exists( $exoms{$key} ) )
              {
                  #could output or write to a new file here, probably output to a file
                  #for large sets.
                  $exoms{$key} = \@splits; 
              }
          }
      
      }
      
      
      #demo to show what was parsed from demo input
      while( my ($key, $value) = each(%exoms) )
      {
          my @splits = @{$value};
          foreach my $position (@splits)
          {
              print( "$position " );
          }
          print( "\n" );
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-05
        • 2013-08-27
        • 1970-01-01
        • 2011-01-24
        • 1970-01-01
        • 2013-06-09
        • 1970-01-01
        相关资源
        最近更新 更多