Plu*_*end 2 perl foreach if-statement
我有一个大型数据集(29 列 x 19000 行),我希望能够比较每一行的值并打印描述性输出。
具体来说,我想查询 A 列(@WTcall)中的值,这实际上是一个通过/失败语句。如果数据失败,我想打印“失败声明”并移至下一行,但如果数据通过,我想继续描述数据。
接下来的问题是确定 X (@positive) 和 Y (@negative) 列中的数据属于哪种分类:
(前任:
如果 X 列和 Y 列 >= 0.6,则打印“ABC”
如果 X 列和 Y 列 < 0.6,则打印“CBA”
如果 X 列 >= 0.6 但 Y 列 < 0.6 打印“DEF”
如果 X 列 < 0.6 但 Y 列 >= 0.6 打印“FED”
否则打印“缺少数据”。)
我已经包含了我在下面编写的代码以及示例数据的子集。
我在发布之前运行的测试在代码中被注释掉了。简而言之,如果我注释掉“if 和 elsif 语句”列表,请打印“@WTcall\t@positive\t@negative\n”并将其通过 head 命令传送 - 我的变量似乎正在提取正确的信息。
问题出现在实际比较中,因为每一行都被分类为“Methylated\tMethylated\n”描述。我不清楚这是为什么。我知道我有 @WTcall 列应该匹配 $BadPosition(通过/失败检查)的条目。此外,如果我再次注释掉“if 语句”,则打印“@WTcall\n$BadPosition”并将其通过 sort 和 uniq 进行管道传输 - 我只得到“No_WT_Concensus”的一个值,因此那里应该没有拼写错误或匹配问题这些值。
我确信这个问题很明显并且正直盯着我的脸,所以我真的很感激任何帮助。
谢谢你。
代码:
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
die "Usage: $0 Filename\n" if @ARGV != 1;
my $file = shift;
my @line;
my @positive;
my @negative;
my @WTcall;
my $BadPosition = 'No_WT_Concensus';
my $i;
open my $infh, '<', $file;
while (<$infh>) {
chomp;
@line = split(/\t/,$_);
$WTcall[0]=$line[0];
$positive[0]=$line[14];
$negative[0]=$line[29];
#foreach $1 (<$infh>) {
foreach $1 (@WTcall) {
if (@WTcall eq $BadPosition){
print "No_WT_Concensus\tNo_WT_Concensus\n";
} elsif (@positive >= 0.6 && @negative >= 0.6){
print "Methylated\tMethylated\n";
} elsif (@positive <= 0.6 && @negative <= 0.6){
print "Under-methylated\tUnder-methylated\n";
} elsif(@positive >= 0.6 && @negative <=0.6){
print "Hemimethylated (m6A)\tHemimethylated (A)\n";
} elsif(@positive <= 0.6 && @negative >= 0.6){
print "Hemimethylated (A)\tHemimethylated (m6A)\n";
} else{
print "Missing_Site\tMissing_Site\n";
}
#print "@WTcall\n$BadPosition\n";
#print "@WTcall\t@positive\t@negative\n"
#print "@negative\n";
}
}
close $infh;
Run Code Online (Sandbox Code Playgroud)
样本数据:
Methylated coding gene 619 thrA NC_000913.3 pos 3 1 0.9535 1 NC_000913.3 619 + 18 0.8889 Methylated coding gene 620 thrA NC_000913.3 neg 3 0.9429 0.9756 0.9714 NC_000913.3 620 - 14 1
No_WT_Concensus coding gene 195410 ispU NC_000913.3 pos 2 0.5789 0.766 0.6071 NC_000913.3 195410 + 39 0.5897 Methylated coding gene 195411 ispU NC_000913.3 neg 3 0.75 0.9074 0.9306 NC_000913.3 195411 - 21 0.8095
Under-methylated pseudogene 3632965 yhiL NC_000913.3 pos 0 0.0323 0.1429 0.0962 NC_000913.3 3632965 + 22 0.0909 Under-methylated pseudogene 3632966 yhiL NC_000913.3 neg 0 0.1463 0.175 0.1429 NC_000913.3 3632966 - 23 0
Methylated intergenic 164636 hrpB-mrcB NC_000913.3 pos 3 0.7381 0.7647 0.7273 NC_000913.3 164636 + 25 0.8 Methylated intergenic 164637 hrpB-mrcB NC_000913.3 neg 3 0.7 0.7931 0.7213 NC_000913.3 164637 - 25 0.4
Methylated intergenic 269287 ykfA-perR NC_000913.3 pos 3 0.875 0.8833 0.931 NC_000913.3 269287 + 22 0.8182 Methylated intergenic 269288 ykfA-perR NC_000913.3 neg 3 0.8077 0.6866 0.6491 NC_000913.3 269288 - 17 0.5294
Methylated coding gene 4397856 mutL NC_000913.3 pos 3 0.9245 0.9831 0.9661 blank blank blank blank blank Methylated coding gene 4397857 mutL NC_000913.3 neg 3 0.9783 0.9808 0.9683 NC_000913.3 4397857 - 1 0
Methylated coding gene 4397969 mutL NC_000913.3 pos 3 0.9643 0.9524 1 blank blank blank blank blank Methylated coding gene 4397970 mutL NC_000913.3 neg 3 1 1 1 blank blank blank blank blank
Methylated coding gene 2761 thrA NC_000913.3 pos 3 0.9259 0.8654 0.9242 NC_000913.3 2761 + 31 1 Methylated coding gene 2762 thrA NC_000913.3 neg 3 0.913 0.9636 0.9767 NC_000913.3 2762 - 29 0.9655
Methylated coding gene 3073 thrB NC_000913.3 pos 3 0.9677 0.8983 1 NC_000913.3 3073 + 29 1 Methylated coding gene 3074 thrB NC_000913.3 neg 3 1 0.9038 0.9778 NC_000913.3 3074 - 31 1
Run Code Online (Sandbox Code Playgroud)
以下是您的要求,经过编辑以显示并行结构:
X >= 0.6 和 Y >= 0.6 然后“ABC”
X < 0.6 和 Y < 0.6 然后是“CBA”
X >= 0.6 但 Y < 0.6 然后“DEF”
X < 0.6 但 Y >= 0.6 然后“美联储”
一些要求是< 0.6,但在您的代码中您有<= 0.6。
你有两件事要测试,你应该首先寻找一种结构,每件事只测试一次。这是表达这一点的伪代码:
if X >= 0.6
if Y >= 0.6
"ABC"
else
"DEF"
else
if Y >= 0.6
"FED"
else
"CBA"
Run Code Online (Sandbox Code Playgroud)
一旦你知道一个值是否大于或等于一个值,你也知道它是否小于,所以你不必再次测试。测试只是分叉;如果您不选择一个分支,则必须选择另一个分支。
您的代码有点不同,因为它同时匹配$x >= 0.6or $x <= 0.6,并且相同 for $y。这意味着,如果两个$x和$y的0.6,那么任何brnach可以匹配,你会得到在链中的第一个。这似乎是代码中的错误,因为它不是您在文本中所描述的。
我不得不做许多项目,这些项目有很长的这类选择列表,许多项目有数百项要测试。
现在,诀窍是将其转换为 Perl。请记住,子例程返回最后计算的表达式,因此它有效:
my @x_y = (
[ 0.1, 0.7 ],
[ 0.1, 0.1 ],
[ 0.7, 0.1 ],
[ 0.7, 0.7 ]
);
foreach my $x_y ( @x_y ) {
printf "X: %.1f Y: %.1f --> %s\n", @$x_y, get_value( @$x_y );
}
sub get_value {
my( $x, $y ) = @_;
if( $x >= 0.6 ) { $y >= 0.6 ? 'ABC' : 'DEF' }
else { $y >= 0.6 ? 'FED' : 'CBA' }
}
Run Code Online (Sandbox Code Playgroud)
如果我不传递一个值,我什至可能会参数化枢轴值并给它一个值:
sub get_value {
my( $x, $y, $pivot ) = @_;
$pivot //= 0.6; # default value
if( $x >= $pivot ) { $y >= $pivot ? 'ABC' : 'DEF' }
else { $y >= $pivot ? 'FED' : 'CBA' }
}
Run Code Online (Sandbox Code Playgroud)
使用(实验性)子程序签名,这会更清晰一些,因为我可以设置默认值:
use v5.22;
use feature qw(signatures);
no warnings qw(experimental::signatures);
sub get_value ( $x, $y, $pivot = 0.6 ){
if( $x >= $pivot ) { $y >= $pivot ? 'ABC' : 'DEF' }
else { $y >= $pivot ? 'FED' : 'CBA' }
}
Run Code Online (Sandbox Code Playgroud)
但事情会变得更有趣。我已经对 重复了那个测试$y,但我可以保存比较的结果:
use v5.22;
use feature qw(signatures);
no warnings qw(experimental::signatures);
sub get_value ( $x, $y, $pivot = 0.6 ){
my $boolean = ($y >= $pivot);
if( $x >= $pivot ) { $boolean ? 'ABC' : 'DEF' }
else { $boolean ? 'FED' : 'CBA' }
}
Run Code Online (Sandbox Code Playgroud)
但是,我真的在这里做什么?我正在尝试选择一个值。我在代码中将其表示为决策树。如果我能把它翻过来呢?我可以使用以下方法执行相同的保存结果技巧$x:
use v5.22;
use feature qw(signatures);
no warnings qw(experimental::signatures);
sub get_value ( $x, $y, $pivot = 0.6 ){
my $y_boolean = ($y >= $pivot);
my $x_boolean = ($x >= $pivot);
if( $x_boolean ) { $y_boolean ? 'ABC' : 'DEF' }
else { $y_boolean ? 'FED' : 'CBA' }
}
Run Code Online (Sandbox Code Playgroud)
所以现在我遇到了布尔组合 (0,0)、(0,1)、(1,0) 和 (1,1) 的情况。我将使用它们作为数组索引。该state做持久varaible所以我不需要每次调用子程序的时间来重新定义它。Perl v5.28 允许您在 中初始化数组和散列state,对于早期版本,您只需使用引用:
use v5.28;
use feature qw(signatures);
no warnings qw(experimental::signatures);
sub get_value ( $x, $y, $pivot = 0.6 ) {
state @table = (
[ qw(CBA FED) ],
[ qw(DEF ABC) ]
);
my $y_boolean = ($y >= $pivot);
my $x_boolean = ($x >= $pivot);
$table[$x_boolean][$y_boolean];
}
Run Code Online (Sandbox Code Playgroud)
或者,稍微紧凑一点,我可以将比较放在数组索引中:
use v5.28;
use feature qw(signatures);
no warnings qw(experimental::signatures);
sub get_value ( $x, $y, $pivot = 0.6 ){
state @table = (
[ qw(CBA FED) ],
[ qw(DEF ABC) ]
);
$table[$x >= $pivot][$y >= $pivot];
}
Run Code Online (Sandbox Code Playgroud)
现在这些值与机制分离了——我在掌握 Perl 中花了很多时间。这也可以是一个参数,尽管现在它必须是一个数组引用,因为数组参数不能有默认值:
use v5.28;
use feature qw(signatures);
no warnings qw(experimental::signatures);
my @x_y = (
[ 0.1, 0.7 ],
[ 0.1, 0.1 ],
[ 0.7, 0.1 ],
[ 0.7, 0.7 ]
);
my $pivot = 0.6;
my @table = ( [ qw(CBA FED) ], [ qw(DEF ABC) ] );
foreach my $x_y ( @x_y ) {
printf "X: %.1f Y: %.1f --> %s\n", @$x_y,
get_value( @$x_y, $pivot, \@table );
}
sub get_value ( $x, $y, $pivot = 0.6,
@table = ([ qw(DEF FED) ], [ qw(ABC CBA) ]) )
{
$table[$x >= $pivot][$y >= $pivot];
}
Run Code Online (Sandbox Code Playgroud)
这更容易管理。您可以在机制不变的情况下调整枢轴和返回的值。
更进一步,将这些值完全从程序中取出,并将它们放入一个配置文件中。同一个程序可以处理许多其他情况,而无需您对其进行编辑。
回到你的代码。choroba 向您展示了这一点,它解决了一些问题,但仍然保留了<=问题:
while (<$infh>) {
chomp;
my @columns = split /\t/;
my ($wt_call, $positive, $negative) = @columns[0, 14, 29];
if ($wt_call eq $BadPosition) {
print "No_WT_Concensus\tNo_WT_Concensus\n";
} elsif ($positive >= 0.6 && $negative >= 0.6) {
print "Methylated\tMethylated\n";
} elsif ($positive <= 0.6 && $negative <= 0.6) {
print "Under-methylated\tUnder-methylated\n";
} elsif ($positive >= 0.6 && $negative <=0.6) {
print "Hemimethylated (m6A)\tHemimethylated (A)\n";
} elsif ($positive <= 0.6 && $negative >= 0.6) {
print "Hemimethylated (A)\tHemimethylated (m6A)\n";
} else {
print "Missing_Site\tMissing_Site\n";
}
}
Run Code Online (Sandbox Code Playgroud)
稍微清理一下,你有一个while控制处理每一行的部分,以及一个处理控制值的部分的子程序。
use v5.28;
use feature qw(signatures);
no warnings qw(experimental::signatures);
while( <$infh> ) {
chomp;
my( $wt_call, $positive, $negative ) = (split /\t/)[0,14,29];
if( $wt_call eq ... ) {
print "No_WT_Concensus\tNo_WT_Concensus\n";
next;
}
say get_value( $positive, $negative );
}
sub get_value ( $x, $y, $pivot = 0.6 ){
state @table = (
[ qw(CBA FED) ],
[ qw(DEF ABC) ]
);
$table[$x >= $pivot][$y >= $pivot];
}
Run Code Online (Sandbox Code Playgroud)
请注意,else由于您已经涵盖了所有情况,因此条件无法达到,因此我省略了这一点。如果在另一种情况下您想查看空字段(null 与 0),您可以在get_value. 一种方法是查看字段的长度。如果为 0(无字符),则不计算。您可以有 0、1 或 2 个空字段,这些可能是不同的情况:
while( <$infh> ) {
chomp;
my( $wt_call, $positive, $negative ) = (split /\t/)[0,14,29];
if( $wt_call eq ... ) {
print "No_WT_Concensus\tNo_WT_Concensus\n";
next;
}
# what if this is 1?
unless( 2 == grep { length } ($positive, $negative) ) {
print "No_WT_Concensus\tNo_WT_Concensus\n";
next;
}
say get_value( $positive, $negative );
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
298 次 |
| 最近记录: |