我有一个似乎无法解决的问题。
我有一个巨大的制表符分隔文本文件,类似于:
chr 10 20 20 a
chr 30 40 10 b
chr 30 40 15 b
chr 30 40 11 b
我需要的是:1)提取所有唯一的行2)如果第5列被多次表示(例如b),则第4列中具有最大值的行。
所以上面的例子中我需要的行是:
chr 10 20 20 a(这是一个独特的行) chr 30 40 15 b(当第 5 列被多次表示时,这是第 4 列中具有最大值的行。
有没有一种简单的方法可以做到这一点?
答案1
那么,按第五列对行进行分组,并为每个组打印第四列最大的行?
假设你没有负数:
$ awk '$4 > val[$5] {val[$5] = $4; line[$5] = $0}
END {for (x in line) print line[x] }' < foo.txt
chr 10 20 20 a
chr 30 40 15 b
答案2
示例.txt
chr 10 20 20 a
chr 30 40 10 b
chr 30 40 15 b
chr 30 40 11 b
代码
awk '$5== "a" {print $0}' l.txt | sort -k4 -nr | sed -n '1p' ; awk '$5=="b" {print $0}' l.txt | sort -k4 -nr | sed -n '1p'
输出
chr 10 20 20 a
chr 30 40 15 b
答案3
我会写:
awk '
NR == FNR {count[$5]++; if ($4 > max[$5]) max[$5] = $4; next}
count[$5] > 1 && $4 == max[$5] && !seen[$0]++
' file file
chr 30 40 15 b
处理文件两次:
- 第一次,统计第5个字段出现的频率,并为每个第5个字段值找到最大的第4个字段
- 第二次,处理你的标准:
- 只记录第 5 个字段出现多次的情况,并且
- 仅包含最大第四个字段的记录,并且
- 仅唯一记录
如果你想查看计数为 1 的行,那么我们可以简单地写
awk 'NR == FNR {if ($4 > max[$5]) max[$5]=$4; next} $4==max[$5] && !seen[$0]++' file file
chr 10 20 20 a
chr 30 40 15 b
答案4
这个片段:
# Utility functions: print-as-echo, print-line-with-visual-space.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
pl " Input data file $FILE:"
head $FILE
pl " Expected output:"
cat $E
pl " Results:"
datamash -t" " --group=5 max 4 --full <$FILE |
cut -d" " -f1-5
产生:
-----
Input data file data1:
chr 10 20 20 a
chr 30 40 10 b
chr 30 40 15 b
chr 30 40 11 b
-----
Expected output:
chr 10 20 20 a
chr 30 40 15 b
-----
Results:
chr 10 20 20 a
chr 30 40 15 b
对于这样的系统:
OS, ker|rel, machine: Linux, 3.16.0-4-amd64, x86_64
Distribution : Debian 8.9 (jessie)
bash GNU bash 4.3.30
datamash (GNU datamash) 1.2
cut (GNU coreutils) 8.23
datamash 的一些详细信息:
datamash command-line calculations (man)
Path : /usr/local/bin/datamash
Version : 1.2
Type : ELF 64-bit LSB executable, x86-64, version 1 (SYS ...)
Help : probably available with -h,--help
Home : https://savannah.gnu.org/projects/datamash/ (pm)
Home : http://www.gnu.org/software/datamash (doc)