如何使用jq计算中位数?

问题描述

如何使用jq计算数组的中位数(P50)? jq手册介绍了如何计算均值,但我想获取中位数。

算法:给定数字列表,对其进行排序。如果条目数量奇数,则选择中间的条目。如果条目数为偶数,则计算中间两个条目的平均值。

示例:

echo '[1,5,9,3]' | jq <ANSWER>  # should output 4,since it's the mean of 3 and 5
echo '[1,2]' | jq <ANSWER>  # should output 2,since it's the middle element
echo '[]' | jq <ANSWER>  # undefined

解决方法

答案:

sort |
  if length == 0 then null
  elif length % 2 == 0 then (.[length/2] + .[length/2-1])/2
  else .[length/2|floor] end

这是指定算法的直接实现。

,

这种方法利用了这样一个事实,即数组的中心可以是“中间的一个”或“中间的两个”,根据定义,它总是与数组的两端等距。也就是说,在排序数组中,从中间下值回到第一个元素的距离与从中间上值到最后一个元素的距离相同,无论下中值和上中间值是否驻留在同一元素中或不是。因此,我们只需要计算两者之一,从两端移动那么远,取这些元素并计算它们的平均值。 (如果它们碰巧相同,计算两个相同值的平均值不会有什么坏处。)我们必须克服的唯一障碍是 jq 从头开始​​计数时从 0 开始,但在从数组的末尾开始,因此两个索引的绝对值必须为一且符号相反。

为了计算平均值,传统上会先将这些值相加,然后将总和减半。但是,在处理空数组时,将(不存在的)值相加会产生 null,并且 /2 的后续应用会引发错误。但是,如果我们先将值减半并使用 ? 跳过它不适用的地方,那么为最终 null 获取 add 不会造成问题,因为它应该是预期的输出输入一个空数组。

sort | [ .[length/2 | ceil | -.,.-1] /2? ] | add