我的文件data.txt包含以下记录结构,包含数百万行:
13
12
11
8
4
3
2
1
1
1
对于这个列的每个值,我需要计算它的PERCENTRANK(数据集中某个值作为数据集的百分比的排名)。
计算数据集中任何值X的百分比秩的公式是
= number of values less than X / (Number of values less than X + Number of Values greater than X)
因此,对于数据集中的每个值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,而六个值大于2。百分比秩2=3/(3+6)=3/9=0.3333。
类似地,4的PERCENTRANK为0.5555,因为5个值小于4,4个值大于4。百分位4=5/(5+4)=5/9=0.5555。
我正在避免嵌套的“while..do”循环,因为在包含数百万条记录的文件中循环时速度非常慢。
我对awk在许多其他迭代计算场景中惊人的速度感到满意,例如:计算平均值、标准差、按和分组等等,因此,理想情况下,我也希望使用awk来解决这个用例。
最佳答案
遵循更简单的sort
和awk
方法可能也有同样的帮助(尽管我没有在数百万行上进行测试,因为我没有它)。
解决方案1:在您的示例中,这不会在输出eg-->数字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
解决方案2:添加解决方案(与第一个不同的小方案),它将在输出中提供甚至重复项的排名,如下所示。
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