Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

PerlによるCSVファイルの高速集計

CSVを自在に扱って、業務を効率化しよう

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2007/02/16 00:00

エンジニアにとって、データの編集や集計の作業は、プログラムの開発と同じくらい頻繁に発生する作業です。その中でもCSVファイルを触らねばならない機会は、いまだに多いのではないでしょうか? ここでは、その厄介なCSVファイルと上手に付き合うノウハウを紹介します。

目次

はじめに

 Perlと言えば、いまだにCGIを思い浮かべる人は多いと思います。しかし、Perlは決してそれだけの言語ではなく、その言語仕様はテキストファイルを処理し、集計結果をレポートするのに非常に向いています。特によく利用されるテキストファイルとして、CSV形式が挙げられます。CSVを集計したい場合、Excelに読み込ませて集計関数やマクロを駆使しているという人も多いかと思いますが、Perlを利用することで、高度な集計作業を簡単かつ高速にできます。

 本稿では、筆者がPerlでCSV集計を行う際によく使うノウハウを紹介したいと思います。

対象読者

  • まだ、Perl=CGIと思っている方。
  • 65,536件を超える大量のCSVデータを前に、手も足も出なくなっている方。

必要な環境

  • テキストエディタ。
  • Perl 5.8.X。ただし、ほとんどのコードはそれ以下のバージョンでも動きます。

Perlのインストール

 Windowsユーザーの方は、ActiveStateのサイトからActivePerlの最新版をダウンロードし、インストールしてください。ここではCドライブに「usr」というフォルダを作り、そこにインストールしてください。Mac OS X、UNIX/Linux系の方は、ほとんどの場合デフォルトでインストールされています。

サンプルデータ

 実際の動作を確認できるように、サンプルデータを用意しました。Windows環境で試すときは「サンプルデータ(Windows用:Shift-JIS、CRLF)」、Unix環境で試すときは「サンプルデータ(Unix用:UTF-8、LF)」を、それぞれダウンロードしてください。

条件にマッチする行数を数える

 まずは基本形として、CSVファイルの読み込み処理をPerlで記述してみます。ですが、ただの読み込みでは実用的でないので、「条件にあてはまる行が何行存在するのか」を数えるようにしてみます。

 次のような「customer_data.csv」ファイルがあるものとします。

customer_data.csv
02547,佐藤大輔,25,北海道,苫小牧市
15983,田中久志,19,沖縄県,那覇市
00893,本間雅洋,29,神奈川県,横浜市
 :
 :(以下、100,000件)
 :

 「customer_data.csv」は、「顧客ID」「氏名」「年齢」「都道府県」「市区」の5つのカラムを含むカンマ区切りのファイルであり、100,000件のデータを含んでいます。ここで、100,000件という前提条件が重要になります。なぜなら、コンピュータでデータ処理をする場合、メモリの使用量はパフォーマンスに重大な影響を与えるからです。このフォーマットの文書が、UTF-8で100,000件書かれていた場合、想定されるファイル容量は約4MBです。最近のPCのメモリ事情を考えれば、この程度の量であればすべてをメモリにのせてもまったく問題がありません。筆者の感覚ですと、データが100万件以内であれば、すべてメモリにのせて処理できると思っています。よって、以降はメモリのことについて深く考えずにスクリプトを書くこととします。

 では、これらのデータの中に、年齢が20代の人が何人含まれるているのかを、Perlを使って数えてみます。Perlは、テキストエディタでプログラムを記述し、DOSプロンプトやシェル内からコマンドで起動することができます。また、Windowsの場合は、perlスクリプトと「perl.exe」が拡張子.plで紐づけられるため、ダブルクリックで実行することもできます。ただし、ダブルクリックによる実行は、実行結果のウィンドウがすぐに閉じてしまうため、スクリプトにエラーがあった場合に追跡が困難になります。慣れるまでは、DOSプロンプトから実行する方が良いでしょう。

 では、早速テキストエディタを立ち上げ、次のようにスクリプトを書きます。スクリプトは「customer_data.csv」と同じディレクトリに「count.pl」という名称で保存してください。

count.plの骨組み
open(IN, 'customer_data.csv');
while(<IN>){
    chomp;
    my @d = split(/,/, $_);
    # ------------------------
    # ここに、集計処理を書く
    # ------------------------
}
close(IN);

 これが、PerlでCSVを扱う場合の基本形となります。最初にopen()で、ファイルを開きます。次のwhile(<IN>) { ... }は、開いたファイルを1行ずつ繰り返し処理することを意味します。Perlでは引き数を省略した場合は$_が暗黙的に使われることになっているので、おのおのの行の内容は$_に保持されています。chompは、末尾の改行コードを取り除く関数です。ここでも引き数を省略し、$_に対して処理させています。splitは文字列を分解する関数です。引き数にカンマを渡し、カンマで文字列を分解して@dという配列に代入しています。Perlの文法では、配列変数には先頭に@、その個々の要素にアクセスする場合には先頭に$をつけて、大括弧[]で添字を指定します。

 例えば1行目の処理であれば、@dには次のような内容が入っています。

行をsplitした結果
$d[0] => 02547
$d[1] => 佐藤大輔
$d[2] => 25
$d[3] => 北海道
$d[4] => 苫小牧市

 後は、集計処理を書けば完成します。20代であればカウンタを1追加する処理を記述し、最後にカウンタの内容をプリントさせます。スクリプトは次のようになりました。ステップ数で言えば10行以下です。

count.plの完成
my $count = 0;

open(IN, 'customer_data.csv');
while(<IN>){
    chomp;
    my @d = split(/,/, $_);

    # 20~29歳ならカウントアップ
    if(20 <= $d[2] && $d[2] <= 29){
          $count++;
    }
}
close(IN);

# 結果を表示
print $count, "\n";

 では、これを実行します。DOSプロンプト(又はシェル)を開き、まずは「customer_data.csv」と「count.pl」の置いてあるディレクトリに移動します。GUIのある環境であれば、スクリプトのアイコンをプロンプトにドラッグすると、パスを手で打つ手間がなく楽です。ファイル名を消して、cdしてください。

DOSプロンプト
> cd D:\csvdata\

 後はスクリプトを実行するだけです。perlコマンドの後にスクリプト名を指定します。CSVファイルの名前はスクリプト内に書かれているので必要がありません。

DOSプロンプト
> perl count.pl
36457

 スクリプトは一瞬~数秒で終わるはずです。20代の人は36,457人いるようです。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • hiratara(ヒラタラ)

    1977年に苫小牧市で生まれる。北海道大学理学部数学科卒。小学生の頃、両親に買い与えられたMZ-2500でプログラミングを始めた。学生時代、CGIの自作に没頭し、それ以降WEB開発の魅力に憑かれる。社会人になっても数学好きは変わらず、専門書を買い集めるのが最近の趣味。 id:hirataraに...

バックナンバー

連載:PerlによるCSVファイルの高速集計
All contents copyright © 2005-2018 Shoeisha Co., Ltd. All rights reserved. ver.1.5