我的文件 data.txt 包含以下包含数百万行的记录结构:
13
12
11
8
4
3
2
1
1
1
对于此列的每个值,我需要计算其PERCENTRANK(数据集中值的等级作为数据集的百分比)。
计算数据集中任何值X的PERCENTRANK的公式是
= number of values less than X / (Number of values less than X + Number of Values greater than X)
因此,对于数据集中的每个值X,程序必须循环遍历所有记录,以查找同一数据集中小于和大于X的值的数量。
如何使用'awk'重复循环文件来计算所有X值的PERCENTRANK?
预期产出:
X PERCENTRANK
13 1.0000
12 0.8888
11 0.7777
8 0.6666
4 0.5555
3 0.4444
2 0.3333
1 0.0000
1 0.0000
1 0.0000
2的PERCENTRANK为0.333,因为集合中的三个值小于2,6个大于2. PERCENTRANK OF 2 = 3 /(3 + 6)= 3/9 = 0.3333。
同样,4的PERCENTRANK为0.5555,因为五个值小于4,四个值更大。 PERCENTRANK为4 = 5 /(5 + 4)= 5/9 = 0.5555。
我正在避免使用嵌套的'while..do'循环,因为在循环包含数百万条记录的文件时它非常慢。
我很高兴awk在许多其他迭代计算场景中的惊人速度,例如:计算平均值,标准差,按总和等等,所以,我最好使用'awk'来解决这个问题用例也是如此。
答案 0 :(得分:4)
GNU awk
gawk '
{count[$1]++}
END {
print "X\tPERCENTRANK"
PROCINFO["sorted_in"] = "@ind_num_desc"
gt = 0
total = NR
for (x in count) {
lt = total - count[x] - gt
pr = lt/(gt+lt)
for (i=1; i<=count[x]; i++)
printf "%d\t%.4f\n", x, pr
gt += count[x]
}
}
' data.txt
X PERCENTRANK
13 1.0000
12 0.8889
11 0.7778
8 0.6667
4 0.5556
3 0.4444
2 0.3333
1 0.0000
1 0.0000
1 0.0000
即使对于大型数据集,这应该非常有效:没有嵌套循环。
这依赖于GNU awk来设置遍历count
数组的顺序:按数组索引排序,以数字方式递减。由于我们强制执行订单,因此我们可以简单地记录多少记录大于我们当前正在查看的记录。
答案 1 :(得分:1)
更简单的sort
和awk
方法也可以帮助你(尽管我没有在数百万行上测试它,因为我没有它)。
解决方案1: 这不会在输出中显示重复项目的排名,例如 - &gt;你的例子中的数字1。
sort -nr Input_file | awk '
function sum(array){
tot="";
for(i in array){
tot+=array[i]};
return tot}
{
a[FNR]=$0;
b[$0]++
}
END{
for(j=1;j<=FNR;j++){
if(b[a[j]]){
val=b[a[j]];
delete b[a[j]];
printf("%d %0.4f\n",a[j],sum(b)/(sum(d)+sum(b)));
d[a[j]]=val;}
}}
'
输出如下。
13 1.0000
12 0.8889
11 0.7778
8 0.6667
4 0.5556
3 0.4444
2 0.3333
1 0.0000
解决方案第二: 添加解决方案(与第一个不同的一个小问题),它将在输出中提供甚至重复项目的RANK,如下所示。
sort -nr Input_file | awk '
function sum(array){
tot="";
for(i in array){
tot+=array[i]};
return tot}
{
a[FNR]=$0;
b[$0]++
}
END{
for(j=1;j<=FNR;j++){
if(b[a[j]]){
val=val1=b[a[j]];
delete b[a[j]];
while(val1>0){
printf("%d %0.4f\n",a[j],sum(b)/(sum(d)+sum(b)));
val1--}
d[a[j]]=val;}
}}
'
13 1.0000
12 0.8889
11 0.7778
8 0.6667
4 0.5556
3 0.4444
2 0.3333
1 0.0000
1 0.0000
1 0.0000