给出以下输入:
MCCC processed: unknown event at: Tue, 14 Oct 2014 12:02:26 CST
station, mccc delay, std, cc coeff, cc std, pol , t0_times , delay_times
ZJ.uno1 -0.7964 0.0051 0.9690 0.0139 0 GRAW.BHZ 301.1263 -1.8041
ZJ.dose -0.7065 0.0072 0.9760 0.0133 0 KNYN.BHZ 301.3372 -1.9249
ZJ.tres 0.9675 0.0072 0.9548 0.0292 0 LEON.BHZ 301.2611 -0.1749
Phase: P
PDE 2013 7 15 14 6 58.00 -60.867 -25.143 31.0 0.0 7.3
我想从每个delay_times中删除第9列(delay_times)的平均值,这需要将第9列值相加,除以这些值的数量,然后从每个值中减去均值( - 1.8041,-1.9249,-0.1749)。
我很困惑从哪里开始这项努力。我在下面提供了一个起始脚本:
#!/usr/bin/perl
use strict;
use warnings;
open my $file '<', "file.txt" or die $!;
while (<$file>) {
my ($name, $time) = (split /\s+/, $file)[1,9];
# Calculate the mean of the 9th column for every row that begins with ZJ,
# and subtract the mean from each value (time) in the 9th column.
}
# Output the new file with the mean removed from each "time" in the 9th column
在awk或perl中这样做会更容易吗?谢谢。
答案 0 :(得分:1)
使用awk:
$ awk '/Phase/{f=0} FNR==NR && f{s+=$9;n++;} /station/{f=1} FNR==NR{next;} FNR==1{ave=s/n} f{$9=$9-ave} 1' file file
MCCC processed: unknown event at: Tue, 14 Oct 2014 12:02:26 CST
station, mccc delay, std, cc coeff, cc std, 1.3013 , t0_times , delay_times
ZJ.uno1 -0.7964 0.0051 0.9690 0.0139 0 GRAW.BHZ 301.1263 -0.5028
ZJ.dose -0.7065 0.0072 0.9760 0.0133 0 KNYN.BHZ 301.3372 -0.6236
ZJ.tres 0.9675 0.0072 0.9548 0.0292 0 LEON.BHZ 301.2611 1.1264
Phase: P
PDE 2013 7 15 14 6 58.00 -60.867 -25.143 31.0 0.0 7.3
由于文件名在命令行中出现两次,因此该程序将读取该文件两次。第一次,它存储s
中第9列数字和n
中第9列数字的总和。因此平均值为s/n
。在第二次通过时,它从第9列的值中减去平均值并打印行。
在我解释问题时,感兴趣的第9列值似乎是以station
开头的行之后和以Phase
开头的行之后的值。我们保留并更新标记f
,以便在我们处于感兴趣的行范围内时发出信号。
/Phase/{f=0}
当我们到达Phase
的行时,将标记f
设置为false,表示我们已到达行范围的末尾。
FNR==NR && f{s+=$9;n++;}
首次阅读文件并且标记f
为真,然后更新总和s
并计算n
。
在awk中,FNR
是到目前为止从当前文件读取的行数,NR
是读取的总行数。因此,如果FNR==NR
,我们仍在阅读第一个文件。
/station/{f=1}
如果我们与station
一致,则将标记f
设置为true以表示感兴趣的行的开头。
FNR==NR{next;}
如果我们是第一次阅读文件,请跳过其余命令并跳转到next
行。
FNR==1{ave=s/n}
如果我们到了这里,我们现在正在第二次阅读该文件。当我们到达第二次阅读的第一行(FNR==1
)时,计算平均值ave
。
f{$9=$9-ave}
如果f
为真,则从第9列ave
中减去平均值$9
。
1
这是awk用于打印线的神秘短手。
答案 1 :(得分:0)
您尝试过的perl解决方案非常适合您 - 您只是没有完成它: - )
“扩展单线”可以如下:
perl -anE 'push @f,[@F] }{ for (@f){ $s += $_->[8] and $n++ if $_->[0] =~ /ZJ/ }
say $_->[0] =~ /ZJ/ ? ( "@{$_}[0..7] ", $_->[8]-($s/$n) ) : "@$_"
for @f' data.txt
使用-an
略微缩短(见perlrun
),但不是非常高尔夫球。与@ John1024的awk
解决方案一样,我们读取了两次文件 - 在这种情况下有两个for
循环。我们使用三元运算符(<cond> ? :
)打印 - 或say
- 每行,按原样(@$_
)或字段替换。
<强>输出强>:
MCCC processed: unknown event at: Tue, 14 Oct 2014 12:02:26 CST
station, mccc delay, std, cc coeff, cc std, pol , t0_times , delay_times
ZJ.uno1 -0.7964 0.0051 0.9690 0.0139 0 GRAW.BHZ 301.1263 -0.5028
ZJ.dose -0.7065 0.0072 0.9760 0.0133 0 KNYN.BHZ 301.3372 -0.6236
ZJ.tres 0.9675 0.0072 0.9548 0.0292 0 LEON.BHZ 301.2611 1.1264
Phase: P
PDE 2013 7 15 14 6 58.00 -60.867 -25.143 31.0 0.0 7.3
作为可能如下所示的脚本:
use v5.16;
my (@timedata, $rec, $sum, $n) ;
while (<DATA>) {
push @timedata, [ split(" ") ] ;
}
foreach my $rec (@timedata){
$sum += $rec->[8] and $n++ if $rec->[0] =~ /ZJ/ ;
}
foreach $rec (@timedata) {
say $rec->[0] =~ /ZJ/ ? ( "@{$rec}[0..7] ", $rec->[8]-($sum/$n) )
: "@$rec" ;
}
__DATA__
MCCC processed: unknown event at: Tue, 14 Oct 2014 12:02:26 CST
station, mccc delay, std, cc coeff, cc std, pol , t0_times , delay_times
ZJ.uno1 -0.7964 0.0051 0.9690 0.0139 0 GRAW.BHZ 301.1263 -1.8041
ZJ.dose -0.7065 0.0072 0.9760 0.0133 0 KNYN.BHZ 301.3372 -1.9249
ZJ.tres 0.9675 0.0072 0.9548 0.0292 0 LEON.BHZ 301.2611 -0.1749
Phase: P
PDE 2013 7 15 14 6 58.00 -60.867 -25.143 31.0 0.0 7.3
可能有一种方法可以避免这两个循环(while
或map
与for
合并但实际上并不算数),但是在一次传递中创建总和和平均值而在另一个代替,使脚本清晰简单。