我有一个数据为:
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
保持运行总和
如果您确实想继续运行总和(suma
和sumb
(并删除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