首页 文章

移动平均线和差异

提问于
浏览
1

我想在我的数据文件(data.txt)中使用5(连续五行)的窗口计算第2列($ 2)的移动/滚动平均值,然后使用每个窗口中的第一个和最后一个值之间的差值来计算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

3 回答

  • 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
    
  • 1

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

    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你的描述:)

  • 0

    如果你没有与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
    

相关问题