如何从具有子组的CSV文件创建数据透视表并使用shell脚本获取最后一个值的计数?

问题描述 投票:0回答:5

我想对列进行分组,然后形成后续组,获取最后一列值的计数。例如,后续组中的主要组A,子组D,J,P和P的计数以及最后一列的总计数。我能够组成小组但是小组看起来有点困难。任何帮助都赞赏如何得到这个。

输入:

A,d,J,P A,d,J,Q A,d,K,P A,d,K,P A,E,J,Q A,E,K,Q A,E,J,Q B,F,L,R B,F,L,R B,F,M,S C,H,N,T C,H,O,U C,H,N,T C,H,O,U

输出:

A D J P 1 &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspQn 1 &nbsp&nbsp&nbsp&nbsp&nbspK P 2 A E J Q 2 &nbsp&nbsp&nbsp&nbsp&nbsp&nbspK Q 1 B F L R 2 &nbsp&nbsp&nbsp&nbsp&nbsp&nbspM S 1 C H N T 2 &nbsp&nbsp&nbsp&nbsp&nbsp&Ubsp U 2 &nbsp&nbsp&nbsp&nbspTotal 14

shell awk
5个回答
0
投票
$ cat tst.awk
BEGIN { FS="," }
!($0 in cnt) { recs[++numRecs] = $0 }
{ cnt[$0]++ }
END {
    for (recNr=1; recNr<=numRecs; recNr++) {
        rec = recs[recNr]
        split(rec,f)
        newVal = 0
        for (i=1; i<=NF; i++) {
            if (f[i] != p[i]) {
                newVal = 1
            }
            printf "%s%s", (newVal ? f[i] : " "), OFS
            p[i] = f[i]
        }
        print cnt[rec]
        tot += cnt[rec]
    }
    print "Total", tot+0
}


$ awk -f tst.awk file
A D J P 1
      Q 1
    K P 2
  E J Q 2
    K Q 1
B F L R 2
    M S 1
C H N T 2
    O U 2
Total 14

1
投票

这是一个不同的方法,一个使用sqlite计算组计数的shell脚本(需要3.25或更新,因为它使用窗口函数):

#!/bin/sh
file="$1"
sqlite3 -batch -noheader <<EOF
CREATE TABLE data(c1 TEXT, c2 TEXT, c3 TEXT, c4 TEXT);
.mode csv
.import "$file" data
.mode list
.separator " "
SELECT (CASE c1 WHEN lag(c1, 1) OVER (PARTITION BY c1 ORDER BY c1) THEN ' ' ELSE c1 END)
     , (CASE c2 WHEN lag(c2, 1) OVER (PARTITION BY c1,c2 ORDER BY c1,c2) THEN ' ' ELSE c2 END)
     , (CASE c3 WHEN lag(c3, 1) OVER (PARTITION BY c1,c2,c3 ORDER BY c1,c2,c3) THEN ' ' ELSE c3 END)
     , c4
     , count(*)
FROM data
GROUP BY c1, c2, c3, c4
ORDER BY c1, c2, c3, c4;
SELECT 'Total ' || count(*) FROM data;
EOF

运行这个给出:

$ ./group.sh example.csv
A D J P 1
      Q 1
    K P 2
  E J Q 2
    K Q 1
B F L R 2
    M S 1
C H N T 2
    O U 2
Total 14

也是使用datamash的单行,但它不包括花哨的输出格式:

$ datamash -st, groupby 1,2,3,4 count 4 < example.csv | tr , ' '
A D J P 1
A D J Q 1
A D K P 2
A E J Q 2
A E K Q 1
B F L R 2
B F M S 1
C H N T 2
C H O U 2

1
投票

使用Perl

脚本

perl -0777 -lne ' 
s/^(.+?)$/$x++;$kv{$1}++/mge; 
foreach my $k (sort keys %kv) 
    { $q=$c=$k; 
        while(length($p) > 0)
        {
        last if $c=~/^$p/g; 
        $q=substr($c,length($p)-1);
        $p=~s/(.$)//;
        }
    printf( "%9s\n", "$q $kv{$k}") ;
    $p=$k;
} 
print "Total $x";
' anurag.txt 

输出:

A,D,J,P 1
      Q 1
    K,P 2
  E,J,Q 2
    K,Q 1
B,F,L,R 2
    M,S 1
C,H,N,T 2
    O,U 2
Total 14

0
投票

我将以unix工具集的精神提出一个多阶段解决方案。

创建已排序,计数,去分隔的数据格式

$ sort file | uniq -c | awk '{print $2,$1}' | tr ',' ' ' 

A D J P 1
A D J Q 1
A D K P 2
A E J Q 2
A E K Q 1
B F L R 2
B F M S 1
C H N T 2
C H O U 2

现在,任务是从连续的行中删除最长的左公共子串

... | awk 'NR==1 {p=$0} 
           NR>1  {k=0; 
                  while(p~t=substr($0,1,++k)); 
                  gsub(/./," ",t); sub(/^ /,"",t); 
                  p=$0; $0=t substr(p,k)}1'


A D J P 1
      Q 1
    K P 2
  E J Q 2
    K Q 1
B F L R 2
    M S 1
C H N T 2
    O U 2

是否比一个脚本更容易理解。


0
投票

我没有一个能够产生你的示例输出的答案,但我已经足够接近敢于发布答案了

现在我的答案恰好产生了你的示例输出...... :-)

$ cat ABCD
A,D,J,P
A,D,J,Q
A,D,K,P
A,D,K,P
A,E,J,Q
A,E,K,Q
A,E,J,Q
B,F,L,R
B,F,L,R
B,F,M,S
C,H,N,T
C,H,O,U
C,H,N,T
C,H,O,U
$ awk '{a[$0]+=1}END{for(i in a) print i","a[i];print "Total",NR}' ABCD |\
  sort | \
  awk -F, '
    /Total/{print;next}
    {print a1==$1?" ":$1,a2==$2?" ":$2,a3==$3?" ":$3,a4==$4?" ":$4,$5
     a1=$1;a2=$2;a3=$3;a4=$4}'
A D J P 1
      Q 1
    K P 2
  E J Q 2
    K   1
B F L R 2
    M S 1
C H N T 2
    O U 2
Total 14
$ 

第一个awk脚本在每一行迭代,在每一行我们增加一个数组的值,a,元素,由整行值索引,接下来在最后(END目标)我们循环在a的索引上打印索引以及相关的值,即我们在数据中包含该行的次数 - 最终我们还输出处理的总行数,该值在变量NR中自动更新,记录数。

第二个awk脚本打印总行并跳过任何进一步的处理,或者将每个字段(用逗号分割)与前一行的相应字段进行比较,并相应地输出新字段或空格。

© www.soinside.com 2019 - 2024. All rights reserved.