ちょっと前にこんな話が話題になりました。
内閣府が国民の休日をCSVファイルとして公開しているのですが、 旧来は
https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv
として公開していたものを特に事前告知することなく次のように変更してしまったのです。
https://www8.cao.go.jp/chosei/shukujitsu/shukujitsu.csv
syukujitsu
がshukujitsu
に変わっています。その割にディレクトリーはshukujitsu
なので、今回アップデートされた名前のほうが正しいのです。
このデータをダウンロードして使っているだけであれば、前の手順でダウンロードしようとしたときに404とかが返ってきて?って思うだけなのですが、なにかのソフトウェア(例えばスケジューラーアプリ)で使っていた場合は、もともと指定していたURLが404になるのでファイル名変更によりエラーを起こしたり、最新の情報に更新されたりするなどのトラブルが起こることが考えられました。
おそらくtypoしたまま公開しているのは嫌だなと担当者が思ったのか、もしくは特にそのような意図はなく、ディレクトリ名と同じファイルで新しいデータとして登録してしまったと思われます。
色々あって、現在はもとのURLに戻っています。変えて以前のURLを廃止にするのではなくて、リダイレクトすればよかったですね。
内閣府より、お詫びと祝日データファイルのURLを元に戻すとのご連絡をいただきました。 https://t.co/1ek9HaH6RC
— 河野太郎 (@konotarogomame) 2023年2月3日
このデータが掲載されているページはこちらで、CSVファイルもここから入手できます。
CSVkitとは
さて、話を戻して今回取り上げるCSVkitは、CSV形式のデータを色々CLIで弄くり回せるツール群です。
OSによってパッケージが公開されているものもありますが、 基本的にはPythonモジュールなので、次のようにインストールできます。
% python3 -m pip install csvkit
インストールすると、次のページで取り上げられているようなコマンドを使えるようになります。
色々あって覚えるのは大変ですが、私はcsvlook、csvcut、csvstat、csvsqlをよく使います。
CSVkitでCSVファイルをいじくり倒してみよう
まずはCSVファイルを覗いてみましょう。中身を参照するには、csvlookコマンドが簡単で便利です。
せっかくsyukujitsu.csv
の話を出したので、このファイルを例にして色々触ってみましょう。
% csvlook syukujitsu.csv Your file is not "utf-8-sig" encoded. Please specify the correct encoding with the -e flag or with the PYTHONIOENCODING environment variable. Use the -v flag to see the complete error.
おおっと...そうでした。このファイルはShift_JISでエンコーディングされているのでした。
というわけで、-e
オプションでsjis
を指定して実行します。
% csvlook -e sjis syukujitsu.csv
毎回文字コード指定が面倒であれば、nkfかiconvで文字コード変換してしまいましょう。ファイル名にハイフンをつけると後で困るので、アンダーバーにしておきましょう。なんで急にそんな事をいうかというと、自分が後で困ったからです。Windowsでは...ちょっとわからないので、WSLv2でLinux上で実行してください。Ubuntuとかならかんたんです。
% iconv -f SHIFT-JIS -t utf-8 syukujitsu.csv > syukujitsu_utf8.csv
これで文字コード指定をすることなく、CSVkitで中身を見ることができます。
% csvlook syukujitsu_utf8.csv
ただ、大容量のCSVファイルだと件数が膨大だと思いますので、--max-rows
オプションを使うことで件数を絞り込めます。
こんな感じです。結果は表形式で出てきます。
% csvlook -e sjis --max-rows 10 syukujitsu.csv | 国民の祝日・休日月日 | 国民の祝日・休日名称 | | ---------- | ---------- | | 1955-01-01 | 元日 | | 1955-01-15 | 成人の日 | | 1955-03-21 | 春分の日 | | 1955-04-29 | 天皇誕生日 | | 1955-05-03 | 憲法記念日 | | 1955-05-05 | こどもの日 | | 1955-09-24 | 秋分の日 | | 1955-11-03 | 文化の日 | | 1955-11-23 | 勤労感謝の日 | | 1956-01-01 | 元日 | | ... | ... |
CSVkitはPythonモジュールなので、次のようにPythonからデータを使って色々できるようです。
% csvpy -e sjis --agate syukujitsu.csv Welcome! "syukujitsu.csv" has been loaded in an agate.Table object named "table". >>> table.print_table() | 国民の祝日・休日月日 | 国民の祝日・休日名称 | | ---------- | ---------- | | 1955-01-01 | 元日 | | 1955-01-15 | 成人の日 | | 1955-03-21 | 春分の日 | | 1955-04-29 | 天皇誕生日 | | 1955-05-03 | 憲法記念日 | | 1955-05-05 | こどもの日 | | 1955-09-24 | 秋分の日 | | 1955-11-03 | 文化の日 | | 1955-11-23 | 勤労感謝の日 | | 1956-01-01 | 元日 | | 1956-01-15 | 成人の日 | | 1956-03-21 | 春分の日 | | 1956-04-29 | 天皇誕生日 | | 1956-05-03 | 憲法記念日 | | 1956-05-05 | こどもの日 | | 1956-09-23 | 秋分の日 | | 1956-11-03 | 文化の日 | | 1956-11-23 | 勤労感謝の日 | | 1957-01-01 | 元日 | | 1957-01-15 | 成人の日 | | ... | ... |
データの概要を知るには、csvstatというコマンドを使います。 行数は1013行で、1955年1月1日から2024年11月23日のデータが含まれていることが実行結果からわかります。
% csvstat -e sjis syukujitsu.csv 1. "国民の祝日・休日月日" Type of data: Date Contains null values: False Unique values: 1013 Smallest value: 1955-01-01 Largest value: 2024-11-23 Most common values: 1955-01-01 (1x) 1955-01-15 (1x) 1955-03-21 (1x) 1955-04-29 (1x) 1955-05-03 (1x) 2. "国民の祝日・休日名称" Type of data: Text Contains null values: False Unique values: 23 Longest value: 12 characters Most common values: 休日 (110x) 元日 (70x) 成人の日 (70x) 春分の日 (70x) 憲法記念日 (70x)
csvsqlは名前の通り、CSVのデータを対応するSQLサーバーにデータを取り込んだり、CSVファイルをソースとしてSQLコマンドでCSVファイルの中身を検索できます。
内部的にSQLAlchemyモジュールを使っているため、このコマンドを利用するには別途インストールする必要があります。 ちなみにSQLAlchemy 2.0でAPI変更があったようで、このコマンドを実行すると警告が表示されるかもしれません。
この警告は、1.4から2.0で変更されたAPIを利用している場合、コマンドを実行する毎に表示されます。回避策は.bashrcや.zshrcなどに
export SQLALCHEMY_SILENCE_UBER_WARNING=1
と書いておくことです。なお、うっかりPythonモジュールをSQLAlchemy 2.0以降にしてしまうと古いAPIが使われている限り動作しなくなる恐れがあるので、対応されるまで気をつける必要があります。
私は作業環境を作るときは次のようなrequirements.txt
を書いておいて、セットアップしています(実際のファイルは、もっと色々書いています)。
% cat ~/requirements.txt pandas pyarrow csvkit sqlalchemy<2.0 psycopg2-binary % python3 -m pip install -r requirements.txt
さて、まずは次のように実行して件数を確認してみましょう。
% csvsql -e sjis --query "SELECT COUNT(*) FROM syukujitsu" syukujitsu.csv COUNT(*) 1013
1013件と出ました。前にcsvstatコマンドを実行したときに現れた件数と一緒ですね。 それではデータから、成人の日を絞り込んでみましょう。
% csvsql -e sjis --query "SELECT * FROM syukujitsu WHERE 国民の祝日・休日名称='成人の日'" syukujitsu.csv 国民の祝日・休日月日,国民の祝日・休日名称 1955-01-15,成人の日 1956-01-15,成人の日 1957-01-15,成人の日 1958-01-15,成人の日 ... 1998-01-15,成人の日 1999-01-15,成人の日 2000-01-10,成人の日 2001-01-08,成人の日 ... 2019-01-14,成人の日 2020-01-13,成人の日 2021-01-11,成人の日 2022-01-10,成人の日 2023-01-09,成人の日 2024-01-08,成人の日
上の例は件数の都合で省略してますが、実際はすべて出力されます。 SQLコマンドを実行しましたが、結果はCSVデータのようにカンマ区切りで表示します。データベースの結果表示出力のような表形式で出力されるcsvlookやcsvpyとは結果の出方が異なります。
ところで成人の日って昔は1月15日だったイメージを筆者は持っていたのですが、2000年以降は連休になるように調整されるようになったようですね(20年以上気がついていないという...)。翌日休みじゃないと確かに辛いですからね。
さて、csvsqlはBETWEENもきちんとサポートしていますので、期間で絞り込みなどもラクにこなせます。 例えば次のような感じで、2000年の元日からおおみそかまでを表示できます。
% csvsql -e sjis --query "SELECT * FROM syukujitsu WHERE 国民の祝日・休日月日 BETWEEN '2000-01-01' AND '2000-12-31'" syukujitsu.csv 国民の祝日・休日月日,国民の祝日・休日名称 2000-01-01,元日 2000-01-10,成人の日 2000-02-11,建国記念の日 2000-03-20,春分の日 2000-04-29,みどりの日 2000-05-03,憲法記念日 2000-05-04,休日 2000-05-05,こどもの日 2000-07-20,海の日 2000-09-15,敬老の日 2000-09-23,秋分の日 2000-10-09,体育の日 2000-11-03,文化の日 2000-11-23,勤労感謝の日 2000-12-23,天皇誕生日
また、売上データが含まれるCSVファイルでは、集約関数をつかった集計も可能です。
% csvsql --query "SELECT name,okashi,price FROM katta_okashi" katta_okashi.csv name,okashi,price Alice,candy,100.0 Alice,candy,50.0 Alice,cookie,30.0 Bob,chocolate,200.0 ... % csvsql --query "SELECT sum(price) FROM katta_okashi" katta_okashi.csv sum(price) 3300.0
よく使うようなSQLコマンドはおおよそ使えそうです。
csvcutもよく使います
今回は詳しく取り上げませんが、csvcutなんかも便利です。データから不要な情報を取り除けます。こんなこともコマンド一発でできて超便利でした。 まずはCSVファイルに含まれるデータを覗いて...2,3,8,9行目が不要だったとします。
% csvcut -n abc6-formated.csv 1: 60.66.22.213 2: - 3: - 4: 09/Feb/2023:10:24:25 +0000 5: GET 6: /category/finance 7: 200 8: 76 "/category/garden" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML 9: like Gecko) Chrome/17.0.963.56 Safari/535.11"
先の判断から次のように実行すると、CSVのデータから必要ではない部分を取り除いて別のファイルとして保存できます。
% csvcut -c 1,4,5,6,7 abc6-formated.csv > abc6-formated-filtered.csv
こういう作業、以前はExcelかLibreOfficeのCalcを使っていました。マウスとキーボード操作しながらポチポチ作業をしていて、「なかなかダサいやり方をしているな」って思ったのですが、CSVkitのおかげで作業が断然ラクになりました。もう、雑にCSVファイルをExcelとかで読み込んでデータを壊すなんてこともありません(えっ?壊したことがあるのかですって?...ははは)。
編集前のと編集後のデータを比較するとこんな感じです。
$ ls -lh -rw-rw-r-- 1 ubuntu ubuntu 398M Feb 10 14:40 abc6-formated-filtered.csv -rw-rw-r-- 1 ubuntu ubuntu 1.2G Feb 10 13:44 abc6-formated.csv
今回CSVkitのいくつかをご紹介しました。ちなみに私のお気に入りはcsvcutとcsvsqlですね。 以上、今日はCSVkitについてのご紹介でした。