分组聚合实用程序(如 SQL GROUP BY)?

分组聚合实用程序(如 SQL GROUP BY)?

Unix 有几个实用程序用于在流上执行类似关系代数的操作(grepjoincut、 的附加内容awk)。是否有现成可用的分组聚合实用程序(或可在大多数 Linux 发行版上安装)?

目标是获取一个文件,其中一列中有一些键,另一列中有一些值,例如:

foo.txt   u1    394082
bar.txt   u2    3948
frob.c    u1    29322

并输出一个文件,该文件具有一列的唯一值以及另一列中的某些值的聚合。例如,第三列与第二列之和:

$ aggregate --sum=3 --group-by=2 <data
u1 423404
u2 3948

这样的实用程序是否存在(Perl、Awk 等,单行不算),还是有待编写?

答案1

我想我在另一个 StackOverflow 问题中找到了这个答案,但我发现“q”对于这个目的非常有用:https://github.com/harelba/q

例如,您的示例目标可以这样实现:

$ q "select c2, sum(c3) from data group by c2"
u1 423404
u2 3948

由于它使用 sqlite 作为后端,因此您可以使用各种 sqlite 函数进行计算。

答案2

有一些限制GNU Recutils可以做到这一点。首先,它需要是 CSV 文件,而不是 TSV(Recutils 似乎不喜欢 TSV 文件),并且需要一个标头。但我可以这样做:

csv2rec foo.csv |recsel -G user -p 'user,sum(size)' |rec2csv

不确定这比 Perl 或 Awk 单行代码是好是坏。

答案3

如果 awk 的单行代码不算数,也许您会喜欢以下 shell (bash/ksh) 单行代码:

sort -k2 data | ( while read c1 c2 c3; do if [ "$prev" = "$c2" ]; then
sum=$(expr $c3 + $sum); else if [ $prev ]; then echo $prev $sum; fi;
sum=$c3; prev=$c2; fi; done; echo $prev $sum)

除了sortand expr(分别用于分组和求和)之外,这里使用的有趣成分是 while 内的 read 语句。括号创建了本地化$prev$sum变量所必需的子流程。

相关内容