在所有列中使用 awk 的移动平均线

Moving average using awk in all columns

我有一个数据为:

2       2
3       3
4       3
2       2
1       1
56      4
3       2
4       1
2       2
4       2
5       5
3       3
5       6
6       4

我想为所有列打印每 5 个过去数字的移动平均线。

期望输出是:

2.4     2.2
13.2    2.6
13.2    2.4
13.2    2
13.2    2
13.8    2.2
3.6     2.4
3.6     2.6
3.8     3.6
4.6     4

您可以使用三个规则使用 "Sliding-Window" 来存储存储在两个数组 a[] 和 [=14= 中的值].您只需使用计数器 n 作为索引来填充每个元素,然后当 n >= 5 输出总和并 delete 输出 a[n-4]b[n-4] 处的值(可选) 并继续前进。您的第一条规则就是(添加一个循环和每个循环中最后 5 个值的平均值的总和。

您的第二条规则只是验证您有 2 个字段并填充 a[]b[] 数组。 (您可以添加测试以确保 field1 和 field2 都是数值——这是留给您的)

您的第三条规则是 END 规则,它计算并输出最终总和,例如

awk '
    n >= 5 {
        suma=sumb=0
        for (i = n-4; i <= n; i++) {
            suma+=a[i]
            sumb+=b[i]
        }
        print suma/5"\t"sumb/5
        delete a[n-4]
        delete b[n-4]
    }
    NF >= 2 {
        a[++n] = 
        b[n] = 
    }
    END {
        suma=sumb=0
        for (i = n-4; i <= n; i++) {
            suma+=a[i]
            sumb+=b[i]
        }
        print suma/5"\t"sumb/5
    }
' data

(不是循环计算总和,您可以保留 运行 总和并从数组中减去您 unset 的值——由您决定)

示例Use/Output

您可以简单地使用 xterm 并更改到存储 data 文件的目录(根据需要更改名称)和 select-copy 上面的 awk 脚本和 middle-mouse-paste 到 xterm 中。您将收到:

2.4     2.2
13.2    2.6
13.2    2.4
13.2    2
13.2    2
13.8    2.2
3.6     2.4
3.6     2.6
3.8     3.6
4.6     4

保持 运行 和

如果您确实想保留 运行 和(sumasumb)并删除 n-4 处的值而不是循环,(这会稍微多一些高效),你可以这样做:

awk '
    n >= 5 {
        print suma/5"\t"sumb/5
        suma -= a[n-4]
        sumb -= b[n-4]
    }
    NF >= 2 {
        a[++n] = 
        b[n] = 
        suma += a[n]
        sumb += b[n]
    }
    END {
        print suma/5"\t"sumb/5
    }
' data

输出相同。

这是另一个 awk 使用 2 遍:

awk -v OFS='\t' 'FNR == NR {
   a[FNR] = 
   b[FNR] = 
   for (i=FNR-4; FNR>= 5 && i<=FNR; i++) {
      sum1[FNR-4] += a[i]
      sum2[FNR-4] += b[i]
   }
   tr = FNR
   next
}
FNR <= tr-4 {
   printf "%.2f%s%.2f\n", sum1[FNR]/5, OFS, sum2[FNR]/5
}' file file
2.40    2.20
13.20   2.60
13.20   2.40
13.20   2.00
13.20   2.00
13.80   2.20
3.60    2.40
3.60    2.60
3.80    3.60
4.60    4.00

能否请您尝试以下操作,再添加一种执行此操作的方法。使用 GNU awk.

中显示的示例编写和测试
awk '
FNR==NR{
  a[FNR]=
  b[FNR]=
  lines++
  next
}
FNR<=(lines-4){
  ++count
  for(i=count;i<=(4+count);i++){
    sum1+=a[i]
    sum2+=b[i]
  }
  print sum1/5,sum2/5
  sum1=sum2=""
}
' Input_file  Input_file | column -t

所有呈现的结果都非常占用内存,因为将整个系统加载到内存中。虽然有些删除分配的内存,但使用模块化索引更容易。最重要的是,你真的不需要不断地重新计算总和(如果你有高精度需求,我会以不同的方式争论浮点数,但不需要整数):

此解决方案假定等量的列和 n 的滑动 window:

awk -v n=5 '{for(i=1;i<=NF;++i) {s[i] = s[i] - a[FNR%n,i] + $i; a[FNR%n,i]=$i } }
            (FNR >= n)  { for(i=1;i<=NF;++i) printf "%s" (i==NF?ORS:OFS), s[i]/n }' file