Arrays 对HoHoA值进行排序和比较
我的HoHoA设置如下:Arrays 对HoHoA值进行排序和比较,arrays,perl,sorting,hash,Arrays,Perl,Sorting,Hash,我的HoHoA设置如下: #!/usr/bin/perl use warnings; use strict; my %experiment = ( 'gene1' => { 'condition2' => ['XLOC_000347','80', '0.5'], 'condition3' => ['XLOC_000100', '50', '0.2']
#!/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']
}
);
我试图找到所有在至少两种情况下重叠的“基因”,并为每个基因打印出具有最低值(例如q_值)的情况。然后我想按这个值排序。以下是我目前的代码:
循环第1个关键点,以查找第2个关键点中至少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的每个重叠实例,根据第二个关键点的一个值比较它们。例如,对于
,我想比较gene1
和condition3
(q_值)的第一个值,只保留最低的值condition2
condition3 gene3 XLOC_001045 0.0001 23
condition3 gene1 XLOC_000100 0.2 50
condition1 gene2 XLOC_025437 0.018 100
- 其次,我想按照我选择的相同值(q_值)对其进行排序,以给出:
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
构建另一个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 )};
}
#NB:用于数字比较。对非数字键使用cmp。
对于我的$gene(排序{$lowest{$a}{$sortkey}$lowest{$b}{$sortkey}}}键%lowest){
本地($,$\)=(“\t”,“\n”);
打印{$最低{$基因}{qw(条件基因xloc q_val百分比)};
}
您的代码太复杂了。要获得具有两种或两种以上条件的基因列表,请使用grep:
my @genes = grep { keys %{$experiment{$_}} >= 2 } keys %experiment;
接下来,我们需要根据最小q_值对基因进行排序。最简单的方法(尽管目前不是最有效的方法)是首先找到每个基因的最小值,并将其填入哈希:
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;
这不是一个非常有效的方法,因为我们要多次遍历散列。您可能需要考虑将数据结构更改为更易于管理的东西。 < P>我已经测试过这个代码,这是我尽可能简化的。我从您发布的原始代码开始,希望我没有错过任何最初的更改。注释内联:
#!/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']
}
);
我将您的一些我的声明移动到了需要它们的地方。我还创建了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散列。这将是打印输出的第一个(外部)排序键。对于每个基因的第一个条件,我们将保存该基因的Q值。对于后续的条件,如果我们找到一个较小的Q值,我们将保存该值
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
,您可以学到比我所能解释的多得多的东西-它允许您做非常复杂的事情,但在这里,我们所使用的只是对我们正在排序的数据以外的其他数据进行排序。在这里,我们将基因(键%qvals
)按其最小qvalue$qvals{$a}
进行排序$a
和$b
由排序
自动使用,不必担心声明它们,
是太空船操作符-它就像超级比较,如果操作数相等,返回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
我得到以下输出:
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
或
这太棒了,谢谢。我需要准确地理解这里发生的事情,但这看起来是一个很好的解决方案@cond{qw(…)}=…
将数组转换为哈希。这不是必需的:可以说$sortkey=2
并按数组索引排序。但是,构建一个结果集供以后显示是一个常见的习惯用法,并且创建/使用的时间通常相差很远。将名称附加到字段是很好的@cond{qw(condition-gene)}=…
将标识字段附加到哈希允许您稍后重新构造结果,而不必挖掘父键名称。存储空间是不使用散列的一个原因。如果您的结果集很大,则哈希占用的列表空间大于2倍(无论如何,在本例中)。$,
是打印列表时显示的字段分隔符$\
是记录分隔符。local()约束对该块的赋值;它们将恢复为块外的先前值。它与print join(“\t”,@{…}{…}),“\n”
相同。这实际上并不像我想的那样有效。我得到的输出不一定对应于每个基因q值最低的条件……你能举个例子吗?我的测试程序的输出与您的最终输出一致-太好了-谢谢!这看起来是一个非常优雅的解决方案。然而,我只想按q_值排序,而不是按基因名称排序-我如何对此进行修改?@FlyingFrog从外部foreach
循环中删除sort
。这就是我尝试的。然而,尽管内部条件被正确排序,但基因并不是按q_值进行全局排序的。将你的输出与我的期望输出进行比较,看看我的意思…@FlyingFrog他们也没有在你期望的输出中进行全局排序:最后四个q_值
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];
}
}
}
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
{$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
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