我的制表符分隔数据中有 4 列,我需要执行 2 个步骤。
- 根据前 2 列的组合对数据进行分组。
- 每当特定组 (col2) 的串联值 (col 4) 中出现新的值组合时,我需要按字母顺序和数字顺序为该行分配一个新类别。如果之前遇到过该组合,则分配相应的类别。
输入文件看起来像
Line Group Name Value
L1 G1 AX27 A
L1 G1 AX25 T
L1 G1 AX356 G
L1 G2 1X87 C
L1 G2 AX78 A
L1 G2 AX987 A
L1 G2 AX001B A
L1 G3 A2XTR1 A
L1 G3 A2XTR2 T
L2 G1 AX27 A
L2 G1 AX25 T
L2 G1 AX356 C
L2 G2 1X87 G
L2 G2 AX78 T
L2 G2 AX987 A
L2 G2 AX001B A
L2 G3 A2XTR1 A
L2 G3 A2XTR2 T
L3 G1 AX25 T
L3 G1 AX356 G
L3 G2 AX987 A
L3 G2 AX001B A
L3 G3 A2XTR1 A
L3 G3 A2XTR2 C
L4 G1 AX27 A
L4 G1 AX25 T
L4 G1 AX356 G
L4 G3 A2XTR1 A
L4 G3 A2XTR2 C
L5 G3 A2XTR1 A
L5 G3 A2XTR2 T
中间输出文件看起来像
Line Group Collapsednames Collapsedvalues
L1 G1 AX27 AX25 AX356 A T G
L2 G1 AX27 AX25 AX356 A T C
L3 G1 AX25 AX356 T G
L4 G1 AX27 AX25 AX356 A T G
L1 G2 1X87 AX78 AX987 AX001B C A A A
L2 G2 1X87 AX78 AX987 AX001B G T A A
L3 G2 AX987 AX001B A A
L1 G3 A2XTR1 A2XTR2 A T
L2 G3 A2XTR1 A2XTR2 A T
L3 G3 A2XTR1 A2XTR2 A C
L4 G3 A2XTR1 A2XTR2 A C
L5 G3 A2XTR1 A2XTR2 A T
对于所有行(L1 到 L4),G1 具有 3 个不同的组合(ATG 、 ATC 、 TG ),其中组合 (ATG) 是重复的。因此,我们可以将字母类别 A、B 和 C 分配给其中 A 出现两次的每个组合。
所以最终的输出看起来像
Line Group Collapsednames Collapsedvalues Alpha_Category Number_Category
L1 G1 AX27 AX25 AX356 A T G A 1
L2 G1 AX27 AX25 AX356 A T C B 2
L3 G1 AX25 AX356 T G C 3
L4 G1 AX27 AX25 AX356 A T G A 1
L1 G2 1X87 AX78 AX987 AX001B C A A A A 1
L2 G2 1X87 AX78 AX987 AX001B G T A A B 2
L3 G2 AX987 AX001B A A C 3
L1 G3 A2XTR1 A2XTR2 A T A 1
L2 G3 A2XTR1 A2XTR2 A T A 1
L3 G3 A2XTR1 A2XTR2 A C B 2
L4 G3 A2XTR1 A2XTR2 A C B 2
L5 G3 A2XTR1 A2XTR2 A T A 1
这是我尝试过的步骤 1,但没有奏效。弄清楚步骤 1 后,我不知道如何进行步骤 2。
awk -F"\t" '{if(a[$1$2]){a[$1$2]=a[$1$2]" "$3" "$4} else { a[$1$2]=$3"\t$4}} END {for (i in a) {print i"|"a[i]}}' file
答案1
并不像看起来那么容易。 Perl 解决方案,我尝试更详细一些以使代码易于理解。需要嵌套数据结构(哈希的哈希、数组的哈希)的基本知识。
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
my (%collapsed, %groups);
<>; # Skip header.
while (<>) {
my ($line, $group, $name, $value) = split;
push @{ $collapsed{$line}{$group}{names} }, $name;
push @{ $collapsed{$line}{$group}{values} }, $value;
undef $groups{$group};
}
for my $group (sort keys %groups) {
for my $line (sort keys %collapsed) {
next unless $collapsed{$line}{$group};
my $value = join q(), @{ $collapsed{$line}{$group}{values} };
$groups{$group}{$value} ||= keys %{ $groups{$group} };
}
}
for my $group (sort keys %groups) {
for my $line (sort keys %collapsed) {
next unless $collapsed{$line}{$group};
my $value = join q(), @{ $collapsed{$line}{$group}{values} };
say join "\t", $line, $group,
join(' ', @{ $collapsed{$line}{$group}{names} }),
join(' ', @{ $collapsed{$line}{$group}{values} }),
chr $groups{$group}{$value} - 1 + ord 'A',
$groups{$group}{$value},
}
}
答案2
Awk
解决方案(许多关联数组)但是:
#!/usr/bin/awk
BEGIN {
SUBSEP=" "
split("A1^B2^C3^D4^E5",c,"^")
}
NR != 1 {
L[$1]=1
G[$2]=1
a[$1,$2]=a[$1,$2]" "$3
b[$1,$2]=b[$1,$2]" "$4
}
END {
for (g in G)
{
i=1
for (l in L)
{
idx=b[l,g]
if(d[idx]=="")
d[idx]=c[i++]
}
}
for (k in a)
print k a[k] b[k],d[b[k]]
}
并执行上面的脚本:
awk -f script.awk tab.data | sort -k2,2 -k1,1
如果需要解释,请在评论中询问。