【问题标题】:generate field-value frequency count with jq使用 jq 生成字段值频率计数
【发布时间】:2019-11-15 17:10:48
【问题描述】:

我可以像这样从 JSON 字段中查询所有唯一值:

$ cat all.json | jq '.complianceState' | sort | uniq

"compliant"
"configManager"
"inGracePeriod"
"noncompliant"
"unknown"

我可以像这样迂腐地查询每个唯一字段值的频率计数:

$ cat all.json | jq '.complianceState' | grep '^"configManager"$' | wc -l

116

jq 中是否有办法一次性完成所有操作以产生如下输出:

{
    "compliant" : 123000,
    "noncompliant" : 2000,
    "configManager" : 116
}

【问题讨论】:

    标签: json stream histogram jq summary


    【解决方案1】:

    来自我的标准库:

    # bag of words
    # WARNING: this is not collision-free!
    def bow(stream): 
      reduce stream as $word ({}; .[($word|tostring)] += 1);
    
    

    有了这个,你可以使用过滤器:

    bow(inputs | .complianceState)
    

    与 -n 命令行选项结合使用。

    总结

    将所有这些结合在一起的一种方法是将上述 jq 行放在一个文件中,例如 bow.jq,然后按如下方式调用 jq:

    jq -n -f bow.jq all.json
    

    另一种方法是使用模块系统——详情请参阅 jq 手册和/或Cookbook

    【讨论】:

    • 我是 jq 的新手(brew 在 MacOS 上安装了它) - 如何添加像 bow 这样的自定义插件功能,所以 jq 工具会选择它?跨度>
    • 请看更新; Cookbook 中的相关部分是github.com/stedolan/jq/wiki/…
    • 越来越近了。当我运行jq -f bow.jq all.json 时,我得到了这个(简短的)sn-p 输出:pastebin.com/ThmQfrTw - 所以它为每次出现分配 1 - 但不是计数。
    • 此次更新提供了一个示例,说明如何使用inputs 处理您的流。
    • 你是超级巨星!最新更新完美运行:pastebin.com/EvDM95kA 谢谢!
    【解决方案2】:

    这是我使用的解决方案,它是一个自定义频率函数,即:

    • 通过 JQ 表达式(桶 key)对 JSON 值/对象数组进行存储桶/分箱
    • 提供桶count(频率)
    • 为每个存储桶提供 percentage 的项目(四舍五入到小数点后 2 位)
    • 提供原始的items,它们被分箱到桶中,并且
    • 按桶的count 降序对桶进行排序。
    def freq(expr):
      length as $total_count
        | group_by(expr)
        | map({
            key: (.[0] | expr),
            count: length,
            percent: (((length / $total_count * 10000 + 0.5) | floor) / 100),
            items: .
          })
        | sort_by(-.count)
      ;
    

    例如,在我的$HOME/.jq 中定义了上述内容,查询:

    jq -n '
    [                                                                                                                                                                                               
      {"complianceState": "a", "other": 0.5},
      {"complianceState": "b", "other": 1.2},
      {"complianceState": "a", "other": 1.7},
      {"complianceState": "c", "other": 5.3},
      {"complianceState": "b", "other": 1.5},
      {"complianceState": "e", "other": 0.6},
      {"complianceState": "c", "other": 3.4},
      {"complianceState": "c", "other": 5.9}
    ] | freq(.complianceState)'
    

    会产生

    [
      {
        "key": "c",
        "count": 3,
        "percent": 37.5,
        "items": [
          {"complianceState": "c", "other": 5.3},
          {"complianceState": "c", "other": 3.4},
          {"complianceState": "c", "other": 5.9}
        ]
      },
      {
        "key": "a",
        "count": 2,
        "percent": 25,
        "items": [
          {"complianceState": "a", "other": 0.5},
          {"complianceState": "a", "other": 1.7}
        ]
      },
      {
        "key": "b",
        "count": 2,
        "percent": 25,
        "items": [
          {"complianceState": "b", "other": 1.2},
          {"complianceState": "b", "other": 1.5}
        ]
      },
      {
        "key": "e",
        "count": 1,
        "percent": 12.5,
        "items": [
          {"complianceState": "e", "other": 0.6}
        ]
      }
    ]
    

    对于您的情况,您需要使用-s 将输入吞入一个 JSON 数组。从那里,您可以将输出转换为所需的格式。例如

    jq -s 'freq(.complianceState)
      | map({key, value: .count})
      | from_entries
    ' all.json
    

    请注意,使用freq 函数,您可以按任意表达式进行分组。例如freq((.other / 1.5) | floor),如果您希望获得类似直方图的分箱。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-03-21
      • 2017-10-01
      • 2017-09-26
      • 2019-05-15
      • 2011-01-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多