使用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