使用awk选择差值小于某给定值的两列元素
在对数值分析进行后处理时,我遇到了以下数据选择问题:使用awk选择差值小于某给定值的两列元素,awk,comparison,Awk,Comparison,在对数值分析进行后处理时,我遇到了以下数据选择问题: time_1 result_1 time_2 result_2 1 10 1.1 10.1 2 20 1.6 15.1 3 30 2.1 20.1 4 40
time_1 result_1 time_2 result_2
1 10 1.1 10.1
2 20 1.6 15.1
3 30 2.1 20.1
4 40 2.6 25.1
5 50 3.1 30.1
6 60 3.6 35.1
7 70 4.1 40.1
8 80 4.6 45.1
9 90 5.1 50.1
10 100 5.6 55.1
6.1 60.1
6.6 65.1
7.1 70.1
7.6 75.1
8.1 80.1
8.6 85.1
9.1 90.1
9.6 95.1
10.1 100.1
该文件有4列,第一列(时间_1)表示程序1的计算实例,第二列(结果_1)表示每个实例的计算结果
第三列(time_2)表示另一个程序的计算实例,第四列(result_2)表示该程序2的每个实例的计算结果
现在我只想选择第三列(time_2)中非常接近第一列(time_1)的瞬间,允许的差值小于或等于0.1。例如:
对于time_1列的instant 1,我希望选择time_2列的instant 1.1,因为(1.1-1)=0.1,我不想选择time_2列的其他instant,因为(1.6-1)>0.1,或者(2.1-1)>0.1
对于time_1列的instant 2,我希望选择time_2列的instant 2.1,因为(2.1-2)=0.1,我不想选择time_2列的其他instant,因为(2.6-1)>0.1,或者(3.1-1)>0.1
最后,我想获得以下数据:
time_1 result_1 time_2 result_2
1 10 1.1 10.1
2 20 2.1 20.1
3 30 3.1 30.1
4 40 4.1 40.1
5 50 5.1 50.1
6 60 6.1 60.1
7 70 7.1 70.1
8 80 8.1 80.1
9 90 9.1 90.1
10 100 10.1 100.1
我希望使用awk,但我还不熟悉此代码。我不知道如何修复第一列的元素,然后将其与第三列的所有元素进行比较,以选择第三列的正确值。如果我这样做很简单,我只能打印第一行:
{if (($3>=$1) && (($3-$1) <= 0.1)) {print $2, $4}}
{如果($3>=$1)&($3-$1)您可以尝试以下perl脚本:
#! /usr/bin/perl
use strict;
use warnings;
use autodie;
use File::Slurp qw(read_file);
my @lines=read_file("file");
shift @lines; # skip first line
my @a;
for (@lines) {
my @fld=split;
if (@fld == 4) {
push (@a,{id=>$fld[0], val=>$fld[1]});
}
}
for (@lines) {
my @fld=split;
my $id; my $val;
if (@fld == 4) {
$id=$fld[2]; $val=$fld[3];
} elsif (@fld == 2) {
$id=$fld[0]; $val=$fld[1];
}
my $ind=checkId(\@a,$id);
if ($ind>=0) {
$a[$ind]->{sel}=[] if (! exists($a[$ind]->{sel}));
push(@{$a[$ind]->{sel}},{id=>$id,val=>$val});
}
}
for my $item (@a) {
if (exists $item->{sel}) {
my $s= $item->{sel};
for (@$s) {
print $item->{id}."\t".$item->{val}."\t";
print $_->{id}."\t".$_->{val}."\n";
}
}
}
sub checkId {
my ($a,$id) = @_;
my $dif=0.1+1e-10;
for (my $i=0; $i<=$#$a; $i++) {
return $i if (abs($a->[$i]->{id}-$id)<=$dif)
}
return -1;
}
!/usr/bin/perl
严格使用;
使用警告;
使用自动模具;
使用文件::Slurp qw(读取文件);
my@lines=读取文件(“文件”);
shift@lines;#跳过第一行
我的@a;
对于(@行){
my@fld=拆分;
如果(@fld==4){
push(@a,{id=>$fld[0],val=>$fld[1]});
}
}
对于(@行){
my@fld=拆分;
我的$id;我的$val;
如果(@fld==4){
$id=$fld[2];$val=$fld[3];
}elsif(@fld==2){
$id=$fld[0];$val=$fld[1];
}
my$ind=checkId(\@a$id);
如果($ind>=0){
$a[$ind]->{sel}=[]如果(!存在($a[$ind]->{sel}));
push(@{$a[$ind]->{sel},{id=>$id,val=>$val});
}
}
我的$item(@a){
如果(存在$item->{sel}){
my$s=$item->{sel};
就(@$s){
打印$item->{id}.\t.“$item->{val}.\t”;
打印$\>{id}.\t“$\>{val}.\n”;
}
}
}
子检查ID{
我的($a,$id)=@;
my$dif=0.1+1e-10;
对于(my$i=0;$i[$i]->{id}-$id)有一件事需要注意:由于浮点数的变化无常,将值与0.1进行比较不太可能得到您想要的结果:
awk 'BEGIN {x=1; y=x+0.1; printf "%.20f", y-x}'
0.10000000000000008882⏎
这里,y=x+0.1
,但是y-x>0.1
因此,我们将差异视为diff=10*y-10x
:
另外,我将处理该文件两次:一次获取所有时间\ 1/result \ 1值,第二次提取“匹配的”时间\ 2/result \ 2值
awk '
NR==1 {print; next}
NR==FNR {if (NF==4) r1[$1]=$2; next}
FNR==1 {next}
{
if (NF == 4) {t2=$3; r2=$4} else {t2=$1; r2=$2}
for (t1 in r1) {
diff = 10*t1 - 10*t2;
if (-1 <= diff && diff <= 1) {
print t1, r1[t1], t2, r2
break
}
}
}
' ~/tmp/timings.txt ~/tmp/timings.txt | column -t
对于第1列中的每个值,第3列中是否有一个相关的瞬间?或者对于第1列中的给定值,第3列中是否有许多候选项?我想如果第1列和第2列在一个文件中,第3列和第4列在另一个文件中,提取和格式化数据会更容易。。(因为列长度似乎不同,这使得处理awk
和其他文本处理工具更加麻烦)实际上,虽然在本例中,第3列中只有一个元素满足选择标准,但我希望能够为第1列中的每个给定元素识别第3列中的一些元素。我想使用数组存储数据,然后更容易地操作数据,但我尚未成功。第1列中的项目数是否始终为小于或等于第3列中的项目数?(通过这种方式,程序可以知道在一行中只有两个项目的情况下,它们将属于第3列和第4列,而不是第1列和第2列)我无法从第二个命令行运行程序。它总是只打印数据文件的第一行,这意味着只打印命令行'NR==1{print;next}'已被考虑。如果我删除此项,则没有结果行。请您解释一下为什么以及如何解决此问题?我可以这样做,只是因为我运行了'awk-f…',但我忘记了按照您的建议处理文件两次。
time_1 result_1 time_2 result_2
1 10 1.1 10.1
2 20 2.1 20.1
3 30 3.1 30.1
4 40 4.1 40.1
5 50 5.1 50.1
6 60 6.1 60.1
7 70 7.1 70.1
8 80 8.1 80.1
9 90 9.1 90.1
10 100 10.1 100.1