【问题标题】:Moving average and difference移动平均线和差异
【发布时间】:2018-09-26 18:16:31
【问题描述】:

我想计算我的数据文件 (data.txt) 中第 2 列 ($2) 的移动/滚动平均值,使用 5 个窗口(连续五行),然后计算第一个值和最后一个值之间的差异每个窗口使用 AWK。请在下面查看我的数据:

> cat data.txt
2001         100
2002         110
2003         120
2004         130
2005         140
2006         900
2007         910
2008         920
2009         930
2010         940

> awk 'BEGIN{size=5} {mod=NR%size; if(NR<=size){count++}else{sum-=array[mod]};sum+=$2;array[mod]=$2;print $1"\t", $2"\t", sum/count}' data.txt
2001     100     100
2002     110     105
2003     120     110
2004     130     115
2005     140     120
2006     900     280
2007     910     440
2008     920     600
2009     930     760
2010     940     920

从上面随附的输出中可以看出,我可以使用上面显示的 AWK 脚本对 2 美元(输出为 3 美元)进行移动平均。但是,如何修改上面的 AWK 脚本,以便我还可以打印出每个窗口的第一个和最后一个 $2 值之间的 $4 差值?例如,我希望上面的输出看起来像这样:

2001     100     100     
2002     110     105
2003     120     110
2004     130     115
2005     140     120      120-100
2006     900     280      280-105
2007     910     440      440-110
2008     920     600      600-115
2009     930     760      760-120
2010     940     920      920-280

【问题讨论】:

  • "打印出每个窗口的第一个和最后一个 $2 值之间的 $4 差值" -- 那么你不应该有 "140-100"、"900-110" 等吗?您的意思是“打印出每个窗口的 移动平均值first 价值 2 美元之间的 4 美元差异”?

标签: awk


【解决方案1】:

在替换 array[mod] 之前,将差异保存到另一个变量,以便您可以在新列中打印它。

awk 'BEGIN{size=5} 
    {   mod=NR%size; 
        if(NR<=size){count++;}
        else{sum-=array[mod]};
        sum+=$2;
        if (NR >= size) {diff = $2"-"array[mod]}
        array[mod]=$2;
        print $1"\t", $2"\t", sum/count"\t", diff
    }' data.txt

【讨论】:

  • 谢谢你,巴尔玛!你是天才。这成功了。我超级开心。
【解决方案2】:

您还需要记住第三列的最后一个值:

awk 'BEGIN{size=5}
{
  mod=NR%size; 
  if(NR<=size) {
    count++
  } else {
    sum-=array[mod]
  };
  sum+=$2;
  avg=sum/count;
  if (NR>=size) {
    diff=avg"-"array2[(mod+1)%size]; # remove quotes to display result as a number
  }
  array[mod]=$2;
  array2[mod]=avg;

  print $1"\t", $2"\t", avg, diff
}
' data.txt

编辑:您当前的描述与问题中的示例不匹配($4 应该与 $2 或 $3 不同?)。我的回答解决了您的示例,Barmars 解决了您的描述:)

【讨论】:

  • 谢谢你,Gyuri16!这正是我一直在寻找的。你来救我了。
【解决方案3】:

如果你不依赖于 awk,perl 是相当整洁的。这假设您的意思是,对于第 4 列,窗口的第一个和最后一个 平均值 之间的差异。

perl -MList::Util=sum0 -slane '
    unshift @values, $F[1];            # add current value to window of values
    splice @values, $size;             # trim window to desired size
    $avg = sum0(@values) / scalar(@values);

    unshift @averages, $avg;
    splice @averages, $size;

    push @F, $avg;
    # remove quotes below if you want the actual difference
    push @F, "$averages[0]-$averages[-1]" if scalar(@values) == $size;
    print join "\t", @F
' -- -size=5 data.txt
2001    100     100
2002    110     105
2003    120     110
2004    130     115
2005    140     120     120-100
2006    900     280     280-105
2007    910     440     440-110
2008    920     600     600-115
2009    930     760     760-120
2010    940     920     920-280

【讨论】:

  • 谢谢格伦!我对 Perl 不是很熟悉。 awk 为我解决了这个问题。
猜你喜欢
  • 1970-01-01
  • 2017-09-01
  • 2022-01-26
  • 2013-12-22
  • 1970-01-01
  • 1970-01-01
  • 2011-06-29
  • 2019-04-24
  • 2012-05-24
相关资源
最近更新 更多