计算每个变量的百分位数和最大值

3

Bash高手们,我需要使用awk计算列表中每个项目的最大值和百分位数。

aa  1
ab  3
aa  4
ac  5
aa  3
ad  2
ab  4
ac  2
ae  2
ac  5

期望的输出结果

Item   90th percentile   max value
aa     3.8             4
ab     3.9             4
ac     5               5
ad     2               2
ae     2               2

我可以使用以下方法获取和最大值,但无法获取百分位数。

awk '{
item[$1]++;
count[$1]+=$2;
max[$1]=$2;
percentile[$1,.9]=$2
 }
 END{
 for (var in item)
 print var,count[var],max[var],percentile[var]
 }
' 

请建议。

1
你期望percentile[$1,.9]=$2做什么? - Tom Fenech
3
你使用什么方法来计算百分位数?是线性插值还是最近排名?你是否在Bash中实现了一个函数来执行此操作? - Aserre
@jas 它们分别是1、3和4。 - Jacek Trociński
@EdMorton 你不知道百分位数吗? - Pradeep BS
@PradeepBS 是的,我是。你是在寻求帮助来计算百分位数或者如何在awk中实现这个计算吗?如果是前者,那么你做得很对,只需说明你想要百分位数,让其他人从那里开始做就可以了。但如果是后者,展示你的算法将有助于鼓励awk专家帮助你在awk中实现它,否则愿意帮助你的人数将会受到限制,你可能最终得到的结果虽然能产生你想要的输出,但并不是一个好的解决方案。 - Ed Morton
显示剩余2条评论
3个回答

2

《统计学入门》第二版中的百分位数计算。在Gnu awk中:

$ cat mnp.awk
BEGIN {
    PROCINFO["sorted_in"]="@ind_num_asc"   # for order in output
    if(p=="")                              # if p not defined it's median
        p=0.5
    else
        p=p/100                            # if 90th percentile: p=0.9
}
{
    v[$1][NR]=$2                           # values stored per keyword. NR for unique
    if($2>m[$1])                           # find max val
        m[$1]=$2
}
END {
    for(i in v) {                          # for all keywords
        n=asort(v[i])                      # sort values, n is count
        prc=p*n;                           # percentile figuration
        if(prc==int(prc))
            w=(v[i][prc]+v[i][prc+1])/2
        else
            w=v[i][int(prc)+1]
        print i, m[i], w                   # print keyword, max and nth value
    }
}

运行它:

$ awk -p=90 -f mnp.awk data.txt
aa 4 4
ab 4 4
ac 5 5
ad 2 2
ae 2 2

待完成:如果数据文件已经排序,那么就可以简化此流程,而且不必将所有数据存储到内存中。


这不是OP发布的预期输出。 - Jacek Trociński
1
@dood 是的。我希望 OP 能够给出他想要的百分位数的定义。引用维基百科关于百分位数的页面:_没有标准的百分位数定义,但是当观察数量非常大时,所有定义都会产生类似的结果_。我使用的定义来自《统计学入门》第二版。 - James Brown

1

datamash 是一个很棒的工具,尽管它不支持百分比部分。

$ datamash -W --sort --group=1 max 2 min 2 < INPUT
aa  4   1
ab  4   3
ac  5   2
ad  2   2
ae  2   2

它支持以下操作。
File operations:
  transpose, reverse
Numeric Grouping operations:
  sum, min, max, absmin, absmax
Textual/Numeric Grouping operations:
  count, first, last, rand 
  unique, collapse, countunique
Statistical Grouping operations:
  mean, median, q1, q3, iqr, mode, antimode
  pstdev, sstdev, pvar, svar, mad, madraw
  pskew, sskew, pkurt, skurt, dpo, jarque

0

这里有一个我在互联网上发现的优雅解决方案,用于查找最大值:

{
  max[$1] = !($1 in max) ? $2 : ($2 > max[$1]) ? $2 : max[$1]
}
END {
  for (i in max)
    print i, max[i]
}

输出:

ab 4
ac 5
ad 2
ae 2
aa 4

1
你只需要执行 max[$1] = (($1 in max) && (max[$1] > $2) ? max[$1] : $2) 来避免使用负数和重复的语法(在多个位置设置为 $2)。 - Ed Morton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接