对数据进行分组并为新类别分配字母和数值

对数据进行分组并为新类别分配字母和数值

我的制表符分隔数据中有 4 列,我需要执行 2 个步骤。

  1. 根据前 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

如果需要解释,请在评论中询问。

相关内容