使用awk计算文件的连续平均值和中值

时间:2018-06-18 22:42:32

标签: awk

这是我的输入文件(有数千行):

$ cat file.txt
1 495.03
2 503.76
3 512.28
4 520.75
5 529.17

我想用awk来计算第一列的中位数(比如1-100)行数和第二列相应值的平均值。然后awk将移动下一组行(101-201)并执行相同操作,即第一列的中位数和第二列的平均值,依此类推。毋庸置疑,我正在努力学习awk并尝试了以前的几种解决方案,但却无法使其发挥作用。

从之前的post开始,我发现我可以通过这种方式计算平均值:

awk '{sum+=$1} NR%3==0 {print sum/3; sum=0}'

这是如何工作的(即{sum+=$1}表达式是什么意思?)以及如何将其调整为中位数?顺便说一句,第一列将始终排序。

提前致谢, TP

2 个答案:

答案 0 :(得分:2)

如果记录已排序,则中位数只是 <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <!-- Wide Responsive Ad (White) --> <ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-4269714478926007" data-ad-slot="1264409627" data-ad-format="link"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> 50 st值的平均值。

51

如果记录数是100的倍数,这将有效,否则您需要处理具有不同大小的最后一个组。

&#34;中位数&#34;还有其他定义。对于偶数个记录,但这是你应该指定的东西。

解释$ awk '{r=NR%100; sum+=$2} r==50 {m=$1} r==51 {m=(m+$1)/2} r==0 {print m, sum/100; sum=0}' file 定义为mod 100的余数,实质上是100个记录的每个块中的相对位置。对于中位数,我们取第50和第51条记录的平均值,r汇总每100个块的第二个字段值。当余数为0时,我们完成每个块,打印中位数和平均值(sum / 100);为下一个块重置sum

答案 1 :(得分:2)

注意::其中包含有关运行方式和未排序数据中位数的更多信息。这应该被视为原始问题的附录。

如果您要计算最近 n 个词的运行平均值(假设 n = 100 ),则必须注意如何处理第一个 > m 记录,其中包含 m 。处理此问题的一种方法是将值放置在索引为 n 模的数组中。这样,您总是在数组中拥有最后的 n 项:

$i的移动平均值:

awk '{a[NR%100] = $i; s=0; for(j in a) { s+=a[j] }; print "avg:" s/length(a) }'

但是,您可以通过跟踪for来删除s循环:

awk '{s+=$i; if (NR%100 in a) s-=a[NR%100]; a[NR%100]=$i; print "avg:" s/length(a) }'

运行$i的中位数:

可以使用gawk完成一种计算中位数的方法,其中我们假定该数组按值进行数组遍历排序

awk 'BEGIN{ PROCINFO["sorted_in"]="@val_num_asc" }
     { a[NR%100] = $i }
     { k=0; m=0;
       for(j in a) { k++
           if (k >= length(a)/2  ) m+=a[j]
           if (k <= length(a)/2+1) {m+=a[j]; break }
       }
       print "med:", m/2
     }'

或者如果您希望在if-conditions上轻一点

awk 'BEGIN{ PROCINFO["sorted_in"]="@val_num_asc" }
     { a[NR%100] = $i }
     { k=0; m=0;
       for(j in a) { k++
           if (k < length(a)/2  ) continue
           if (k > length(a)/2+1) break
           m+=a[j]
       }
       print "med:", (length(a)%2==0 ? m/2 : m)
     }'

如果您不想使用预先排序的概念,则中位数的计算将变得更加困难。一种可能的方式是使用selection algorithm,如here所述。