【问题标题】:removal of redundant lines based on value in last column根据最后一列中的值删除冗余行
【发布时间】:2013-04-11 08:47:39
【问题描述】:

我正在尝试从制表符分隔文件中删除冗余数据,如下所示

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}'

请帮忙

【问题讨论】:

  • 输入的倒数第二行缺少制表符,这可能是这里的问题。

标签: perl shell awk


【解决方案1】:
$ 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-3 的行时,这将使用最后一行,而不是具有最高列 4 的行。
  • 文件不应该先排序吗?
  • 问题中要求:应该使用第四列(最大值)
  • 连接是否正确?如果一行有chr1 34 5 而另一行有chr1 3 45 怎么办?
  • 美丽。如果可以的话,我会再给它 +1 :-)。
【解决方案2】:
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

【讨论】:

  • 第 4 列中的值的一个问题已解决,就像行 chr1 2491 2501 的情况一样,但行的重复仍然存在,它应该选择最高值第四列如行:chr1 3241 3251
  • 已修复。 sort -u 不能只作用于密钥的一部分,所以它确实需要 awk。
  • 请检查测试数据,它仍然不起作用:( ...第3列中最高值的重复行仍然存在,它需要从数据集中关闭
  • 我确实测试过(我第一次搞砸了,我在输出而不是输入上测试了它)。
  • 我仍然得到这两行输出 chr1 3241 3251 6 chr1 3241 3251 1 而不是只有这一行 chr1 3241 3251 6
【解决方案3】:

这个单行应该给出输出:

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

【讨论】:

  • 不,它没有。输出文件仍然包含重复的值。查找行 chr1 3241 3251 ,当它在第四列中的最高值为 6 时,它出现了两次而不是一次
  • @Angelo 它不会。因为在数组中,相同的索引/键将被覆盖。查看输出,我在答案中添加了。
  • 我不知道为什么,但我没有得到你得到的输出。问题只是 chr1 3241 3251 行,我在第四列得到 chr1 3241 3251 1 而不是 6
  • @Angelo 你能检查你的真实文件中的3241 3251 1 行是否是单个制表符分隔的吗?尝试在 vim 中打开你的文件并执行这个::%s/\s\+/\t/g 然后再试一次。
【解决方案4】:

您可以通过使用前三列作为哈希的键来做到这一点,并且只记住具有最大 $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

【讨论】:

  • @Angelo:哪个版本不工作?您使用的是什么版本的 awk?
  • awk 版本是 4.0.0,是这个问题吗?
  • @Angelo:它在这里工作。也许是因为我通过unexpand -a传递文件?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-06
  • 2019-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-20
相关资源
最近更新 更多