xsv について
xsv は高性能の CSV 処理ツールで、インデックス、スライシング、結合、統計分析機能を提供します。Rust で記述されており、大規模 CSV ファイルの効率的な処理を実現します。
主な機能
- 01CSV ファイル内の列と行をインデックス・検索する
- 02カウント、合計、平均などの統計情報を計算する
- 03複数の CSV ファイルを結合・連結・変換する
活用シーン
- 01データワークフローで CSV ファイルを効率的に処理するコーディングエージェント
- 02ログ、設定、データエクスポートファイルを分析・変換する開発者
インストール
OS またはパッケージマネージャーを選び、コマンドをターミナルで実行します。
インストール後にxsv --versionを実行して確認します。
コマンド例
よく使うコマンドを使う順に並べています。
詳細
xsv は現在メンテナンスされていません
xsv の代わりに、
qsv
または
xan
をおすすめします。
xsv は、CSV ファイルのインデックス作成、行の抽出、分析、分割、結合を行うコマンドラインプログラムです。各コマンドはシンプルで、高速かつ組み合わせやすいことを目指しています。
- 簡単なタスクは、簡単に実行できるべきです。
- パフォーマンス上のトレードオフは、CLI インターフェイスで明示されるべきです。
- パフォーマンスを犠牲にして、コマンドの組み合わせやすさを実現してはなりません。
この README では、いくつかのコマンドの簡単な紹介に加えて、
xsv のインストール方法を説明しています。
MIT または UNLICENSE のデュアルライセンスです。
利用可能なコマンド
- cat - CSV ファイルを行または列単位で連結します。
- count - CSV ファイルの行数を数えます(インデックスがあれば瞬時に完了します)。
- fixlengths - レコードのパディングまたは切り詰めによって、CSV ファイルの各レコードの長さをそろえます。
- flatten - CSV レコードをフラット化して表示します。レコードを1つずつ確認するのに便利です。例:
xsv slice -i 5 data.csv | xsv flatten。 - fmt - 区切り文字、レコード終端文字、引用符のルールを変更して CSV データを再フォーマットします(ASCII 区切りデータに対応しています)。
- frequency - CSV データの各列の度数表を作成します(インデックスがある場合、並列処理によって高速化します)。
- headers - CSV データのヘッダーを表示します。または、複数の CSV ファイルに共通するすべてのヘッダーを表示します。
- index - CSV ファイルのインデックスを作成します。非常に高速で、CSV ファイルを定数時間でインデックス参照できます。
- input - 特殊な引用符やエスケープのルールを使って CSV データを読み込みます。
- join - 内部結合、外部結合、クロス結合を行います。シンプルなハッシュインデックスを使って高速に処理します。
- partition - 列の値に基づいて CSV データを分割します。
- sample - リザーバーサンプリングを使って、CSV データから行をランダムに抽出します(つまり、サンプルのサイズに比例するメモリを使用します)。
- reverse - CSV データの行の順序を逆にします。
- search - CSV データに正規表現を適用します。各フィールドに個別に正規表現を適用し、一致した行のみを表示します。
- select - CSV データから列を選択、または並べ替えます。
- slice - CSV ファイルの任意の部分から行を抽出します。インデックスがある場合は、スライスの開始位置より前のすべての行ではなく、スライス内の行のみを解析します。
- sort - CSV データを並べ替えます。
- split - 1つの CSV ファイルを N 個のチャンクからなる複数の CSV ファイルに分割します。
- stats - CSV ファイルの各列の基本的な型と統計情報を表示します(平均、標準偏差、中央値、範囲など)。
- table - elastic tabstops を使って、あらゆる CSV データを整列して表示します。
ざっと見てみましょう
Data Science Toolkitのデータを使ってみることにしましょう。このデータには複数の CSV ファイルが含まれています。たとえば、世界各都市の人口に関心があるとします。データを取得して、調べ始めてみましょう。
$ curl -LO https://burntsushi.net/stuff/worldcitiespop.csv
$ xsv headers worldcitiespop.csv
1 Country
2 City
3 AccentCity
4 Region
5 Population
6 Latitude
7 Longitude
次に、各列にどのようなデータが含まれているか、概要を確認したくなるかもしれません。stats コマンドを使えば確認できます。
$ xsv stats worldcitiespop.csv --everything | xsv table
field type min max min_length max_length mean stddev median mode cardinality
Country Unicode ad zw 2 2 cn 234
City Unicode bab el ahmar Þykkvibaer 1 91 san jose 2351892
AccentCity Unicode Bâb el Ahmar ïn Bou Chella 1 91 San Antonio 2375760
Region Unicode 00 Z9 0 2 13 04 397
Population Integer 7 31480498 0 8 47719.570634 302885.559204 10779 28754
Latitude Float -54.933333 82.483333 1 12 27.188166 21.952614 32.497222 51.15 1038349
Longitude Float -179.983333 180 1 14 37.08886 63.22301 35.28 23.8 1167162
xsv table コマンドは、CSV データを受け取り、elastic tabstopsを使って列を揃えて表示します。Unicode 文字でも正しく揃うことがわかります。
このコマンドは私のマシンでは実行に約 12 秒かかりますが、インデックスを作成してからコマンドを再実行すれば高速化できます。
$ xsv index worldcitiespop.csv
$ xsv stats worldcitiespop.csv --everything | xsv table
...
これで私のマシンでは約 8 秒に短縮されます(インデックスの作成にかかる時間は 2 秒未満です)。
注目すべきことに、別のCSV コマンドラインツールキットにある同様の「統計」コマンドでは、同じデータセットから同様の統計を出力するのに約 2 分かかります。
インデックスを作成すると、統計の取得が速くなるだけではありません。スライス操作も非常に速くなります。解析が必要なのは、スライスした部分だけだからです。たとえば、最後の 10 レコードを取得したいとします。
$ xsv count worldcitiespop.csv
3173958
$ xsv slice worldcitiespop.csv -s 3173948 | xsv table
Country City AccentCity Region Population Latitude Longitude
zw zibalonkwe Zibalonkwe 06 -19.8333333 27.4666667
zw zibunkululu Zibunkululu 06 -19.6666667 27.6166667
zw ziga Ziga 06 -19.2166667 27.4833333
zw zikamanas village Zikamanas Village 00 -18.2166667 27.95
zw zimbabwe Zimbabwe 07 -20.2666667 30.9166667
zw zimre park Zimre Park 04 -17.8661111 31.2136111
zw ziyakamanas Ziyakamanas 00 -18.2166667 27.95
zw zizalisari Zizalisari 04 -17.7588889 31.0105556
zw zuzumba Zuzumba 06 -20.0333333 27.9333333
zw zvishavane Zvishavane 07 79876 -20.3333333 30.0333333
これらのコマンドは、スライスのサイズに比例する時間とメモリで実行されるため、瞬時に完了します(つまり、どれほど大きな CSV データにも対応できます)。
少し話を変えましょう。CSV データのすべての列を常に見たいとは限りません。この場合、必要なのは国、都市、人口だけかもしれません。それでは、ランダムに選んだ 10 行を見てみましょう。
$ xsv select Country,AccentCity,Population worldcitiespop.csv \
| xsv sample 10 \
| xsv table
Country AccentCity Population
cn Guankoushang
za Klipdrift
ma Ouled Hammou
fr Les Gravues
la Ban Phadèng
de Lüdenscheid 80045
qa Umm ash Shubrum
bd Panditgoan
us Appleton
ua Lukashenkivske
おっと!人口が記録されていない都市があるようです。どの程度よくあることでしょうか?
$ xsv frequency worldcitiespop.csv --limit 5
field,value,count
Country,cn,238985
Country,ru,215938
Country,id,176546
Country,us,141989
Country,ir,123872
City,san jose,328
City,san antonio,320
City,santa rosa,296
City,santa cruz,282
City,san juan,255
AccentCity,San Antonio,317
AccentCity,Santa Rosa,296
AccentCity,Santa Cruz,281
AccentCity,San Juan,254
AccentCity,San Miguel,254
Region,04,159916
Region,02,142158
Region,07,126867
Region,03,122161
Region,05,118441
Population,(NULL),3125978
Population,2310,12
Population,3097,11
Population,983,11
Population,2684,11
Latitude,51.15,777
Latitude,51.083333,772
Latitude,50.933333,769
Latitude,51.116667,769
Latitude,51.133333,767
Longitude,23.8,484
Longitude,23.2,477
Longitude,23.05,476
Longitude,25.3,474
Longitude,23.1,459
(xsv frequency コマンドは、CSV データの各列の度数表を作成します。今回は 5 秒しかかかりませんでした。)
どうやら、ほとんどの都市には人口がまったく登録されていないようです。問題ありません。人口が登録されている行だけを表示するよう、先ほどのコマンドを調整できます。
$ xsv search -s Population '[0-9]' worldcitiespop.csv \
| xsv select Country,AccentCity,Population \
| xsv sample 10 \
| xsv table
Country AccentCity Population
es Barañáin 22264
es Puerto Real 36946
at Moosburg 4602
hu Hejobaba 1949
ru Polyarnyye Zori 15092
gr Kandíla 1245
is Ólafsvík 992
hu Decs 4210
bg Sliven 94252
gb Leatherhead 43544
うーん。at はどの国でしょうか?まったくわかりませんが、Data Science Toolkit には countrynames.csv という CSV ファイルがあります。これを取得して結合すれば、どの国なのか確認できます。
curl -LO https://gist.githubusercontent.com/anonymous/063cb470e56e64e98cf1/raw/98e2589b801f6ca3ff900b01a87fbb7452eb35c7/countrynames.csv
$ xsv headers countrynames.csv
1 Abbrev
2 Country
$ xsv join --no-case Country sample.csv Abbrev countrynames.csv | xsv table
Country AccentCity Population Abbrev Country
es Barañáin 22264 ES Spain
es Puerto Real 36946 ES Spain
at Moosburg 4602 AT Austria
hu Hejobaba 1949 HU Hungary
ru Polyarnyye Zori 15092 RU Russian Federation | Russia
gr Kandíla 1245 GR Greece
is Ólafsvík 992 IS Iceland
hu Decs 4210 HU Hungary
bg Sliven 94252 BG Bulgaria
gb Leatherhead 43544 GB Great Britain | UK | England | Scotland | Wales | Northern Ireland | United Kingdom
おっと、Country という列が 2 つと、もう不要な Abbrev 列ができてしまいました。xsv select コマンドで列の順序を変えれば、簡単に修正できます。
$ xsv join --no-case Country sample.csv Abbrev countrynames.csv \
| xsv select 'Country[1],AccentCity,Population' \
| xsv table
Country AccentCity Population
Spain Barañáin 22264
Spain Puerto Real 36946
Austria Moosburg 4602
Hungary Hejobaba 1949
Russian Federation | Russia Polyarnyye Zori 15092
Greece Kandíla 1245
Iceland Ólafsvík 992
Hungary Decs 4210
Bulgaria Sliven 94252
Great Britain | UK | England | Scotland | Wales | Northern Ireland | United Kingdom Leatherhead 43544
元の CSV データに対してこれを実行することもできるでしょうか?もちろんできます。xsv の結合は高速だからです。
$ xsv join --no-case Abbrev countrynames.csv Country worldcitiespop.csv \
| xsv select '!Abbrev,Country[1]' \
> worldcitiespop_countrynames.csv
$ xsv sample 10 worldcitiespop_countrynames.csv | xsv table
Country City AccentCity Region Population Latitude Longitude
Sri Lanka miriswatte Miriswatte 36 7.2333333 79.9
Romania livezile Livezile 26 1985 44.512222 22.863333
Indonesia tawainalu Tawainalu 22 -4.0225 121.9273
Russian Federation | Russia otar Otar 45 56.975278 48.305278
France le breuil-bois robert le Breuil-Bois Robert A8 48.945567 1.717026
France lissac Lissac B1 45.103094 1.464927
Albania lumalasi Lumalasi 46 40.6586111 20.7363889
China motzushih Motzushih 11 27.65 111.966667
Russian Federation | Russia svakino Svakino 69 55.60211 34.559785
Romania tirgu pancesti Tirgu Pancesti 38 46.216667 27.1
!Abbrev,Country[1] という構文は、「Abbrev 列を削除し、Country 列の 2 つ目の出現箇所を削除する」という意味です。最初に countrynames.csv と結合したので、最初の Country 名(完全な名前)が CSV データに含まれています。
この xsv join コマンドは、私のマシンでは約 7 秒かかります。高速なのは、指定した CSV データファイルの 1 つに非常にシンプルなハッシュインデックスを作成するためです。join コマンドはデフォルトで内部結合を行いますが、左外部結合、右外部結合、完全外部結合にも対応しています。
インストール
Windows、Linux、macOS 用のバイナリはGithubから入手できます。
macOS Homebrew ユーザーの場合は、homebrew-core から xsv をインストールできます。
$ brew install xsv
macOS MacPorts ユーザーの場合は、公式ポートから xsv をインストールできます。
$ sudo port install xsv
Nix/NixOS ユーザーの場合は、nixpkgs から xsv をインストールできます。
$ nix-env -i xsv
または、Cargo(Rust のパッケージマネージャー)をインストールし、Cargo を使って xsv をインストールすれば、ソースからコンパイルできます。
cargo install xsv
このリポジトリからコンパイルする場合も、同様の手順で行えます。
git clone git://github.com/BurntSushi/xsv
cd xsv
cargo build --release
コンパイルには、お使いのマシンによって数分かかることがあります。バイナリは ./target/release/xsv に生成されます。
ベンチマーク
さまざまな xsv コマンドのおおまかなベンチマークをいくつか作成しました。
開発の動機
このプロジェクトには、次のような妥当な批判がいくつかあります。
- CSV はひどい形式なので、CSV データを扱うべきではありません。
- データがギガバイト単位なら、CSV は適切なストレージ形式ではありません。
- さまざまな SQL データベースでは、より高度なインデックス機能を備えながら、
xsvで利用できるすべての操作を実行できます。しかも、パフォーマンスは何億倍も優れています。
ほかにも批判はあると思いますが、このプロジェクトのきっかけは、私に渡された 40GB の CSV ファイルでした。その中のデータの構造を把握し、既存のシステムに統合する方法を考えるよう依頼されたのです。そのとき、私が知っている CSV ツールはどれもまったく不十分だと気づきました。処理が遅すぎるか、柔軟性が足りなかったのです。(別のプロジェクトでは、数十個の CSV ファイルを扱っていました。それぞれは 40GB より小さいものの、同じ種類のデータを表すはずでした。しかし、列の構成が異なり、列名も直感的ではありませんでした。ここでは便利な CSV 検査ツールが不可欠であり、しかも十分な速さが必要でした。)
作業に役立った重要な機能は、インデックス作成、ランダムサンプリング、検索、スライス、列の選択でした。こうした機能がすべて、40GB の CSV データ(または数十個の CSV ファイル)を少し扱いやすくしてくれました。
一度でも巨大な CSV ファイルを渡されれば、私がこの探求に乗り出すには十分でした。他の人たちとの会話からすると、これほど大きな CSV データファイルは珍しくないようです。ですから、これほど大きなデータを扱える可能性のあるツールには、存在意義があると考えています。
名前の重複
このプロジェクトは、同じ名前を持つ、よく似た別のプロジェクトとは無関係です。 https://mj.ucw.cz/sw/xsv/