RやPythonのような成熟したコンピューティング環境は、詳しくデータを分析するのには素晴らしいものだ。しかし、素早くシンプルにデータの調査や捜査をしたいときには、UNIXのコマンドラインツールはものすごく効率的だ。この記事では、自分で見つけ日々使っているいくつかのツールに光を当ててみようと思う。新しいツールをあなたのレパートリーに加えられたらうれしい。
ファイルをのぞき見る( head
tail
less
)
NASAのサンプルWebログデータをダウンロードするところから始めよう。
$ wget ftp://ita.ee.lbl.gov/traces/NASA_access_log_Jul95.gz
ダウンロードされたファイルはgzipで圧縮されており、 less
はデフォルトではこれを展開まではしてくれない。しかしその代わり、 zless
を使える。あるいは、 gunzip
の結果をファイルに代わって、パイプで他のコマンドに出力を送るのに便利な stdout
(標準出力)に送れば、 head
や tail
でファイルの先頭や最後をそれぞれ調査することができる。
$ gunzip -c NASA_access_log_Jul95.gz | head -n 5
199.72.81.55 - - [01/Jul/1995:00:00:01 -0400] "GET /history/apollo/ HTTP/1.0" 200 6245
unicomp6.unicomp.net - - [01/Jul/1995:00:00:06 -0400] "GET /shuttle/countdown/ HTTP/1.0" 200 3985
199.120.110.21 - - [01/Jul/1995:00:00:09 -0400] "GET /shuttle/missions/sts-73/mission-sts-73.html HTTP/1.0" 200 4085
burger.letters.com - - [01/Jul/1995:00:00:11 -0400] "GET /shuttle/countdown/liftoff.html HTTP/1.0" 304 0
199.120.110.21 - - [01/Jul/1995:00:00:11 -0400] "GET /shuttle/missions/sts-73/sts-73-patch-small.gif HTTP/1.0" 200 4179
列をフィルタリングする( awk
cut
)
最初の列には、リクエスト元の(サブ)ドメインかIPアドレスが書いてあるようだ。こういった部分を抜き出すのによく使われるツールは awk
と cut
だ。
$ gunzip -c NASA_access_log_Jul95.gz | head -n 5 | awk '{print $1}'
199.72.81.55
unicomp6.unicomp.net
199.120.110.21
burger.letters.com
199.120.110.21
ユニークな行を数える
ユニーク(一意)な(サブ)ドメインやIPアドレスを数えるには、行を並べ替えて( sort
)、重複を排除し( uniq
)、その結果の行数を数えれば( wc
)よい。並べ替えの際には全ての行がメモリにロードされる点に注意しよう。
$ gunzip -c NASA_access_log_Jul95.gz | awk '{print $1}' | sort | uniq | wc -l
81983
行をフィルタリングする( grep
)
テキストファイルから正規表現にマッチする行をフィルタリングするのは非常によくあるオペレーションだ。これは、 grep
とその変化形で実現できる。ソースIPがあるリクエストだけを見たいとしよう。
$ gunzip -c NASA_access_log_Jul95.gz | egrep '^\d+\.\d+\.\d+\.\d+' | head -n 5
199.72.81.55 - - [01/Jul/1995:00:00:01 -0400] "GET /history/apollo/ HTTP/1.0" 200 6245
199.120.110.21 - - [01/Jul/1995:00:00:09 -0400] "GET /shuttle/missions/sts-73/mission-sts-73.html HTTP/1.0" 200 4085
199.120.110.21 - - [01/Jul/1995:00:00:11 -0400] "GET /shuttle/missions/sts-73/sts-73-patch-small.gif HTTP/1.0" 200 4179
205.212.115.106 - - [01/Jul/1995:00:00:12 -0400] "GET /shuttle/countdown/countdown.html HTTP/1.0" 200 3985
129.94.144.152 - - [01/Jul/1995:00:00:13 -0400] "GET / HTTP/1.0" 200 7074
$ gunzip -c NASA_access_log_Jul95.gz | egrep '^\d+\.\d+\.\d+\.\d+' | wc -l
419797
指定のパターンを除外したい場合は、単純に -v
オプションを付けよう。
$ gunzip -c NASA_access_log_Jul95.gz | egrep -v '^\d+\.\d+\.\d+\.\d+' | head -n 5
unicomp6.unicomp.net - - [01/Jul/1995:00:00:06 -0400] "GET /shuttle/countdown/ HTTP/1.0" 200 3985
burger.letters.com - - [01/Jul/1995:00:00:11 -0400] "GET /shuttle/countdown/liftoff.html HTTP/1.0" 304 0
burger.letters.com - - [01/Jul/1995:00:00:12 -0400] "GET /images/NASA-logosmall.gif HTTP/1.0" 304 0
burger.letters.com - - [01/Jul/1995:00:00:12 -0400] "GET /shuttle/countdown/video/livevideo.gif HTTP/1.0" 200 0
d104.aa.net - - [01/Jul/1995:00:00:13 -0400] "GET /shuttle/countdown/ HTTP/1.0" 200 3985
$ gunzip -c NASA_access_log_Jul95.gz | egrep -v '^\d+\.\d+\.\d+\.\d+' | wc -l
1471918
データを抽出する( shuf
head
)
もうひとつ、ファイルからランダムに行を抽出するというのもよくあるタスクだ。データがメモリに収まるなら、行をシャッフルするのに shuf
を使い、その一部を head
で取り出せる。OS Xでは、 shuf
は coreutils
をインストールすれば使える。homebrewを使っているなら、 brew install coreutils
でよい。デフォルトでは、前にインストールされたバージョンとの重複を避けるためにツール名の最初に「g」がついた状態でインストールされることに注意しよう。つまり、 shuf
は gshuf
として使えるようになる。
$ gunzip -c NASA_access_log_Jul95.gz | gshuf | head -n 5
rs710.gsfc.nasa.gov - - [24/Jul/1995:15:32:01 -0400] "GET /images/launch-logo.gif HTTP/1.0" 200 1713
annex-065.gower.net - - [21/Jul/1995:23:37:43 -0400] "GET /images/ HTTP/1.0" 200 17688
cevennes.jpl.nasa.gov - - [23/Jul/1995:16:03:57 -0400] "GET /images/vab-small.gif HTTP/1.0" 200 35709
eoi18.eda.mke.ab.com - - [05/Jul/1995:09:08:35 -0400] "GET /shuttle/countdown/countdown.html HTTP/1.0" 200 3985
131.156.47.24 - - [05/Jul/1995:10:13:50 -0400] "GET /shuttle/missions/sts-71/mission-sts-71.html HTTP/1.0" 200 8192
CSVファイルを操作する( csvtool
)
CSV(comma-separated values)ファイルをコマンドラインから操作するのに一番簡単なのは column -s, -t file.csv
だが、値が含まれなかったり、値自体にコンマが含まれているような場合にはややこしくなる。CSVファイルを扱うのにデザインされたツールはたくさんあるが、ここでは csvtool
を紹介しよう。
DebianベースのLinuxディストリビューションでは、 csvtool
は sudo apt-get install csvtool
でインストールできる。OS Xでインストールした状態にするのは少々骨が折れるが、努力の価値はある。このツールはOCamlで書かれているので、まずはこれをインストールする必要がある。Homebrewでなら、OCamlのパッケージマネージャOPAMをインストールすれば、依存するOCamlがインストールされる。関連するパッケージをインストールするのにもOPAMを使えばよい。
$ brew install opam
...
$ opam install csv
...
$ sudo ln -s ~/.opam/system/bin/csvtool /usr/local/bin/
$ csvtool --help | head -n 6
csvtool - Copyright (C) 2005-2006 Richard W.M. Jones, Merjis Ltd.
csvtool is a tool for performing manipulations on CSV files from shell scripts.
Summary:
csvtool [-options] command [command-args] input.csv [input2.csv [...]]
インストールはこれでやっつけたので、サンプルのCSVデータをダウンロードしよう。イギリス内閣府が配布している、高級官僚の高所得者給料一覧だ。
$ wget https://www.gov.uk/government/uploads/system/uploads/attachment_data/file/83716/high-earners-pay-2012.csv
$ wc -l high-earners-pay-2012.csv
259 high-earners-pay-2012.csv
$ head -n1 high-earners-pay-2012.csv
Post Unique Reference,Surname,Forename(s),Grade Equivalent,Job Title,Job/Team Function,Parent Department,Organisation,Total Pay Floor (£),Total Pay Ceiling (£),Change from 2011,Notes,Contact Email
上を見ると、このファイルには258行と、カラム名が含まれたヘッダが1行あるのがわかる。タブを区切り文字として、カラムの一部(job title, organisation, total pay floor, total pay ceiling)を取り出したいとしよう。
$ csvtool -u TAB col 5,8-10 high-earners-pay-2012.csv | head -n 5
Job Title Organisation Total Pay Floor (£) Total Pay Ceiling (£)
Director Serious Fraud Office 165000 169999
Non-Executive Director Defence Board and Chair Audit Committee Ministry of Defence 30000 34999
Chairman Olympic Delivery Authority 250000 254999
HM Inspector of Constabulary Northern Region HM Inspectorate of Constabulary 185000 189999
賃金の下限(total pay floor)で降順に並べ替えて、その上位のレコードを確認しよう。まずはヘッダの行を削除して、ファイルの代わりに stdin
(標準入力)から読み込むよう -
を指定した csvtool
にパイプで渡す。それから、3番目のカラムを元に降順に行を並べ替え、さらに表示を整えるために csvtool
にパイプで渡せばよい。
$ csvtool drop 1 high-earners-pay-2012.csv | csvtool -u TAB col 5,8-10 - | sort -t$'\t' -k3rn | head -n 4 | csvtool -t TAB readable -
Chief Executive Olympic Delivery Authority 310000 314999
Chief Executive Office of Fair Trading 275000 279999
Chief Executive Officer Nuclear Decommissioning Authority 265000 269999
NHS Chief Executive Department of Health 265000 269999
JSONフォーマットのデータを操作する( jq
)
最後に一番重要なこととして、JSONフォーマットのデータを操作するのに素晴らしく便利なツールであるjqについて書きたい。バイナリはダウンロードページから入手できる。OS Xでは、Homebrewを使って brew install jq
でもインストールできる。
forecast.ioから、現在のロンドンの天気予報データをダウンロードしよう。
$ curl "https://api.forecast.io/forecast/$API_KEY/51.51121389999999,0.11982439999997041" > forecast.json
$ wc forecast.json
0 142 25804 forecast.json
なんと1行で巨大なレスポンスが返ってきた。 jq
できれいにフォーマットできる。
$ cat forecast.json | jq . | head
{
"flags": {
"units": "us",
"darksky-stations": [
"uk_london"
],
"datapoint-stations": [
"uk-324164",
"uk-350286",
"uk-351142",
JSONオブジェクトに含まれるキーを全て出してみよう。
$ cat forecast.json | jq 'keys'
[
"currently",
"daily",
"flags",
"hourly",
"latitude",
"longitude",
"minutely",
"offset",
"timezone"
]
現在の天気をフィルターしてみる。
$ cat forecast.json | jq '.currently'
{
"ozone": 311.54,
"temperature": 42.65,
"precipProbability": 0,
"precipIntensity": 0,
"nearestStormBearing": 191,
"nearestStormDistance": 176,
"icon": "wind",
"summary": "Breezy",
"time": 1390689251,
"apparentTemperature": 34.98,
"dewPoint": 35.04,
"humidity": 0.74,
"windSpeed": 15.9,
"windBearing": 286,
"visibility": 10,
"cloudCover": 0,
"pressure": 1013.82
}
jq
には何ができるのかをほんの少し見てみた。この他にもたくさんある素晴らしい機能については、 jq
の豊富なドキュメントを参照して欲しい。
追記 : @jeroenhjanssenのブログ7 command-line tools for data scienceもチェックするのを忘れないように。ここに挙げたツールの他にも、より高度なものについても書かれている。もうすぐ発売される「Data Science at the Command Line」という彼の本にも注目だ。