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



我有一个数据为:

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

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

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

您的第三条规则是计算并输出最终总和的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] = $1
b[n] = $2
}
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的值 - 由你决定(

示例使用/输出

您只需使用 xterm 并切换到存储data文件的目录(根据需要更改名称(,然后选择复制上面的awk脚本并将鼠标中键粘贴到 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] = $1
b[n] = $2
suma += a[n]
sumb += b[n]
}
END {
print suma/5"t"sumb/5
}
' data

输出是相同的。

这是使用 2 pass 的另一个awk

awk -v OFS='t' 'FNR == NR {
a[FNR] = $1
b[FNR] = $2
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%.2fn", 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

您能否尝试以下操作,添加另一种方法。使用 GNUawk中显示的示例编写和测试。

awk '
FNR==NR{
a[FNR]=$1
b[FNR]=$2
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的滑动窗口:

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

最新更新