在所有列中使用 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
保持 运行 和
如果您确实想保留 运行 和(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] =
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
我有一个数据为:
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
保持 运行 和
如果您确实想保留 运行 和(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] =
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