如何使用awk仅打印在特定字段具有最小值的匹配项?

时间:2019-02-06 22:48:20

标签: awk minimum

我正在尝试解析HMMER给出的一些结果,并在tblout文件中能够隔离出我想要的匹配项。

尽管如此,如果仅与一个配置文件匹配,则同一值将重复多次。

例如,这是一次读取重复3次:

SRR6033660.161030 FAM007172 4e-15 4.2e-15 63.4 63.4
SRR6033660.1458607 FAM019859 2.5e-12 2.7e-12 55.0 54.9
SRR6033660.1458607 FAM015326 4e-14 4.2e-14 58.8 58.7
SRR6033660.1458607 FAM000764 7.5e-25 8.1e-25 94.6 94.5

它可以匹配3个家庭,不过我只想选择e值最低的行(第3列和第4列)

我如何编写一个awk命令给我这个输出?

SRR6033660.161030 FAM007172 4e-15 4.2e-15 63.4 63.4
SRR6033660.1458607 FAM000764 7.5e-25 8.1e-25 94.6 94.5

谢谢!

3 个答案:

答案 0 :(得分:0)

通常无法选择两个字段的最小值,在这里我提出了一种线性组合,您可以在其中设置权重。

$ awk -v a=0.5 '{c=a*$3+(1-a)*$4}
        !($1 in min) || c<min[$1]{min[$1]=c; minLine[$1]=$0}
         END{for(k in minLine) print minLine[k]}' file | column -t

SRR6033660.1458607  FAM000764  7.5e-25  8.1e-25  94.6  94.5
SRR6033660.161030   FAM007172  4e-15    4.2e-15  63.4  63.4

由于哈希,记录的顺序未保留。您可以添加序列号,然后根据该序列号进行排序。

答案 1 :(得分:0)

这将$3$4相加,并且总和最小的具有最低的e值(在没有更好的定义的情况下):

$ awk '
# $3+$4==s[$1] {            # this commented out part appends records when
#    r[$1]=r[$1] ORS $0     # the sum of $3+$4 is equally small with the 
# }                         # smallest so far
$3+$4<s[$1] || s[$1]=="" {  # if the sum of $3+$4 is the smallest or first
    s[$1]=$3+$4             # store the sum
    r[$1]=$0                # and record
}
END {                       # after all records are processed
    for(i in r)             # loop thru stored records
        print r[i]          # and output them
}' file
SRR6033660.1458607 FAM000764 7.5e-25 8.1e-25 94.6 94.5
SRR6033660.161030 FAM007172 4e-15 4.2e-15 63.4 63.4

如果取消注释第一个块,则脚本将输出所有具有最小$3+$4的记录,例如:awk {script} file file将输出:

SRR6033660.1458607 FAM000764 7.5e-25 8.1e-25 94.6 94.5
SRR6033660.1458607 FAM000764 7.5e-25 8.1e-25 94.6 94.5
SRR6033660.161030 FAM007172 4e-15 4.2e-15 63.4 63.4
SRR6033660.161030 FAM007172 4e-15 4.2e-15 63.4 63.4

答案 2 :(得分:0)

其他人提供了纯awk解决方案。请注意,它们实际上涉及将数据的全部内容加载到内存中。在一般情况下,这是有问题的。

事实证明,这种类型(特别是GNU coreutils版本,不确定其他版本)足够聪明,可以在处理大量数据时使用临时文件。它还可以比较浮点中指定的数字。

所以:

LC_NUMERIC=C sort <TBLOUT -k1 -k3g -k4g | awk 't!=$1{t=$1;print}'
  • 首先,对输入进行排序,以便按第一列对行进行分组,然后按第3列和第4列对数字进行排序
  • LC_NUMERIC=C确保我们在数字写为1.234,56(而不是1,234.56)的语言环境中正确排序
  • 如果第四列更重要,我们可以在-k3g-k4g之间切换
  • 组合/加权第3列和第4列并非易事(但我们可以预处理每行以产生一个新列-也许在排序之前通过另一个awk传递管道)
  • 将结果存入awk-仅打印第一列已更改的行