廿TT

譬如水怙牛過窓櫺 頭角四蹄都過了 因甚麼尾巴過不得

dplyr ユーザーのための AWK 入門

はじめに

dplyrを使いこなす!基礎編 - Qiita を参考に、相模原市オープンデータライブラリー | 相模原市 で公開されている駅別乗降人員の推移データを使用して dplyr と対比させながら AWK で簡単な集計を行ってみます。

行の絞り込み

dplyr でいう filter みたいなことがやりたい場合。

AWK は単に条件を書くだけで条件に沿ったデータを出力します。

2行目が "町田駅(参考)" となっている列を抽出したいときはこうします。

awk -F, '$2== "町田駅(参考)"' jyoukou_20141111.csv
>横浜線,町田駅(参考),54506,79366,119620,171478,195652,197638,211864,216428,215598,218154,218084,221086,221880
>小田急線,町田駅(参考),154831,197393,236259,281813,297703,279498,282772,291952,289622,290621,288884,291678,292779

-F, はカンマを区切り文字として認識させるためのオプションです。

&& でつなぐことで AND 条件、|| でつなぐことで OR 条件が使用可能です。

列ごとの集計

dplyr でいう summarise みたいなことがやりたいとき。

列ごとの集計は AWK の得意分野です。

AWK はテキストファイルを一行ずつ読んでいき、条件にマッチした行に対してアクションを実行します。

プログラムの構成は基本的には、以下のようになります。

BEGIN {
  (ファイルを読み込む前にやる処理)
}

(条件 1) {
  (アクション 1)
}

(条件 2) {
  (アクション 2)
}
 
...
 
END {
  (ファイルを読み終わった後にやる処理)
}

BEGIN 節、END 節 は省略可能です。

3 列目の合計を求めたいときはこうします。

awk -F, 'NR > 1{sum+=$3}END{print sum}' jyoukou_20141111.csv
>506989

NR > 1 は「行の番号が 1 より大きい」という意味です。最初の行には列名が入っているので飛ばしました。

; で区切ってアクションを複数書くこともできます。

awk -F, 'NR > 1 {sum1 += $3; sum2 += $4} END {print sum1, sum2}' jyoukou_20141111.csv
>506989 599739

グループ化

dplyr でいう group_by みたいなことがやりたいとき。

awk の配列は文字列を添え字として使うことができます。

配列の大きさを宣言する必要はありません。

以下では一列目に登場する文字列を sum という配列の添え字にしています。

awk -F, 'NR > 1 {sum[$1] += $3} END {for(i in sum) print i ","sum[i]}' jyoukou_20141111.csv
>小田急線,339273
>京王線,0
>相模線,11690
>中央本線,0
>横浜線,156026

複数列をキーにして集計したいときはこうします。

awk -F, '{array[$1","$2]+=$3} END { for (i in array) {print i"," array[i]}}' jyoukou_20141111.csv

新しい列の追加

dplyr でいう mutate みたいなことがやりたいとき。

列同士で計算して新しい列を作るのもかんたんです。

$3=$1+$2 とすれば、「3列目 = 1列目 + 2列目」の意味です。

awk -F, 'BEGIN{OFS = ","}NR==1{$1="newline"; print $0}NR > 1 {$1 = $3+$4;print$0}' jyoukou_20141111.csv  > new.csv

R の ifelse のようなことがやりたいときは ? という演算子が使えます。

$3 > 10000 ? 1 : 0 とすると、「10000 より大きければ 1 そうでなければ 0」という意味です。

awk -F, 'BEGIN{OFS = ","}NR==1{$1="newline"; print $0}NR > 1 {$1=$3 > 10000 ? 1 : 0 ;print$0}' jyoukou_20141111.csv  > new.csv

付録

jyoukou_20141111.csv データはところどころ空欄がある。

空欄を無視して最小値を取り出すコードを書いてみた。

BEGIN{
	FS = ","
}
(NR > 1&& $3 !=""){
	counter++;
	array[counter]=$3;
	}
END{
	min =array[1];
	for(i=2; i<=counter; i++){
		if(min>array[i]) min = array[i];
		}
	print min
}

最大値の場合はもっとシンプルに書けます。下記のページなどをご覧ください。

Awkワンライナー (最小値、最大値、合計、平均、中央値) - それがしの足音

関連エントリ

abrahamcow.hatenablog.com