连续平均重复数据但行数不同

Successive averaging of repeating data but different number of lines

我有以下格式的数据:

         1        3
   1.723608      0.8490000
   1.743011      0.8390000
   1.835833      0.7830000
         2        5
   1.751377      0.8350000
   1.907603      0.7330000
   1.780053      0.8190000
   1.601427      0.9020000
   1.950540      0.6970000
         3        2
   1.993951      0.6610000
   1.796519      0.8090000
         4        4
   1.734961      0.8430000
   1.840741      0.7800000
   1.818444      0.7950000
   1.810717      0.7980000
         5        1
   2.037940      0.6150000
         6        7
   1.738221      0.8330000
   1.767678      0.8260000
   1.788517      0.8140000
   2.223586      0.4070000
   1.667492      0.8760000
   2.039232      0.6130000
   1.758823      0.8300000
...

数据由数据块组成。每个数据块的格式相同如下:

  1. 第一行是 header 行。 header行包含ID号和每个数据块的总行数。比如第一个数据块的ID是1,总行数是3,第三个数据块的ID是3,总行数是2,所有的数据块都有这个header行.

  2. 接下来就是“真实数据”了。正如我所解释的,“真实数据”的行数在 header 行的第二个整数中指定。

  3. 因此,每个数据块的总行数将为number_of_lines+1。在这个例子中,数据块1的总行数是4,数据块2花费了6行...

这种格式在我当前的数据中一直重复最多 10000 个数据块,但我可以提供这 10000 个作为 bash 中的变量或 awk 脚本作为输入值。我知道数据块总数。

现在,我想做的是,我想得到每两列数据的平均值,并打印出数据块ID号和总行数。输出文本将具有:

ID_number number_of_lines average_of_column_1 average_of_column_2

在小数点后 6 位格式的列之间使用 5 个空格。结果将有 10000 行,每行将有 ID、行数、每个数据块的第 1 列数据的平均值和第 2 列数据的平均值。这个例子的结果看起来像

1     3     1.767484     0.823666
2     5     1.798200     0.797200
3     2     1.895235     0.735000
...

我知道如何在 awk 和 bash 中获取简单数据列的平均值。这些已经在 Whosebug 中回答了很多次。例如,我真的很喜欢使用

awk '{ total += ; count++ } END { print total/count }' data.txt

所以,我希望使用 awk 或 bash。但我真的不知道如何处理甚至开始获得这种多个重复数据块的平均值,但每个数据块的行数不同。

我正在尝试基于 awk,如下 https://www.unix.com/shell-programming-and-scripting/135829-partial-average-column-awk.html

但我不确定对于每个数据块,如何使用 NR 或 FNR 来计算总行数不同的数据的平均值。

你可以试试

awk -v qnt=none 'qnt == "none" {id = ; qnt = ; s1 = s2 = line = 0;next}{s1 += ; s2 += ; ++line} line == qnt{printf "%d     %d     %.6f     %.6f\n", id, qnt, s1/qnt, s2/qnt; qnt="none"}'

以上展开如下:

qnt == "none" 
{
  id = ;
  qnt = ;
  s1 = s2 = line = 0;
  next
}
{
  s1 += ;
  s2 += ;
  ++line
}
line == qnt
{
  printf "%d     %d     %.6f     %.6f\n", id, qnt, s1/qnt, s2/qnt; 
  qnt="none"
}

处理完一个数据块后(或开始时),记录头信息。 否则,当我们完成此块中的所有行时,添加到总和并打印结果。

你可以试试这个awk:

awk -v OFS='\t' ' ~ /\./ {s1 += ; s2 += ; next} {if (id) {print id, num, s1/num, s2/num; s1=s2=0} id=; num=} END {print id, num, s1/num, s2/num}' file

1  3  1.76748  0.823667
2  5  1.7982   0.7972
3  2  1.89524  0.735
4  4  1.80122  0.804
5  1  2.03794  0.615
6  7  1.85479  0.742714

如果您有 gnu awk,则使用 OFMT 获取固定大小的十进制数,如下所示:

awk -v OFMT="%.6f" -v OFS='\t' ' ~ /\./ {s1 += ; s2 += ; next} {if (id) {print id, num, s1/num, s2/num; s1=s2=0} id=; num=} END {print id, num, s1/num, s2/num}' file
1   3   1.767484    0.823667
2   5   1.798200    0.797200
3   2   1.895235    0.735000
4   4   1.801216    0.804000
5   1   2.037940    0.615000
6   7   1.854793    0.742714

扩展形式:

awk OFMT='%.6f' -v OFS='\t' '
 ~ /\./ {
   s1 += 
   s2 += 
   next
}
{
   if (id) {
      print id, num, s1/num, s2/num
      s1 = s2 = 0
   }
   id = 
   num = 
}
END {
   print id, num, s1/num, s2/num
}' file

还有一个:

awk -v num_blocks=10000 '
BEGIN {
  OFS = "\t"
  OFMT = "%.6f"
}
num_lines == 0 {
  id = 
  num_lines = 
  sum1 = sum2 = 0
  next
}
lines_read < num_lines {
  sum1 += 
  sum2 += 
  lines_read++
}
lines_read >= num_lines {
  print id, num_lines, 
    sum1 / num_lines,
    sum2 / num_lines
  num_lines = lines_read = 0
  num_blocks--;
}
num_blocks <= 0 {
  exit
}' file