AWK每N行合并一次

时间:2014-04-16 09:16:28

标签: awk

我有这样的数据:

1
2
3
4
5

我想对这列中的每N行求和(bin),但不喜欢:

awk '{s+=$1}NR%2==0{print s;s=0}' file

例如,对于2个分区,我想要对行1 + 2,2 + 3,3 + 4,4 + 5求和。所以它看起来像这样:

3
5
7
9

对于这样的3个binning:

6
9
12

有什么想法吗?

我的真实数据如下:

2014-04-13 17:25:33.25  5.5
2014-04-13 17:25:53.25  27.5
2014-04-13 17:26:13.26  -3.5
2014-04-13 17:26:33.26  5.5
2014-04-13 17:26:53.26  22.5
2014-04-13 17:27:12.27  1.5
2014-04-13 17:27:32.27  26.5
2014-04-13 17:27:52.27  -14.5
2014-04-13 17:28:12.28  26.5
2014-04-13 17:28:32.28  0.5
2014-04-13 17:28:52.28  -14.5
2014-04-13 17:29:12.29  12.5
2014-04-13 17:29:32.29  9.5

前两列是~20秒步的时间,3行是~1分钟。因此,例如,我想总结(bin)第3列,以获得在任何给定的30分钟(90行)或5分钟(15行)中总体变化的程度。

2 个答案:

答案 0 :(得分:2)

像Awk中的这样

$ awk -v Bin=3 '{ tot += $3 } 0 == NR%Bin { print tot; tot = 0 }' data.txt
29.5
29.5
38.5
-1.5

但是你可能最好解析时间戳并使用awk的mktime()来创建实际的时间段,而不是你的近似值。当然,除非你不需要那么高的精确度。

使用日期时间功能:

awk -v Bin=1 '
    BEGIN { Step = Bin * 60; } # convert Bin in minutes to seconds
    function Output () {
        print strftime("%Y-%m-%d %T -", StartTime), strftime("%Y-%m-%d %T", EndTime), Total; 
        Total = 0; 
        StartTime += Step;
        EndTime += Step; 
    }
    {
        Time = $1 OFS $2;
        sub(/\.[0-9]+$/, "", Time); 
        gsub(/[-:.]/, OFS, Time);
        Time = mktime(Time); 
    }
    1 == NR { 
        StartTime = Time;
        EndTime = StartTime + Step - 1;
    } 
    Time > EndTime { 
        Output()
    }
    {
        Total += $3; 
    } 
    END { Output() }
 '
2014-04-13 17:25:33 - 2014-04-13 17:26:32 29.5
2014-04-13 17:26:33 - 2014-04-13 17:27:32 56
2014-04-13 17:27:33 - 2014-04-13 17:28:32 12.5
2014-04-13 17:28:33 - 2014-04-13 17:29:32 7.5

答案 1 :(得分:2)

您可以使用此功能,例如:

awk -v bin=THE_NUMBER-1 '{a[NR]=$1}
       END {
            for (i=1; i<=NR-bin; i++)
               { 
                 for (j=0; j<=bin; j++) {c+=a[i+j]} 
                 print c; c=0
               }
           }' file

解释

  • -v bin=THE_NUMBER-1给出了价值。我们使用的是数字-1。
  • {a[NR]=$1}存储每行的值。
  • END {}在脚本结束时执行。
  • {for (i=1; i<=NR-bin; i++)循环显示行号,从第一行到最后一行减去bin
  • { for (j=0; j<=bin; j++) {c+=a[i+j]}遍历受影响的行序列,并作出总和。
  • {print c; c=0}打印结果并重置计数器。

测试

对于您的给定示例文件1 2 3...,它的工作方式如下:

$ awk -v bin=2 '{a[NR]=$1} END {for (i=1; i<=NR-bin; i++) { for (j=0; j<=bin; j++) {c+=a[i+j]} print c; c=0}}' file
6
9
12


$ awk -v bin=1 '{a[NR]=$1} END {for (i=1; i<=NR-bin; i++) { for (j=0; j<=bin; j++) {c+=a[i+j]} print c; c=0}}' file
3
5
7
9

如果您想将其他文件与日期一起使用,请将所有$1替换为$NF,以便将该文件的最后一列作为要检查的数字。

使用您的真实文件进行测试

$ awk -v bin=1 '{a[NR]=$NF} END {for (i=1; i<=NR-bin; i++) { for (j=0; j<=bin; j++) {c+=a[i+j]} printf "%.2f\n", c; c=0}}' a
33.00
24.00
2.00
28.00
24.00
28.00
12.00
12.00
27.00
-14.00
-2.00
22.00

$ awk -v bin=2 '{a[NR]=$NF} END {for (i=1; i<=NR-bin; i++) { for (j=0; j<=bin; j++) {c+=a[i+j]} printf "%.2f\n", c; c=0}}' a
29.50
29.50
24.50
29.50
50.50
13.50
38.50
12.50
12.50
-1.50
7.50

$ awk -v bin=3 '{a[NR]=$NF} END {for (i=1; i<=NR-bin; i++) { for (j=0; j<=bin; j++) {c+=a[i+j]} printf "%.2f\n", c; c=0}}' a
35.00
52.00
26.00
56.00
36.00
40.00
39.00
-2.00
25.00
8.00

$ awk -v bin=4 '{a[NR]=$NF} END {for (i=1; i<=NR-bin; i++) { for (j=0; j<=bin; j++) {c+=a[i+j]} printf "%.2f\n", c; c=0}}' a
57.50
53.50
52.50
41.50
62.50
40.50
24.50
10.50
34.50

$ awk -v bin=5 '{a[NR]=$NF} END {for (i=1; i<=NR-bin; i++) { for (j=0; j<=bin; j++) {c+=a[i+j]} printf "%.2f\n", c; c=0}}' a
59.00
80.00
38.00
68.00
63.00
26.00
37.00
20.00