2

我有一个 HoHoA 设置如下:

#!/usr/bin/perl
use warnings;
use strict;

my %experiment = (
    'gene1' =>  {
                       'condition2' => ['XLOC_000347','80', '0.5'],
                       'condition3' => ['XLOC_000100', '50', '0.2']
                   },
    'gene2'   =>  {
                       'condition1' => ['XLOC_025437', '100', '0.018'],
                       'condition2' => ['XLOC_000322', '77', '0.22'],
                       'condition3' => ['XLOC_001000', '43', '0.02']
                   },
    'gene3'   =>  {
                      'condition1' => ['XLOC_025437', '100', '0.018'],
                      'condition3' => ['XLOC_001045', '23', '0.0001']
                   },
    'gene4'   =>  {
                      'condition3' => ['XLOC_091345', '93', '0.005']
                   }

);

我试图找到在至少 2 个条件下重叠的所有“基因”,并且对于每个基因,打印出具有最低值的条件(例如 q_value)。然后我想按这个值排序。到目前为止,这是我的代码:

循环遍历第一个键,以查找出现在第二个键中至少 2 个中的所有键。

my(%overlap, %condition_name);
my ($xloc, $q_val, $percentage, %seen);

for my $gene (sort keys %experiment) { 
    for my $condition (sort keys %{$experiment{$gene}}) {
        $condition_name{$condition} = 1;
        $seen{$gene}++; # Counts for each occurrence of gene 
        $overlap{$gene} = 1 if $seen{$gene} > 1;
    }
}

对于每个重叠实例,打印出找到 key1 的每个条件 (key2) 以及相关值:

my @cond_name = keys %condition_name;
foreach my $gene (keys %overlap){ 
        foreach my $condition (@cond_name){
            next unless exists $experiment{$gene}{$condition};
            ($xloc, $percentage, $q_val) = @{$experiment{$gene}{$condition}};
            print "$condition\t$gene\t$xloc\t$q_val\t$percentage\n";
        }
        print "\n";
}

输出:

condition3  gene3   XLOC_001045 0.0001  23
condition1  gene3   XLOC_025437 0.018   100

condition3  gene1   XLOC_000100 0.2 50
condition2  gene1   XLOC_000347 0.5 80

condition3  gene2   XLOC_001000 0.02    43
condition1  gene2   XLOC_025437 0.018   100
condition2  gene2   XLOC_000322 0.22    77

我正在尝试以两种方式更改输出:

  • 对于 key1 的每个重叠实例,根据其中一个值比较每个第二个键。例如,对于gene 1,我想比较condition3condition2(q_value) 的第一个值并只保留最低值。

期望的输出:

condition3  gene3   XLOC_001045 0.0001  23    
condition3  gene1   XLOC_000100 0.2 50
condition1  gene2   XLOC_025437 0.018   100
  • 其次,我想按我在 (q_value) 上选择的相同值对其进行排序,以给出:

所需的最终输出(见下面的更新):

condition3  gene3   XLOC_001045 0.0001  23
condition1  gene2   XLOC_025437 0.018   100
condition3  gene1   XLOC_000100 0.2 50

更新:16.9.13

我已经开始在这个问题上悬赏,因为答案(虽然很好)并没有完全达到我的期望。如果需要对问题进行任何澄清,请告诉我...

我的最终期望输出也略有变化:如上所述,我想比较每个条件的一个值,并根据该值对基因进行排序。理想情况下,我想为每个排序的基因输出每个条件(并在内部按相同的值排序):

condition3  gene3   XLOC_001045 0.0001  23 # Lowest q_value
condition1  gene3   XLOC_025437 0.018   100 # Other condition(s) for the gene with lowest q_value...

condition1  gene2   XLOC_025437 0.018   100 # For each gene, rank by q_value
condition3  gene2   XLOC_001000 0.02    43
condition2  gene2   XLOC_000322 0.22    77

condition3  gene1   XLOC_000100 0.2 50
condition2  gene1   XLOC_000347 0.5 80
4

4 回答 4

2

您的代码过于复杂。要获取具有两个或多个条件的基因列表,请使用 grep:

my @genes = grep { keys %{$experiment{$_}} >= 2 } keys %experiment;

接下来,我们需要根据它们的最小 q_value 对基因进行排序。最简单的方法(虽然到目前为止不是最有效的方法)是首先找到每个基因的最小值并将其填充到哈希中:

use List::Util qw(min);

my %minimum;
foreach my $gene (@genes) {
    my @q_vals;
    push @q_vals, $experiment{$gene}{$_}[2] for keys %{$experiment{$gene}};
    $minimum{$gene} = min @q_vals;
}

当我们得到所有最小值后,我们可以对它们进行排序:

@genes = sort { $minimum{$a} <=> $minimum{$b} } keys %minimum;

现在我们只需要对每个基因中的条件进行排序并打印出值:

foreach my $gene (@genes) {

    # Sort conditions on the "2th" field (counting from 0)
    my @conditions = sort { $experiment{$gene}{$a}[2] <=> $experiment{$gene}{$b}[2] } keys %{$experiment{$gene}};

    foreach my $condition (@conditions) {
        my ($xloc, $percentage, $q_val) = @{$experiment{$gene}{$condition}};
        print "$condition\t$gene\t$xloc\t$q_val\t$percentage\n";
    }
    print "\n";
}

更新的输出:

condition3  gene3   XLOC_001045 0.0001  23
condition1  gene3   XLOC_025437 0.018   100

condition1  gene2   XLOC_025437 0.018   100
condition3  gene2   XLOC_001000 0.02    43
condition2  gene2   XLOC_000322 0.22    77

condition3  gene1   XLOC_000100 0.2 50
condition2  gene1   XLOC_000347 0.5 80

这不是一个非常有效的方法,因为我们要多次遍历我们的哈希。您可能需要考虑将数据结构更改为更易于管理的东西。

于 2013-09-17T21:43:32.163 回答
1

构建另一个 HoH 而不是打印。最后对其进行迭代以决定要打印的内容。

所以在顶部,添加这个:

my %lowest;
my $sortkey='q_val';

在中间,进行以下编辑:

foreach my $condition (@cond_name){
    next unless exists $experiment{$gene}{$condition};
    ## ($xloc, $percentage, $q_val) = @{$experiment{$gene}{$condition}};
    ## print "$condition\t$gene\t$xloc\t$q_val\t$percentage\n";

    my %cond;
    @cond{ qw( xloc percentage q_val ) } = @{$experiment{$gene}{$condition}};
    # >= may also be appropriate
    if (!defined($lowest{$gene}) or $lowest{$gene}{$sortkey} > $cond{$sortkey}) {  
        @cond{ qw( condition gene ) } = ($condition, $gene); # useful at print time
        $lowest{$gene} = \%cond
    }
}
## print "\n";

最后:

# NB: <=> is for numeric comparison. Use cmp for non-numeric keys.
for my $gene (sort { $lowest{$a}{$sortkey} <=> $lowest{$b}{$sortkey} } keys %lowest) {
    local ($, , $\)=("\t","\n");
    print @{$lowest{$gene}}{qw( condition gene xloc q_val percentage )};
}
于 2013-09-13T12:47:30.940 回答
1

我已经测试了这段代码,我尽可能地简化了它。我从您发布的原始代码开始,希望我没有错过任何第一轮更改。内联评论:

#!/usr/bin/perl
use warnings;
use strict;

my %experiment = (
    'gene1' =>  {
                       'condition2' => ['XLOC_000347','80', '0.5'],
                       'condition3' => ['XLOC_000100', '50', '0.2']
                   },
    'gene2'   =>  {
                       'condition1' => ['XLOC_025437', '100', '0.018'],
                       'condition2' => ['XLOC_000322', '77', '0.22'],
                       'condition3' => ['XLOC_001000', '43', '0.02']
                   },
    'gene3'   =>  {
                      'condition1' => ['XLOC_025437', '100', '0.018'],
                      'condition3' => ['XLOC_001045', '23', '0.0001']
                   },
    'gene4'   =>  {
                      'condition3' => ['XLOC_091345', '93', '0.005']
                   }

);

我将您的一些my声明移到了需要它们的地方。我还创建了qvals哈希,我用它来代替你的overlap哈希。它将包含每个基因的最小 qval,以便于排序。

my (%qvals, %seen);

for my $gene (sort keys %experiment) { 
    for my $condition (sort keys %{$experiment{$gene}}) {
        $seen{$gene}++; # Counts for each occurrence of gene 

所以现在我们需要构建我们的 qvals 哈希。这将是我们打印输出的第一个(外部)排序键。每个基因的第一个条件,我们将保存该基因的 qvalue。对于后续条件,如果我们找到一个较小的 qvalue,我们就保存那个。

        if ((not exists $qvals{$gene}) || # First time we've seen this gene, OR
            ($qvals{$gene} > $experiment{$gene}{$condition}[2])) { # Has a smaller q value
            $qvals{$gene} = $experiment{$gene}{$condition}[2];
        }
    }
}

您可能不熟悉这种排序语法。大括号中的东西{}是“排序块”。通过在 google 或 Linux 控制台中输入信息,您可以学到比我解释的更多的东西perldoc sort——它允许您做非常复杂的事情,但在这里我们使用它的目的只是对我们正在排序的数据以外的其他内容进行排序。keys %qvals在这里,我们根据基因的最小 qvalue对基因 ( ) 进行排序$qvals{$a}$aand$b被 自动使用sort,不用担心声明它们,and <=>is the spaceship operator - 它就像一个超级比较,0如果操作数相等,-1如果左运算符更小,+1如果左运算符更大,则返回。基本上,如果您不指定排序块,排序将{$a <=> $b}默认使用。

foreach my $gene (sort {$qvals{$a} <=> $qvals{$b}} keys %qvals) { # Sort the genes on ascending minimum q-val 
    if ($seen{$gene} == 1) {next;} # Skip gene if it only has one condition
    foreach my $condition (sort # Sort conditions on ascending q-val

另一个复杂的排序,这次是针对每个基因的条件 - 我们根据keys $experiment{$gene}该基因 ( ) 的条件的 q 值对条件 ( ) 进行排序$experiment{$gene}{$a}[2]

                {$experiment{$gene}{$a}[2] <=> $experiment{$gene}{$b}[2]}
                keys $experiment{$gene} ) { 
        next unless exists $experiment{$gene}{$condition};
        my ($xloc, $percentage, $q_val) = @{$experiment{$gene}{$condition}};
        print "$condition\t$gene\t$xloc\t$q_val\t$percentage\n";
    }
    print "\n";
}

我得到以下输出:

condition3      gene3   XLOC_001045     0.0001  23
condition1      gene3   XLOC_025437     0.018   100

condition1      gene2   XLOC_025437     0.018   100
condition3      gene2   XLOC_001000     0.02    43
condition2      gene2   XLOC_000322     0.22    77

condition3      gene1   XLOC_000100     0.2     50
condition2      gene1   XLOC_000347     0.5     80
于 2013-09-18T13:14:29.860 回答
0
use 5.10.0;
$, = "\t";
do {
    my ( $gene, @conds ) = @$_;
    say( ( $gene, @$_ )[ 1, 0, 2, 4, 3 ] ) for @conds;
    say "";
    }
    for (
    sort { $a->[1][3] <=> $b->[1][3] }
    map {
        my $conds = $experiment{$_};
        [   $_ => sort { $a->[3] <=> $b->[3] }
                map { [ $_, @{ $conds->{$_} } ] }
                keys %$conds
        ]
    } grep { keys %{ $experiment{$_} } > 1 } keys %experiment
    );

将输出:

condition3      gene3   XLOC_001045     0.0001  23
condition1      gene3   XLOC_025437     0.018   100

condition1      gene2   XLOC_025437     0.018   100
condition3      gene2   XLOC_001000     0.02    43
condition2      gene2   XLOC_000322     0.22    77

condition3      gene1   XLOC_000100     0.2     50
condition2      gene1   XLOC_000347     0.5     80

或者

use 5.10.0;
$, = "\t";
say @$_[ 1, 0, 2, 4, 3 ]
    for (
    map {
        my ( $gene, @conds ) = @$_;
        map { [ $gene, @$_ ] } @conds
    }
    sort { $a->[1][3] <=> $b->[1][3] }
    map {
        my $conds = $experiment{$_};
        [   $_ => sort { $a->[3] <=> $b->[3] }
                map { [ $_, @{ $conds->{$_} } ] }
                keys %$conds
        ]
    } grep { keys %{ $experiment{$_} } > 1 } keys %experiment
    );

将输出:

condition3      gene3   XLOC_001045     0.0001  23
condition1      gene3   XLOC_025437     0.018   100
condition1      gene2   XLOC_025437     0.018   100
condition3      gene2   XLOC_001000     0.02    43
condition2      gene2   XLOC_000322     0.22    77
condition3      gene1   XLOC_000100     0.2     50
condition2      gene1   XLOC_000347     0.5     80
于 2013-09-18T22:11:32.133 回答