我有一个制表符分隔的文件:
Class Sample_1 Sample_2 Sample_3
A 0 0 0
Z 0.25 0 0.75
A|B|C 0 0 0
A|B|C 0 1 0
A|B|C 0.1875 0.671875 0.140625
A|B|C 0.2739726027 0.5890410959 0.1369863014
A|B|C|D|E 0 0.2 0.8
A|B|C|D 0.1666666667 0.3333333333 0.5
A|B|C|D 0.4723756906 0.179558011 0.3480662983
我想根据第一列中的 id 合并行并在合并时添加值:
Class Sample_1 Sample_2 Sample_3
A 0 0 0
Z 0.25 0 0.75
A|B|C 0.4614726027 2.2609160959 0.2776113014
A|B|C|D|E 0 0.2 0.8
A|B|C|D 0.6390423573 0.5128913443 0.8480662983
答案1
这就是 GNU datamash 擅长的事情:
$ datamash -H groupby 1 sum 2-4 < file.tsv | column -t
GroupBy(Class) sum(Sample_1) sum(Sample_2) sum(Sample_3)
A 0 0 0
Z 0.25 0 0.75
A|B|C 0.4614726027 2.2609160959 0.2776113014
A|B|C|D|E 0 0.2 0.8
A|B|C|D 0.6390423573 0.5128913443 0.8480662983
或者,在 GNU awk 中使用 2D 数组(尽管请注意,不能保证数组遍历的顺序 - 因此输出行不一定与输入的顺序相同):
$ gawk '
BEGIN{getline; print}
{for(i=2;i<=4;i++) a[$1][i] += $i}
END {
for(k in a){printf k; for(i=2;i<=4;i++) printf "\t%s", a[k][i]; printf "\n"}
}' file.tsv | column -t
Class Sample_1 Sample_2 Sample_3
A 0 0 0
A|B|C 0.461473 2.26092 0.277611
A|B|C|D 0.639042 0.512891 0.848066
A|B|C|D|E 0 0.2 0.8
Z 0.25 0 0.75
注意:我添加管道column -t
只是为了视觉格式化
答案2
通过下面的方法完成
for i in `awk 'NR>1{if (!seen[$1]++){print $1}}' p.txt`; do awk -v i="$i" '$1 == i{print $0}' p.txt| awk -v i="$i" 'BEGIN{sum=0;hum=0;rum=0}{sum=sum+$2;hum=hum+$3;rum=rum+$4}END {print i,sum,hum,rum}'|awk '{printf "%s%14s%20s%20s\n",$1,$2,$3,$4}'; done| sed '1i Class Sample_1 Sample_2 Sample_3'
输出
Class Sample_1 Sample_2 Sample_3
A 0 0 0
Z 0.25 0 0.75
A|B|C 0.461473 2.26092 0.277611
A|B|C|D|E 0 0.2 0.8
A|B|C|D 0.639042 0.512891 0.848066