クロス集計を AWK で

クロス集計をBash(とawk)だけで実装した話 にインスパイヤされて AWK で作ってみます。 ここでは クロス集計をBash(とawk)だけで実装した話 の資料の P. 5 にある左の表を右の表の形式に変換します。

ここでは以下のような表を準備しました。

$ cat sample.txt
User    Item    Money
A       Ice     130
A       Ice     180
B       Juice   120
B       Ice     130
I       OREO    210
I       OREO    210
I       OREO    210

ユーザー (User) と商品 (Item) の重複を避けるために連想配列にインデックスと値が同じものを構成しています。

#! /usr/local/bin/gawk -f
# table.awk

NR > 1 {
    user[$1]        = $1;
    item[$2]        = $2;
    money           = $3;
    total[$1, $2]   = total[$1, $2] + money;
}

END {
    PROCINFO["sorted_in"] = "@val_str_asc";     # for gawk 4.0 or later

    for (i in item) {
        table_idx = table_idx sprintf("%8s", item[i]);
    }

    print sprintf("%8s", "") table_idx;

    for (i in user) {

        table = sprintf("%8s", user[i]);

        for (j in item) {
            table = table sprintf("%8d", total[i, j]);
        }

        print table;
    }
}

ただ、連想配列を使っているため、AWK では for ~ in で呼び出した際に順序が定まらないため、gawk 4.0 以降で使える PROCINFO で for ~ in での呼び出し順序を固定しています。

ではやってみましょう。

$ gawk -f table.awk sample.txt
             Ice   Juice    OREO
       A     310       0       0
       B     130     120       0
       I       0       0     630

このような形で集計を行うことができました。

tag_gawk.png