CSVファイルの加工について調べていたところ、Rustで書かれたCSVの集計・加工ツール『xsv』コマンドなるものがあると知ったのでちょっと触ってみた。

1.インストール

まずはインストールから。
インストールの方法は2種類あり、ひとつはコンパイル済みのバイナリをそのまま使う方法、もう一つは自分でコンパイルする方法だ。

バイナリをそのままダウンロードしてくる

バイナリをそのままダウンロードする場合、以下のようにする(念のため、こちらで最新版のURLを確認しておくことをすすめる)。

wget https://github.com/BurntSushi/xsv/releases/download/0.9.14/xsv-0.9.14-x86_64-unknown-linux-gnu.tar.gz
tar xzvf xsv-0.9.14-x86_64-unknown-linux-gnu.tar.gz
sudo sh -c 'cp xsv-0.9.14-x86_64-unknown-linux-gnu/xsv /usr/local/bin/'

コンパイルする

コンパイルを行う場合、Rustのパッケージマネージャーである『Cargo』を入れるといいようだ。
今はRustのインストールと同時に自動的に入ってくるので、以下のコマンドでRustをインストールする。

curl -s https://static.rust-lang.org/rustup.sh | sh -s

Rustインストール後、以下のコマンドでxsvをコンパイル、インストールを行う。

git clone git://github.com/BurntSushi/xsv
cd xsv
cargo build --release

2.触ってみる

無事インストールが終わったら、実際にxsvコマンドでCSVファイルをいじってみよう。
サンプル用にcsvファイルをダウンロードしてくる。

curl -LO http://burntsushi.net/stuff/worldcitiespop.csv

xsvコマンドは、サブコマンドを使ってcsvを加工するスタイルだ。
いくつかのサブコマンドを抜粋して使ってみる。

CSVのヘッダーを確認する

以下のようにコマンドを実行することで、CSVのヘッダーを確認することができる。

xsv headers ファイルPATH
blacknon@BS-PUB-UBUNTU-01:~$ head -10 worldcitiespop.csv
Country,City,AccentCity,Region,Population,Latitude,Longitude
ad,aixas,Aixas,06,,42.4833333,1.4666667
ad,aixirivali,Aixirivali,06,,42.4666667,1.5
ad,aixirivall,Aixirivall,06,,42.4666667,1.5
ad,aixirvall,Aixirvall,06,,42.4666667,1.5
ad,aixovall,Aixovall,06,,42.4666667,1.4833333
ad,andorra,Andorra,07,,42.5,1.5166667
ad,andorra la vella,Andorra la Vella,07,20430,42.5,1.5166667
ad,andorra-vieille,Andorra-Vieille,07,,42.5,1.5166667
ad,andorre,Andorre,07,,42.5,1.5166667
blacknon@BS-PUB-UBUNTU-01:~$ xsv headers worldcitiespop.csv
1   Country
2   City
3   AccentCity
4   Region
5   Population
6   Latitude
7   Longitude

CSVの行数を取得する

CSVの行数を取得する場合は、以下のようにする。
wcの結果と比べて一行少ないのは、ヘッダーを含めないからだ。

xsv count ファイルPATH
blacknon@BS-PUB-UBUNTU-01:~$ wc worldcitiespop.csv
  3173959   5681543 151488712 worldcitiespop.csv
blacknon@BS-PUB-UBUNTU-01:~$ wc -l worldcitiespop.csv
3173959 worldcitiespop.csv
blacknon@BS-PUB-UBUNTU-01:~$ xsv count worldcitiespop.csv
3173958

コンソール上で読みやすいようにテーブル状にする

「table」サブコマンドを使うことで、コンソール上で読みやすいようにテーブル上に出力させることができる。

xsv table ファイルPATH
blacknon@BS-PUB-UBUNTU-01:~$ cat /tmp/test.csv
id,user,value
1,aaa,1223
2,bbb,3333
3,ccc,855
4,ddd,998
5,eee,24354
6,fff,345
7,ggg,325
8,hhh,22
9,iii,4657
10,jjj,896
blacknon@BS-PUB-UBUNTU-01:~$ xsv table /tmp/test.csv
id  user  value
1   aaa   1223
2   bbb   3333
3   ccc   855
4   ddd   998
5   eee   24354
6   fff   345
7   ggg   325
8   hhh   22
9   iii   4657
10  jjj   896

指定された行数をランダムでサンプリング抽出する

サブコマンド「sample」で、既存のCSVファイルからランダムに行を抽出させることもできる。

xsv sample 抽出する行数 ファイルPATH
blacknon@BS-PUB-UBUNTU-01:~$ xsv sample 10 worldcitiespop.csv | xsv table
Country  City                        AccentCity                  Region  Population  Latitude    Longitude
ir       band-i-kariz                Band-i-Kariz                42                  35.504858   58.211005
nl       keup                        Keup                        05                  51.310603   5.985442
co       gallinazo                   Gallinazo                   35                  9.318912    -74.915084
al       hendek i goges              Hendek i Goges              48                  41.6402778  19.6458333
mx       la puerta de agua caliente  La Puerta de Agua Caliente  11                  20.224167   -101.681111
br       cunha                       Cunha                       15                  -20.333333  -42.966667
cn       wulihotzutsun               Wulihotzutsun               05                  43.459722   126.483333
lv       riebiki                     Riebiki                     29                  57.0166667  22.7833333
id       tjihandjawar                Tjihandjawar                30                  -7.0347     107.3194
eg       at tall al kafr al gharbi   At Tall al Kafr al Gharbi   07                  30.5563889  31.7786111

CSVファイルのインデックスを作成する

サイズの大きいCSVファイルを取り扱う場合、処理の前にインデックスを作成しておくことができる。

xsv index ファイルPATH
blacknon@BS-PUB-UBUNTU-01:~$ time xsv count worldcitiespop.csv
3173958

real    0m1.386s
user    0m1.280s
sys     0m0.096s
blacknon@BS-PUB-UBUNTU-01:~$ xsv index worldcitiespop.csv
blacknon@BS-PUB-UBUNTU-01:~$ time xsv count worldcitiespop.csv
3173958

real    0m0.039s
user    0m0.032s
sys     0m0.004s

CSVファイル全体の統計分析を行う

CSVファイル全体の統計分析を行う場合、サブコマンド「stats」を使うとよいだろう。

xsv stats ファイルPATH # CSV全体での統計
xsv stats -s カラム名 ファイルPATH # 特定のカラムを指定して統計
xsv stats --cardinality ファイルPATH # カーディナリティも出力する
blacknon@BS-PUB-UBUNTU-01:~$ xsv stats worldcitiespop.csv | xsv table
field       type     min            max            min_length  max_length  mean                stddev
Country     Unicode  ad             zw             2           2
City        Unicode   bab el ahmar  Tykkvibaer     1           91
AccentCity  Unicode   Bab el Ahmar  in Bou Chella  1           91
Region      Unicode  00             Z9             0           2
Population  Integer  7              31480498       0           8           47719.570633597104  302885.55920403753
Latitude    Float    -54.933333     82.483333      1           12          27.188165808469346  21.952613849125445
Longitude   Float    -179.9833333   180            1           14          37.08885989656549   63.22301045924227
blacknon@BS-PUB-UBUNTU-01:~$ xsv stats -s Population worldcitiespop.csv | xsv table
field       type     min  max       min_length  max_length  mean                stddev
Population  Integer  7    31480498  0           8           47719.570633597104  302885.55920403753
blacknon@BS-PUB-UBUNTU-01:~$ xsv stats -s Population --cardinality worldcitiespop.csv | xsv table
field       type     min  max       min_length  max_length  mean                stddev              cardinality
Population  Integer  7    31480498  0           8           47719.570633597104  302885.55920403753  28754

CSVから特定の列のみ表示させる

CSVファイルから特定の列だけを抜き出す場合は、「select」で列名を指定してやればよい。

xsv select 列名1,列名2,... ファイルPATH
blacknon@BS-PUB-UBUNTU-01:~$ head worldcitiespop.csv | xsv table
Country  City              AccentCity        Region  Population  Latitude    Longitude
ad       aixas             Aixas             06                  42.4833333  1.4666667
ad       aixirivali        Aixirivali        06                  42.4666667  1.5
ad       aixirivall        Aixirivall        06                  42.4666667  1.5
ad       aixirvall         Aixirvall         06                  42.4666667  1.5
ad       aixovall          Aixovall          06                  42.4666667  1.4833333
ad       andorra           Andorra           07                  42.5        1.5166667
ad       andorra la vella  Andorra la Vella  07      20430       42.5        1.5166667
ad       andorra-vieille   Andorra-Vieille   07                  42.5        1.5166667
ad       andorre           Andorre           07                  42.5        1.5166667
blacknon@BS-PUB-UBUNTU-01:~$ xsv headers worldcitiespop.csv
1   Country
2   City
3   AccentCity
4   Region
5   Population
6   Latitude
7   Longitude
blacknon@BS-PUB-UBUNTU-01:~$ xsv select Country,Region worldcitiespop.csv | head | xsv table
Country  Region
ad       06
ad       06
ad       06
ad       06
ad       06
ad       07
ad       07
ad       07
ad       07

CSVの特定の行範囲を抜き出す

「split」サブコマンドで、CSVから特定の行~行を抜き出すように指定させることができる。

xsv slice -s 開始行 -e 終了行 ファイルPATH
blacknon@BS-PUB-UBUNTU-01:~$ xsv slice -s 10 -e 20 worldcitiespop.csv | xsv table
Country  City             AccentCity       Region  Population  Latitude    Longitude
ad       andorre-vieille  Andorre-Vieille  07                  42.5        1.5166667
ad       ansalonga        Ansalonga        04                  42.5666667  1.5166667
ad       anyos            Anyos            05                  42.5333333  1.5333333
ad       arans            Arans            04                  42.5833333  1.5166667
ad       arinsal          Arinsal          04                  42.5666667  1.4833333
ad       aubinya          Aubinya          06                  42.45       1.5
ad       auvinya          Auvinya          06                  42.45       1.5
ad       bicisarri        Bicisarri        06                  42.4833333  1.4666667
ad       bixessarri       Bixessarri       06                  42.4833333  1.4666667
ad       bixisarri        Bixisarri        06                  42.4833333  1.4666667

CSVの検索をする

CSV内の検索を行う場合は、サブコマンド「search」で行える。

xsv search キーワード ファイルPATH
xsv search -s 検索の対象列 キーワード ファイルPATH
blacknon@BS-PUB-UBUNTU-01:~$ xsv search Japan worldcitiespop.csv | xsv sample 10 | xsv table
Country  City                  AccentCity            Region  Population  Latitude    Longitude
bo       nuevo japan           Nuevo Japan           04                  -15.35      -68.0666667
id       japanan               Japanan               07                  -7.571667   110.856111
us       japan                 Japan                 PA                  40.9925000  -75.9105556
id       japanan               Japanan               10                  -7.734444   110.293056
id       japanan kidul         Japanan Kidul         08                  -7.4246     112.3969
my       rumah japang          Rumah Japang          11                  2.066667    112.416667
id       japan                 Japan                 07                  -7.449167   110.281944
us       japanese village one  Japanese Village One  HI                  20.9052778  -156.4213889
id       japan lor             Japan Lor             07                  -6.6665     110.9096
us       japan                 Japan                 MO                  38.2391667  -91.3058333
blacknon@BS-PUB-UBUNTU-01:~$ xsv search -s Country jp worldcitiespop.csv | xsv sample 10 | xsv table
Country  City                AccentCity          Region  Population  Latitude   Longitude
jp       heita               Heita               16                  39.233333  141.883333
jp       funatsu             Funatsu             27                  32.766667  130.033333
jp       hama-koshimizu      Hama-koshimizu      12                  43.925     144.454167
jp       kokubu              Kokubu              32                  34.566667  135.633333
jp       okata               Okata               40                  34.783333  139.383333
jp       takatsuki           Takatsuki           42                  36.75      137.316667
jp       kinetambefutaroppu  Kinetambefutaroppu  12                  43.766667  144.183333
jp       toseppu             Toseppu             12                  42.05      143.316667
jp       kobama              Kobama              47                  24.337665  123.967611
jp       miake               Miake               24                  38.419451  141.038796

CSVファイルの結合をする

xsvコマンドでは、サブコマンド「join」で指定したカラム同士でCSVファイルを結合させることができる。

xsv join --no-case カラム名1 CSVファイル1 カラム名2 CSVファイル2

blacknon@BS-PUB-UBUNTU-01:~$ xsv headers worldcitiespop.csv
1   Country
2   City
3   AccentCity
4   Region
5   Population
6   Latitude
7   Longitude
blacknon@BS-PUB-UBUNTU-01:~$ xsv headers countrynames.csv
<span style="color: #0000ff;">1   Abbrev
2   Country</span>
blacknon@BS-PUB-UBUNTU-01:~$ xsv join --no-case  Country sample.csv Abbrev countrynames.csv | xsv sample 10 | xsv table
Country  City         AccentCity   Region  Population  Latitude    Longitude    Abbrev  Country
fr       trois-palis  Trois-Palis  B7                  45.633333   .05          FR      France
cf       wama         Wama         02                  4.3         21.65        CF      Central African Republic
pg       nagamize     Nagamize     09                  -6.0333333  145.4166667  PG      Papua New Guinea
cn       jihuizhou    Jihuizhou    03                  29.298401   116.728288   CN      China
cn       fubian       Fubian       32                  31.284892   102.476942   CN      China
gb       barby        Barby        J1                  52.316667   -1.2         GB      Great Britain | UK | England | Scotland | Wales | Northern Ireland | United Kingdom
af       jija         Jija         06                  32.839626   61.985546    AF      Afghanistan
ir       qareh kahal  Qareh Kahal  32                  37.622778   48.434722    IR      Iran
bd       char salda   Char Salda   81                  23.6833333  89.8166667   BD      Bangladesh
et       didu         Didu         54                  7.016667    37.733333    ET      Ethiopia</pre>

結構便利そうなコマンドだ。