【问题标题】:how to calculate averages of repeated records over a day using awk?如何使用awk计算一天内重复记录的平均值?
【发布时间】:2016-12-17 23:46:15
【问题描述】:

谁能告诉我如何使用 awk 使用数据集的唯一 id ($1) 和测量 ($3) 记录来计算每天 ($2) 重复记录的平均值。 数据集如下所示:

32070     2010-12-15    540  
32070     2010-12-15    546  
32070     2010-12-15    549  
32070     2010-12-17    579  
32070     2010-12-17    553  
25903     2010-12-15    556  
25903     2010-12-15    543  
25903     2010-12-15    564  
25903     2010-12-16    567  
25903     2010-12-16    583 

我希望根据每个唯一 ID ($1) 的测量 ($3) 计算平均每天记录 ($2),并分别打印我的输出文件,如下所示:

32070  2010-12-15    545  
32070  2010-12-17    566  
25903  2010-12-15     554.33  
25903  2010-12-16     575  

【问题讨论】:

    标签: awk


    【解决方案1】:
    $ cat tst.awk
    { curr = $1 OFS $2 }
    curr != prev { if (cnt) print prev, sum / cnt; sum=cnt=0 }
    { sum+=$3; cnt++; prev=curr }
    END { if (cnt) print prev, sum / cnt }
    
    $ awk -f tst.awk file
    32070 2010-12-15 545
    32070 2010-12-17 566
    25903 2010-12-15 554.333
    25903 2010-12-16 575
    

    这个答案和@Ruslans 答案的区别在于:

    1. His 将整个输入文件存储在内存中,而上面仅将 4 个变量(curr、prev、sum 和 cnt)的值存储在内存中。
    2. 他以随机(在大多数 awk 实现中实际上是散列)顺序输出结果,而上面的输出以它们在输入中出现的顺序。
    3. 无论您的输入以什么顺序出现,他都会起作用,而上述依赖于您的输入按 id 和日期排序。

    【讨论】:

    • 脚本只是按原样给我,没有平均每日记录。我期待着你的回应。谢谢
    • 您在复制/粘贴时做错了,或者您的输入与您提供的示例不同。正如您在我的回答中看到的那样,根据您提供的示例输入,脚本确实按照您的要求执行。
    【解决方案2】:
    BEGIN { SUBSEP = "@" }
    
    { a[$1,$2] += $3; n[$1,$2]++ }
    
    END {
      for (x in a) {
        split(x, parts, SUBSEP)
        print parts[1] " " parts[2] " " a[x] / n[x]
      }
    }
    

    输出

    25903 2010-12-15 554.333
    25903 2010-12-16 575
    32070 2010-12-15 545
    32070 2010-12-17 566
    

    说明

    SUBSEP 是一个内部变量,用于分隔multidimensional arrays 中的键。它的默认值是"\034",它不太可能出现在输入中。出于调试目的,我已将其设置为 @。您可以跳过修改此变量。

    与“预期输出”相比,输出的顺序不同。但是您可以使用sort 工具按列轻松对其进行排序。例如,以下将按第二列对输出进行排序,然后按第一列(按此顺序):

    awk -f script.awk file | sort -k2 -k1g
    

    输出

    25903 2010-12-15 554.333
    25903 2010-12-16 575
    32070 2010-12-15 545
    32070 2010-12-17 566
    

    这只是一个示例。你应该有大致的想法。根据需要修改命令。

    【讨论】:

    • 如果您想将 SUBSEP 设置为某个值,请将其设置为 OFS,然后您不需要 END 部分中的 split()parts 数组,您只需打印 @987654332 @ 索引原样,同时摆脱硬编码的 " " 以支持正常的 , 输出分隔符。
    • @EdMorton,谢谢。我只是想向他展示大致的想法。我觉得你的建议很有用,我认为 OP 也会觉得它们很有用。
    猜你喜欢
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-01
    • 1970-01-01
    相关资源
    最近更新 更多