首页 > 解决方案 > 如何比较一个字段中具有相同唯一子字符串的行并仅保留最后一个字段中具有最大数字的行?

问题描述

我有一个文件,其格式为一系列唯一标识符 ( >lcl|ORF#_URS[:alnum:]:##:## foo, bar:##) 段,后跟相应的 alpha 字符串 ( ALPHAALPHAALPHA:::0) 在其正下方的行上。文件样本:

>lcl|ORF1_URS0000000001:102:197 unnamed protein product:95
MVVGDNARKRTLIPHTSYGRKQGTFGPCAIR:::0
>lcl|ORF2_URS0000000001:1:93 unnamed protein product, partial:92
LNAGGRPNTCKSSGREKLASLESGGRVSNA:::0
>lcl|ORF3_URS0000000001:8:82 unnamed protein product:74
MAAGLTHASRAVERSLLLLRAADG:::0
>lcl|ORF4_URS0000000001:86:118 unnamed protein product:32
MPRNLPGSGG:::0
>lcl|ORF5_URS0000000001:193:152 unnamed protein product:41
MIAQGPKVPCFLP:::0
>lcl|ORF6_URS0000000001:167:135 unnamed protein product:32
MLSPVGRMRY:::0
>lcl|ORF7_URS0000000001:32:0 unnamed protein product, partial:32
MHVLGLPPAFN:::0
>lcl|ORF1_URS00000000M3:42:77 unnamed protein product:35
MINALCSYLLA:::0
>lcl|ORF2_URS00000000M3:174:236 unnamed protein product:62
MRGRSPTLVLRHGPDFYGRQ:::0
>lcl|ORF3_URS00000000M3:246:311 unnamed protein product:65
MDNGGNSDPAMPREGRRPYGL:::0

解决此问题需要重点关注的关键元素是字母数字URS 标识符和以“>”开头并以“:”分隔的行的最后一个字段 ( $4 ) 。

我想只保留每个唯一字母数字 URS 标识符(例如 ,URS0000000001URS00000000M3)在同一行的最后一个字段中具有最大值的行(始终以“”开头并以“ >”分隔:)。如果同一标识符的最终字段中有两行或多行具有相同值,则取第一行或最后一行(无关紧要)。所需输出的示例:

>lcl|ORF1_URS0000000001:102:197 unnamed protein product:95
>lcl|ORF3_URS00000000M3:246:311 unnamed protein product:65

或者,如果它更简单:

URS0000000001    95
URS00000000M3    65

这远远超出了我的能力awk,但我觉得我的逻辑已经完成了一半。我尝试编写一个awk命令,搜索以“”开头的每一行,并在大于具有相同 URS 标识符的另一行时>打印该行:$4$4

awk -F":" 'BEGIN {OFS=FS} /^ *>/ {if (substr($1,11)==substr($1,11)){$4>$4}} 1' file

必须有更好的方法来匹配不同行上字段 ( ) 的子字符串$1,以便随后将链接/关联字段 ( $4) 与进行比较awk。想法?

标签: awk

解决方案


请您尝试以下方法:

awk -F ":" '
    NR==FNR {                                   # 1st loop to find the maximum valued line for each id
        if (match($1, "URS[[:alnum:]]+")) {     # check if $1 matches the format
            id = substr($1, RSTART, RLENGTH)    # extract the id
            if ($4 > a[id]) {                   # if $4 > max
                a[id] = $4                      # update the max value
                b[id] = $1                      # memorize the corresponding $1
            }
        }
        next
    }
    {                                           # 2nd loop to print the maximum valued line for each id
        if (match($1, "URS[[:alnum:]]+")) {
            id = substr($1, RSTART, RLENGTH)
            if ($1 == b[id]) print
        }
    }
' file file

输出:

>lcl|ORF1_URS0000000001:102:197 unnamed protein product:95
>lcl|ORF3_URS00000000M3:246:311 unnamed protein product:65

如果更简单的输出足够好并且您不介意出现的顺序,则可以使用更简单的替代方法:

awk -F ":" '
    NR==FNR {
        if (match($1, "URS[[:alnum:]]+")) {
            id = substr($1, RSTART, RLENGTH)
            if ($4 > a[id]) a[id] = $4
        }
        next
    }
    END {
        for (i in a) print i, a[i]
    }
' file

输出:

URS00000000M3 65
URS0000000001 95

推荐阅读