Perl:从多列文件的每一列计算切刀误差
Perl: calculate jackknife error from of each column of a multi-column file
我正在尝试计算多列文件中每列的 jacknife 平均值和误差。
我的示例数据文件如下所示:
$ cat data.HW2
1.1 2.1 3.1 4.1
1.2 2.2 3.2 4.2
1.3 2.3 3.3 4.3
1.4 2.4 3.4 4.4
我尝试的解决方案是定义最终大小与列数(在本例中为 4)相同的数组,并逐行迭代它们:
cat jackkinfe.pl
#! /usr/bin/perl
use warnings; use strict;
my @n=0;
my @x;
my $j;
my $i;
my $dg;
my @x_jack;
my @x_tot=0;
my $cols;
my $col_start=0;
# read in the data
while(<>)
{
my @column = split();
$cols=@column;
foreach my $j ($col_start .. $#column) {
$x[$n[$j]][$j] = $column[$j];
$x_tot[$j] += $x[$n[$j]][$j];
$n[$j]++;
}
}
# Do the jackknife estimates
for ($j=$col_start; $j<$cols; $j++)
{
for ($i = 0; $i < $n[$j]; $i++)
{
$x_jack[$i][$j] = ($x_tot[$j] - $x[$i][$j]) / ($n[$j] - 1);
}
# Do the final jackknife estimate
my @g_jack_av=0;
my @g_jack_err=0;
for ($i = 0; $i < $n[$j]; $i++)
{
$dg = $x_jack[$i][$j];
$g_jack_av[$j] += $dg;
$g_jack_err[$j] += $dg**2;
}
$g_jack_av[$j] /= $n[$j];
$g_jack_err[$j] /= $n[$j];
$g_jack_err[$j] = sqrt(($n[$j] - 1) * abs($g_jack_err[$j] - $g_jack_av[$j]**2));
printf "%e %e ", $g_jack_av[$j], $g_jack_err[$j];
}
printf "\n";
它给了我以下两个警告:
$cat data.HW2 | perl jackknife.pl
Use of uninitialized value within @n in array element at cols_jacknife.pl line 19, <> line 1.
Use of uninitialized value within @n in array element at cols_jacknife.pl line 20, <> line 1.
在下面两行报错:
$x[$n[$j]][$j] = $column[$j];
$x_tot[$j] += $x[$n[$j]][$j];
但是我想根据数据文件的大小动态设置@n
的大小
如何删除此警告?
对于我的 Perl 使用的任何其他建议也欢迎并非常感谢,因为我正在努力学习最佳实践。
你的这部分代码
my @n=0;
....
foreach my $j ($col_start .. $#column) {
$x[$n[$j]][$j] = $column[$j];
$x_tot[$j] += $x[$n[$j]][$j];
$n[$j]++;
}
对于$j
的每个值大于0都会触发一次警告,因为只定义了@n
中的第一个元素:$n[0] = 0
。只有在循环迭代结束时,数组值才最终定义,当它被增量运算符设置为 1
时 $n[$j]++
.
从技术上讲,该代码仍会按您预期的那样工作,因为 undef
将转换为 0
。所以....忽略警告应该是安全的。你可以在你的循环中做这样的事情来避免它:
$n[$j] //= 0; # $n[$j] is defined, or set to 0
这相当于
if (not defined($n[$j])) {
$n[$j] = 0;
}
我正在尝试计算多列文件中每列的 jacknife 平均值和误差。 我的示例数据文件如下所示:
$ cat data.HW2
1.1 2.1 3.1 4.1
1.2 2.2 3.2 4.2
1.3 2.3 3.3 4.3
1.4 2.4 3.4 4.4
我尝试的解决方案是定义最终大小与列数(在本例中为 4)相同的数组,并逐行迭代它们:
cat jackkinfe.pl
#! /usr/bin/perl
use warnings; use strict;
my @n=0;
my @x;
my $j;
my $i;
my $dg;
my @x_jack;
my @x_tot=0;
my $cols;
my $col_start=0;
# read in the data
while(<>)
{
my @column = split();
$cols=@column;
foreach my $j ($col_start .. $#column) {
$x[$n[$j]][$j] = $column[$j];
$x_tot[$j] += $x[$n[$j]][$j];
$n[$j]++;
}
}
# Do the jackknife estimates
for ($j=$col_start; $j<$cols; $j++)
{
for ($i = 0; $i < $n[$j]; $i++)
{
$x_jack[$i][$j] = ($x_tot[$j] - $x[$i][$j]) / ($n[$j] - 1);
}
# Do the final jackknife estimate
my @g_jack_av=0;
my @g_jack_err=0;
for ($i = 0; $i < $n[$j]; $i++)
{
$dg = $x_jack[$i][$j];
$g_jack_av[$j] += $dg;
$g_jack_err[$j] += $dg**2;
}
$g_jack_av[$j] /= $n[$j];
$g_jack_err[$j] /= $n[$j];
$g_jack_err[$j] = sqrt(($n[$j] - 1) * abs($g_jack_err[$j] - $g_jack_av[$j]**2));
printf "%e %e ", $g_jack_av[$j], $g_jack_err[$j];
}
printf "\n";
它给了我以下两个警告:
$cat data.HW2 | perl jackknife.pl
Use of uninitialized value within @n in array element at cols_jacknife.pl line 19, <> line 1.
Use of uninitialized value within @n in array element at cols_jacknife.pl line 20, <> line 1.
在下面两行报错:
$x[$n[$j]][$j] = $column[$j];
$x_tot[$j] += $x[$n[$j]][$j];
但是我想根据数据文件的大小动态设置@n
的大小
如何删除此警告?
对于我的 Perl 使用的任何其他建议也欢迎并非常感谢,因为我正在努力学习最佳实践。
你的这部分代码
my @n=0;
....
foreach my $j ($col_start .. $#column) {
$x[$n[$j]][$j] = $column[$j];
$x_tot[$j] += $x[$n[$j]][$j];
$n[$j]++;
}
对于$j
的每个值大于0都会触发一次警告,因为只定义了@n
中的第一个元素:$n[0] = 0
。只有在循环迭代结束时,数组值才最终定义,当它被增量运算符设置为 1
时 $n[$j]++
.
从技术上讲,该代码仍会按您预期的那样工作,因为 undef
将转换为 0
。所以....忽略警告应该是安全的。你可以在你的循环中做这样的事情来避免它:
$n[$j] //= 0; # $n[$j] is defined, or set to 0
这相当于
if (not defined($n[$j])) {
$n[$j] = 0;
}