本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーは、デジタルガレージにてデータ分析のお仕事をしている下野寿之さんで、テーマは「表形式データを操るUNIXシェル型Perl製コマンド群」です。各コマンドの実体はPerlで書かれた単体で動くプログラムで、単独または既存のコマンドと組み合わせて実行します。
本稿のサンプルコードは、WEB+DB PRESS Vol.124のサポートサイトから入手できます。
データ分析の難しさ
ビッグデータやデータサイエンスという言葉がよく使われ始めて何年も経ちますが、企業に蓄積されたPOSや人事などのデータを存分に活用するのは、まだいろいろと厳しいのが現実です。
データには不具合がある
現場のデータには、次のような不具合が多数あります[1]。
- (a)不要なデータの混入[2]
- (b)仕様書未記載かつ担当者も知らない特別値[3]
- (c)データの欠損[4]
- (d)ある列で特定の値が不自然に頻発[5]
- (e)複数の表データ間での不整合[6]
そのため、不具合を簡潔に調べる手段が必要です。
使用するデータの選定が難しい
次の理由により、多数のデータからどの部分を本格的な分析に使うかを決める手間も、際限なく増えがちです。
- (f)各列の値(符号や略語や特別値)の意味が不明
- (g)1枚の表が持つ列数が過多[7]
- (h)1枚の表に酷似した列が複数[8]
- (i)異なる表に同じ意味の列が過多[9]
- (j)提供された表の枚数が過多[10]
そのため、分析に使う可能性のある表と列を網羅的に簡潔に調べる手段が必要です。
既存ソフトウェアの問題点
UNIX系コマンドや、Pythonライブラリのcsvkitやpandas_profiling、R言語、既存の商用ソフトウェアでは、(a)~(j)の10項目への対処は困難です。(a)~(e)の実務データの不具合への対処は、初歩的には可能でも全貌の把握は困難です。教科書的な基礎統計量(平均や最大、最小など)を算出するユーティリティは多いですが、ありがちな特別値(-1
や999
や空欄など)を含む符号化された文字列データを解読するには、アドホックな操作が必要で汎用性に難があります。(f)~(j)の使用するデータの選定も、目的に見合った容易さではプログラミングできません。たとえば、全3列のデータに対して2列目を末尾(右端)に移動したい場合[11]はAWKでawk '{print $1,$3,$2}'
と書けばよいものの、12列もある場合は、12列分をコマンドラインに入力するか、for
文を使ったプログラミングを行う必要があります。これらは1回ではなかなか正しく書けないため、デバッグ作業が発生して本来の分析目的に集中しづらくなり、(f)(g)(h)で起こる問題の解決を遠ざけます。(i)(j)はなおさら難しいです。
表形式データを扱う新しいPerl製コマンド群
上記の現状を打破すべく、UNIXコマンドとして動くプログラムをPerlで作り、CPANモジュール化しました。本稿ではそのうちの8個を紹介します。
Perl製コマンドのメリット
(a)~(j)に対処するプログラムの動作は、CPUリソースよりもデータ記憶装置からの読み取り速度が律速する場合が多いです。そのため、C++言語などを採用する必然性は低く、スクリプト言語の中で、文字列処理、多次元配列や多次元ハッシュなどの構文が書きやすいPerlを採用しました[12]。Perlは後方互換性が高いので、今作ったプログラムが50年後も使える見込みが高いのも理由です。
インストール方法
本稿で使う各コマンドは、App::
を前置したモジュール名を指定してインストールします[13]。
これらのコマンドは、Perl 5.14(2011年5月リリース)以降で動作します[14]。本稿の各コマンドの動作は、Perl 5.18.4とPerl 5.32.1で確認しました。
コマンドの共通オプション
各コマンドには、そのコマンド独自のオプションのほかに、コマンド間で共通するオプションがあります。たとえば-jは、出力を日本語表記にすることを指定するためのものです。-~
は、何かの機能を反転するときに使います。
いくつかのオプションは、パラメータを持ちます。-m0
など0
を伴う場合の多くは、何かの機能の抑制の指定です。-i
は、タブ文字以外への入力の列区切り文字の指定です。-g
は、何かの抽出指定数の指定です。
各コマンドのマニュアルは、各コマンドに--help
を付与して実行すると表示されます。
扱うデータはTSV形式
多くのデータは表形式で、SQLのテーブルのように行(レコード)と列(属性)からなります[15]。表形式のデータはCSV(Comma-Separated Values、カンマ区切り)形式が多いですが、本稿ではCSVの亜種であるTSV(Tab-Separated Values、タブ区切り)形式のデータを処理します。CSV形式は引用符囲みやエスケープ文字の処理がやっかいなためです。
自由に使えるTSVファイルとしては、国立国会図書館のオープンデータセットなどがあります。
CSV形式からの変換 ──csv2tsv
CSV形式のファイルをTSV形式に変換する場合は、csv2tsv
を使います[16]。
自在な列操作 ──csel
便利さに長年の定評があるAWKをさらに便利にすべく、csel
を作りました。たとえば、csel -p3..7
により、3~7列目だけを出力します。
列を縦ぞろえで表示 ──expandtab
表形式のデータは、less
で中身を見ても、同じ列が縦にそろわず画面で読みにくい場合があります。その場合はexpandtab
を使います。expandtab
は、全列が縦にそろうように、各列の最も幅の広い文字列に合わせて各値の右側に半角空白を補填します。
次の例では、Amazon Linuxのパスワードファイル/etc/passwd
に対して実行しています。
実行結果は図1です。
ファイルがタブ区切りではない場合は、-i
オプションで区切り文字を指定します。ここでは/etc/passwd
の区切り文字である:を指定しました。
数値パラメータ付きの-s
オプションにより、できるだけ多くの列の先頭を縦にそろえつつ、出力表の横幅を縮めることができます[17]。
<続きの(2)はこちら。>
- 特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現!
- 特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう
- 特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、NFT