シェルでクロス集計するメモ
クロス集計をBash(とawk)だけで実装した話 より学んだことメモ
処理の流れ
1.必要なカラムの抽出
2.クロス集計の行と列の要素を取り出す。
# クロス集計表の行になる部分を抽出してユニーク化&ソート cat table.csv | cut -f 1 -d , | sort -u > rowname.txt # クロス集計の列になる部分を抽出、改行をタブに変えて縦横変換 cat table.csv | cut -f 2 -d , | sort -u | gtr '¥n' '¥t' > header.txt # cutコマンド補足 cut -f {取り出したい項目} -d {区切り文字}
3.awkでファイル分割する。
cat table.csv a,ice,130 a,ice,180 b,juice,120 b,ice,130 i,oreo,210 i,oreo,210 i,oreo,210 # awkで分割した結果をファイル出力できる cat table.csv | gawk -F, '{print > "split_"$2}' ls split_ice split_juice split_oreo table.csv
4.awkで集計する
5.sortでソート
ls | grep "split_" | gsed -e 's/split_//' | while read file; do gawk -F, '{a[$1]+=$3;}END{for(i in a)print i","a[i];}' split_${file} | sort -k 1 > sort_${file}; done
とか
gawk '{print FILENAME","$0}' split_* | gsed 's/split_//' | gawk -F, '{a[$1","$2]+=$4}END{for(i in a)print i","a[i];}' | sort -t, -k1,2 | gawk -F, '{print $2","$3 > "sort_"$1}'
6.2で取り出した行の要素と5の結果をJOIN
# joinできなかったキーも含めて出力し、空行は0で埋める ls | grep sort_ | gsed 's/sort_//' | while read file; do join -t ',' -1 1 -2 1 -a 1 rowname.txt sort_${file} | gawk -F, '{print $2}' | gsed 's/^$/0/g' > split_sum_${file}; done cat split_sum_juice 0 120 0 # joinコマンドメモ # -t 区切り文字を指定 # -1 1番目のファイルで結合キーに使う項目番号 # -2 2番目のファイルで結合キーに使う項目番号 # -a 1 LEFT JOIN (未指定の場合はINNNER JOIN) # -a 2 RIGHT JOIN join -t ',' -1 1 -2 1 -a 1 rowname.text sort_${file}
7.paste と cat でマージしてリストを表に加工
# pasteで列同士を結合する cp header.txt sum_result.txt paste rowname.txt split_sum_* >> sum_result.txt