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

Shell 在所有列中使用awk的移动平均值,shell,awk,moving-average,Shell,Awk,Moving Average,我的数据如下: 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       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]处的值(可选),然后继续。你的第一条规则是,加上一个循环和每个循环中最后5个值的总和,得到平均值

第二条规则只是验证您有2个字段,并填充a[]和b[]数组。您可以添加测试以确保field1和field2都是数值,这由您自己决定

第三个规则是计算并输出最终总和的结束规则,例如

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
保持流动资金

如果您确实希望继续运行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

输出是相同的。

您可以使用三条规则来完成这项工作,即使用滑动窗口来显示存储在两个数组a[]和b[]中的值。您只需使用计数器n作为索引填充每个元素,然后当n>=5时,输出总和并删除a[n-4]和b[n-4]处的值(可选),然后继续。你的第一条规则是,加上一个循环和每个循环中最后5个值的总和,得到平均值

第二条规则只是验证您有2个字段,并填充a[]和b[]数组。您可以添加测试以确保field1和field2都是数值,这由您自己决定

第三个规则是计算并输出最终总和的结束规则,例如

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
保持流动资金

如果您确实希望继续运行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
输出相同。

这里是另一个awk,使用2次通过:

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%.2f\n", sum1[FNR]/5, OFS, sum2[FNR]/5
}' file file
下面是另一个使用2通道的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%.2f\n", sum1[FNR]/5, OFS, sum2[FNR]/5
}' file file

请您尝试下面的方法,再添加一种方法。使用GNU awk中显示的样本编写和测试


请您尝试下面的方法,再添加一种方法。使用GNU awk中显示的样本编写和测试


当将整个系统加载到内存中时,所有呈现的结果都非常占用内存。虽然有些人会删除分配的内存,但只使用模块化索引更容易。最重要的是,你不需要经常用浮点数重新计算和,如果你有高精度的要求,我会提出不同的观点,但对于整数,它是不需要的:

此解决方案假定列数相等,滑动窗口为n:


当将整个系统加载到内存中时,所有呈现的结果都非常占用内存。虽然有些人会删除分配的内存,但只使用模块化索引更容易。最重要的是,你不需要经常用浮点数重新计算和,如果你有高精度的要求,我会提出不同的观点,但对于整数,它是不需要的:

此解决方案假定列数相等,滑动窗口为n:


++相信这一个更有效,有趣的是,你的第一个想法并不总是最有效的,但当你开始修补时,你会发现一路上有改进。。。除非您的Ed或Charles:@Kay,否则我回滚了编辑,因为使用shell变量的$n1的使用应该使用-v选项或BEGIN规则来处理,以使其成为awk变量。否则,美元的报价和逃逸将变得脆弱。我喜欢你做的概括和清理的格式虽然!对非常感谢。我的意思是delete-gladunset是无害的,它一定曾经被使用过,或者是某物的同义词。接得好!++相信这一个更有效,有趣的是,你的第一个想法并不总是最有效的,但当你开始修补时,你会发现一路上有改进。。。除非您的Ed或Charles:@Kay,否则我回滚了编辑,因为使用shell变量的$n1的使用应该使用-v选项或BEGIN规则来处理,以使其成为awk变量。否则,美元的报价和逃逸将变得脆弱。我喜欢你做的概括和清理的格式虽然!对非常感谢。我的意思是delete-gladunset是无害的,它一定曾经被使用过,或者是某物的同义词。抢手货好的,我明白了,你对输入进行了两次传递。我必须记住这一点。我已经看过好几次了,这真的很好。好吧,我明白了,你对输入进行了两次传递。我必须记住这一点。我已经看过好几次了,真是太棒了,太棒了!!好极了!!
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