0

我有一些以下格式的输入数据(制表符划定):

(基因条件值)

wnt condition1  1
wnt condition2  10
wnt condition3  15
wnt condition4  -1
bmp condition1  10
bmp condition2  inf
bmp condition3  12
bmp condition4  -1
frz condition1  -12
frz condition2  -6
frz condition3  -0.3

我正在构建一个 HoH,如下所示:

#!/usr/bin/perl
use warnings;
use strict; 
use File::Slurp;
use Data::Dumper;

my @data = read_file('stack.txt');

my %hash;
foreach (@data){
    chomp;
    my ($gene, $condition, $value) = (/^(\w+)\t(\w+\d)\t(-?\d+|-?inf)/);
    $hash{$gene}{$condition} = $value;
}

我想遍历 HoH,并且对于每个基因,打印出该基因的所有值是正数(例如 10)或负数(-3)的值。在上面的数据中,我只会打印出:

frz condition1  -12
frz condition2  -6
frz condition3  -0.3

由于其他两个基因都包含具有正负值的条件:

wnt condition1  1
wnt condition2  10
wnt condition3  15
wnt condition4  -1 # discrepancy

bmp condition1  10
bmp condition2  inf
bmp condition3  12
bmp condition4  -1 # discrepancy 

我可以按如下方式循环,但不确定如何在一个 HoH 值和该基因条件键组合的“下一个”值之间进行比较:

for my $gene (sort keys %hash) { 
     for my $condition (sort keys %{$hash{$gene}}) {
        my $value = $hash{$gene}{$condition};
        print "$gene\t$condition\t$value\n" if $value  =~ m/-/;  # This obviously will only print out negative values. I want to compare all values here, and if they are all positive, or all negative, print them.        
    }
}

让我知道如果我能进一步澄清这一点

4

3 回答 3

1

此代码通过检查每个基因的哈希值中的所有值来解决问题,$neg如果值包含减号则递增,否则$pos。如果正计数或负计数为零,则所有值的符号相同,并且对该基因的数据进行分类和显示。

请注意,这很重要inf,并且0是积极的,这可能是也可能不是想要的。

请注意,使用read_file是浪费的,因为它一次将整个文件拉入内存。与其循环遍历数组,不如使用while循环并逐行读取文件。use autodie无需检查文件open调用是否成功。

use strict;
use warnings;
use autodie;

open my $fh, '<', 'stack.txt';

my %data;

while (<$fh>) {
  chomp;
  my ($gene, $condition, $value) = split /\t/;
  $data{$gene}{$condition} = $value;
}

while (my ($gene, $values) = each %data) {

  my ($pos, $neg) = (0, 0);

  ++(/-/ ? $neg : $pos) for values %$values;

  unless ($neg and $pos) {
    for my $condition (sort keys %$values) {
      printf "%s\t%s\t%s\n", $gene, $condition, $values->{$condition};
    }
  }
}

输出

frz condition1  -12
frz condition2  -6
frz condition3  -0.3
于 2013-10-09T20:35:28.760 回答
1

您可以遍历给定基因的整个值列表,并为正值和负值增加单独的计数器,然后比较计数以查看是否存在差异,而不是单独将一个值与其邻居进行比较。

假设您的数据符合以下方案:

'bmp' => HASH(0x7324710)
   'condition1' => 10
   'condition2' => 'inf'
   'condition3' => 12
   'condition4' => '-1'
'frz' => HASH(0x7323c78)
   'condition1' => '-12'
   'condition2' => '-6'
   'condition3' => '-0.3'
'wnt' => HASH(0x72a5c30)
   'condition1' => 1
   'condition2' => 10
   'condition3' => 15
   'condition4' => '-1'

对于您问题中的最后一个代码块,此替换将为您提供所需的结果:

for my $gene (sort keys %hash) {
    # These variables will contain:
    # - Counts of positive and negative values
    my ($pos_vals, $neg_vals) = (0, 0);
    # - A true/false value indicating whether discrepancy exists
    my $discrepant = undef;
    # - A list of the values of all conditions for a given gene
    my @values = ();

    # Collect condition values for this gene into @values
    my @values = values %{ $hash{$gene} };

    # For each such value, test for a leading - and increment
    # the positive or negative value count accordingly
    for @values { $_ =~ m/^-/ ? $neg_vals++ : $pos_vals++ };

    # If neither counter is zero (i.e. both evaluate true), then
    # a discrepancy exists; otherwise, one doesn't -- either way,
    # we put the test result in $discrepant so as to produce a
    # cleaner test in the following if statement
    $discrepant = (($pos_vals > 0) and ($neg_vals > 0));

    # In the absence of a discrepancy...
    if (not $discrepant) {
        # iterate over the conditions for this gene and print the gene
        # name, the condition name, and the value
        # NB: this is somewhat idiomatic Perl, but you'll tend to see
        # it from time to time and it's thus worth knowing about
        print "$gene\t$_\t$hash{$gene}->{$_}\n"
          foreach sort keys %{ $hash{$gene} };
    };
}

注意:这将正确处理正无穷和负无穷,但会将零视为正无穷,这可能不适合您的情况。您的数据中是否出现零值?如果是这样,它们应该被视为正面、负面还是两者都不是?

于 2013-10-09T18:47:13.130 回答
-1
my @data = <$your_file_handle>;

my %hash;
foreach (@data){
    chomp;
    my ($gene, $condition, $value) = split; #Sorry, your regex didn't work for me, 
                                            #hence the change.
    $hash{$gene}{$condition} = $value;
}

for my $gene (sort keys %hash){
    my $values = join '', values $hash{$gene};
    my $num = %{$hash{$gene}}/1;  #Number of conditions

    #when no '-' is detected or number of '-' matches the one of conditions, print.
    say $gene if ($values !~ /-/ or $values =~ tr/-/-/ == $num); 
}
于 2013-10-09T19:56:21.567 回答