将最大值除以第二大值

Divide largest value by second largest value

我有一个以下格式的文件。第一列有大约 20,000 个 uniq 条目,第二列有大约 120,000 个不同的条目,第三列有与第二列相关联的计数。对于第一列中的单个条目,第二列中可以有多个条目。对于第一列中的每个唯一条目,我我正在尝试获取第 3 列的最大值与第二个最大值的比率。

F1.txt

S1      S2      C1
A       A1      1
A       AA      10
A       A6      5
A       A0      4
B       BB      12
B       BC      11
B       B1      19
B       B9      4

预期输出

S1  S2  C1  
B   B1  19  1.58333
A   AA  10  2

我可以按照下面的步骤进行。但是有没有一种聪明的方法可以在一个脚本中完成?

awk 'NR==1; NR > 1 {print [=12=] | "sort -k3 -n -r "}' F1.txt | awk '!seen[]++' >del1.txt

awk 'FNR==NR{a[]=1; next}FNR==1{print [=13=];}!a[]' del1.txt F1.txt | awk 'NR==1; NR > 1 {print [=13=] | "sort -k3 -n -r"}' | awk '!seen[]++' >del2.txt

awk 'FNR==NR{a[]=; next}FNR==1{print [=14=]"\t";"RT"}FNR>1 a[]{print [=14=]"\t"/a[]}' del2.txt del1.txt

#!/usr/bin/awk -f

NR == 1 { print , , ; next }
{ data[][] =  }
END {
  for (key in data) {
    asorti(data[key], s, "@ind_num_desc")
    print key, data[key][s[1]], s[1], s[1] / s[2]
  }
}

这^^^假设行的任意排列(并且需要gawk(这很常见)或其他使用原生多维“数组”的实现)。

如果您可以对输入做出更多假设——例如它总是按第一列分组 —,那么您可以提高内存效率并摆脱多维数组(通过 not 延迟评估直到 END而是在每次第一列的值更改时在每行块中计算它(然后最后一次在 END 中)。)

要对相等的数值进行不同的处理(例如,报告第一个(而不是最后一个)出现的值的“子键”(第 2 列),您可以添加 if (!( in data[])) ... 或之类的

每当您发现自己正在创建一个包含 awk 的管道时,您尝试做的事情很有可能可以在一次调用 awk 中更有效地完成。

一种非 GNU awk 方法,假定所有 field1 'A' 记录都在一起并且所有 'B' 记录都在一起( 如您在示例数据中所示) 可能是:

awk '
    FNR==1 { print; next }      ## 1st line, output heading
     != n  {                  ## 1st field changed
        if (n) {                ## if n set, output result of last block
            printf "%s\t%s\n", rec, max / nextmax
        }
        rec = [=10=]                ## initialize vars for next block
        n = 
        max = 
        nextmax = 1
        next                    ## skip to next record
    }
    {
        if ( > max) {         ## check if 3rd field > max
            rec = [=10=]            ## save record
            nextmax = max       ## update nextmax
            max =             ## update max
        }
        else if ( > nextmax) {    ## if 3rd field > nextmax
            nextmax =             ## update nextmax
        }
    }   ## output final block results
    END { printf "%s\t%s\n", rec, max / nextmax }
' file

例子Use/Output

使用文件 file 中的数据,您将:

$ awk '
>     FNR==1 { print; next }      ## 1st line, output heading
>      != n  {                  ## 1st field changed
>         if (n) {                ## if n set, output result of last block
>             printf "%s\t%s\n", rec, max / nextmax
>         }
>         rec = [=11=]                ## initialize vars for next block
>         n = 
>         max = 
>         nextmax = 1
>         next                    ## skip to next record
>     }
>     {
>         if ( > max) {         ## check if 3rd field > max
>             rec = [=11=]            ## save record
>             nextmax = max       ## update nextmax
>             max =             ## update max
>         }
>         else if ( > nextmax) {    ## if 3rd field > nextmax
>             nextmax =             ## update nextmax
>         }
>     }   ## output final block results
>     END { printf "%s\t%s\n", rec, max / nextmax }
> ' file
S1      S2      C1
A       AA      10      2
B       B1      19      1.58333

在每个 Unix 机器上使用任何 shell 中的任何 awk 并且几乎不使用内存(这很重要,因为根据您的描述,您的输入文件会很大):

$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR == 1 { print; next }
 != prev {
    if ( prev != "" ) {
        print prev, val, max, (preMax ? max/preMax : 0)
    }
    prev = 
    max = ""
}
(max == "") || ( > max) {
    val = 
    preMax = max
    max = 
}
END { print prev, val, max, (preMax ? max/preMax : 0) }

$ awk -f tst.awk F1.txt
S1      S2      C1
A       AA      10      10
B       B1      19      1.58333