グループ集約ユーティリティ(例:SQL GROUP BY)?

グループ集約ユーティリティ(例:SQL GROUP BY)?

Unixには、ストリームで関係代数に似た操作を実行するためのいくつかのユーティリティがあります(grep、、、、、に追加)。すぐに利用可能な(またはほとんどのLinuxディストリビューションにインストール可能な)グループ集約ユーティリティはありますか?joincutawk

目的は、次のように、ある列にいくつかのキーがあり、他の列にいくつかの値を持つファイルを取得することです。

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

そして、ある列には一意の値があり、もう一方の列にはいくつかの値のセットを含むファイルが出力されます。たとえば、3番目の列と2番目の列の合計は次のようになります。

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

そのようなユーティリティが存在しますか(Perl、Awkなど、1行は含まれていません)、またはまだ作成されていませんか?

答え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これは可能です。まず、TSVではなくCSVファイルでなければなりません(RecutilsはTSVファイルが好きではないようです)、ヘッダーが必要です。しかし、私はこれを行うことができます:

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

これがPerlやAwk one-linerより良いか悪いかはわかりません。

答え3

awk 1行が含まれていない場合は、おそらく次のシェル(bash / ksh)1行が欲しいでしょう:

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)

そして(それぞれのグループ化と合計のために)ここで使用される興味深い要素は、sortwhileexpr内の読み取りステートメントです。括弧は、ローカライズ$prevと変数$sumに必要なサブプロセスを作成します。

関連情報