数据结构

数据结构

我有一些以下形式的输出:

count  id     type
588    10 |    3
 10    12 |    3
883    14 |    3
 98    17 |    3
 17    18 |    1
77598    18 |    3
10000    21 |    3
17892     2 |    3
20000    23 |    3
 63    27 |    3
  6     3 |    3
 2446    35 |    3
 14    4 |    3
 15     4 |    1
253     4 |    2
19857     4 |    3
 1000     5 |    3
...

这相当混乱,需要清理成 CSV 文件,这样我就可以将它送给项目经理,让他们把电子表格搞得一团糟。

问题的核心是:我需要的输出是:

id、sum_of_type_1、sum_of_type_2、sum_of_type_3

id“4”就是一个例子:

14    4 |    3
 15     4 |    1
253     4 |    2
19857     4 |    3

这应该是:

4,15,253,19871

不幸的是,我对这类事情很垃圾,我已经设法清理所有行并将其转换为 CSV,但我无法对行进行重复数据删除和分组。现在我有这个:

awk 'BEGIN{OFS=",";} {split($line, part, " "); print part[1],part[2],part[4]}' | awk '{ gsub (" ", "", $0); print}'

但所做的只是清理垃圾字符并再次打印行。

将行按摩到上述输出的最佳方法是什么?

答案1

一种方法是将所有内容放入哈希中。

# put values into a hash based on the id and tag
awk 'NR>1{n[$2","$4]+=$1}
END{
    # merge the same ids on the one line
    for(i in n){
        id=i;
        sub(/,.*/,"",id);
        a[id]=a[id]","n[i];
    }
    # print everyhing
    for(i in a){
        print i""a[i];
    }
}'

编辑:我的第一个答案没有正确回答问题

答案2

Perl 来拯救:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

<>;  # Skip the header.

my %sum;
my %types;
while (<>) {
    my ($count, $id, $type) = grep length, split '[\s|]+';
    $sum{$id}{$type} += $count;
    $types{$type} = 1;
}

say join ',', 'id', sort keys %types;
for my $id (sort { $a <=> $b } keys %sum) {
    say join ',', $id, map $_ // q(), @{ $sum{$id} }{ sort keys %types };
}

它保存两个表,类型表和 ID 表。对于每个 id,它存储每种类型的总和。

答案3

如果GNU 数据混合是你的一个选择,那么

awk 'NR>1 {print $1, $2, $4}' OFS=, file | datamash -t, -s --filler=0 crosstab 2,3 sum 1
,1,2,3
10,0,0,588
12,0,0,10
14,0,0,883
17,0,0,98
18,17,0,77598
2,0,0,17892
21,0,0,10000
23,0,0,20000
27,0,0,63
3,0,0,6
35,0,0,2446
4,15,253,19871
5,0,0,1000

答案4

您可以使用 Perl 循环 CSV 文件,并在此过程中将适当类型的总和累加到哈希中。最后,显示为每个 ID 收集的信息。

数据结构

%h = (
   ID1    =>  [ sum_of_type1, sum_of_type2, sum_of_type3 ],
   ...
)

这有助于理解下面的代码:

珀尔

perl -wMstrict -Mvars='*h' -F'\s+|\|' -lane '
   $, = chr 44, next if $. == 1;

   my($count, $id, $type) = grep /./, @F;
   $h{ $id }[ $type-1 ] += $count}{
   print $_, map { $_ || 0 } @{ $h{$_} } for sort { $a <=> $b } keys %h
' yourcsvfile

输出

2,0,0,17892
3,0,0,6
4,15,253,19871
5,0,0,1000
...

相关内容