根据最后一列中的值删除冗余行

时间:2013-04-11 08:47:40

标签: perl shell awk

我正在尝试从我的制表符分隔文件中删除冗余数据,该文件看起来像这样

chr1    1841    1851    4
chr1    1991    2001    3
chr1    2491    2501    2
chr1    2491    2501    2
chr1    2501    2511    1
chr1    2681    2691    3
chr1    2881    2891    4
chr1    2891    2901    1
chr1    3241    3251    1
chr1    3241    3251    6

条件是:如果前三列相同,则应使用第四列(最高值)中的值来获取前三列和第四列。如果存在平局,则只应打印4列中的值。

因此,对于上述输入,理想输出应为

chr1    1841    1851    4
chr1    1991    2001    3
chr1    2491    2501    2
chr1    2501    2511    1
chr1    2681    2691    3
chr1    2881    2891    4
chr1    2891    2901    1
chr1    3241    3251    6

我是怎么接近的:

首先对文件进行排序,然后将其搞砸了

sort file | awk -F '\t' 'NR==1{last = $1; max = 0} {if (last != $1) {printf "%s\t%e\n", last, max; last = $1; max = $4} else if (max < $4) max = $4} END{printf "%s\t%e\n", last, max}'

请帮助

4 个答案:

答案 0 :(得分:3)

$ sort -k1 -k2,3n -k4nr file | awk '!a[$1,$2,$3]++'
chr1    1841    1851    4
chr1    1991    2001    3
chr1    2491    2501    2
chr1    2501    2511    1
chr1    2681    2691    3
chr1    2881    2891    4
chr1    2891    2901    1
chr1    3241    3251    6

答案 1 :(得分:1)

sort -k 1,3 -k 4r file | awk 'last != $1" "$2" "$3 { print; last = $1" "$2" "$3; }'

我的输出:

chr1    1841    1851    4
chr1    1991    2001    3
chr1    2491    2501    2
chr1    2501    2511    1
chr1    2681    2691    3
chr1    2881    2891    4
chr1    2891    2901    1
chr1    3241    3251    6

http://ideone.com/nH6boE

答案 2 :(得分:1)

您可以将前三列用作哈希的键,并且只记住具有最大$4的那一列:

<infile awk '
  BEGIN { FS = OFS = "\t" }

  $4 > h[$1,$2,$3] { h[$1,$2,$3] = $4 }

  END { 
    for(k in h) { 
      split(k, a, SUBSEP)
      print a[1], a[2], a[3], h[k]
    }
  }
' | sort -k1 -k2n,3n

输出:

chr1    1841    1851    4
chr1    1991    2001    3
chr1    2491    2501    2
chr1    2501    2511    1
chr1    2681    2691    3
chr1    2881    2891    4
chr1    2891    2901    1
chr1    3241    3251    6

如果你使用的是GNU awk,你也可以在awk中进行排序:

parse.awk

BEGIN { FS = OFS = "\t" }

$4 > h[$1,$2,$3] { h[$1,$2,$3] = $4 }

END { 
  len = asorti(h, d)
  for(i=1; i<=len; i++) {
    flen = split(d[i], a, SUBSEP)
    for(j=1; j<=flen; j++)
      printf "%s%s", a[j], OFS
    print h[d[i]]
  }
}

然后像这样运行:

awk -f parse.awk infile

答案 3 :(得分:1)

这个单行应该给出输出:

awk -F'\t' -v OFS="\t" '{t=$1FS$2FS$3;if(!(t in a)||a[t]<$4)a[t]=$4}END{for(x in a) print x,a[x]}' file|sort

清晰格式:

 awk -F'\t' -v OFS="\t" '{
    t=$1FS$2FS$3
    if(!(t in a)||a[t]<$4)
        a[t]=$4
 }
 END{for(x in a) print x,a[x]}' file|sort

如果您使用数据文件运行:

kent$  cat file
chr1    1841    1851    4
chr1    1991    2001    3
chr1    2491    2501    2
chr1    2491    2501    2
chr1    2501    2511    1
chr1    2681    2691    3
chr1    2881    2891    4
chr1    2891    2901    1
chr1    3241    3251    1
chr1    3241    3251    6

kent$  awk -F'\t' -v OFS="\t" '{t=$1FS$2FS$3;if(!(t in a)||a[t]<$4)a[t]=$4}END{for(x in a) print x,a[x]}' file|sort
chr1    1841    1851    4
chr1    1991    2001    3
chr1    2491    2501    2
chr1    2501    2511    1
chr1    2681    2691    3
chr1    2881    2891    4
chr1    2891    2901    1
chr1    3241    3251    6