もた日記

くだらないことを真面目にやる

xsvコマンドでCSVデータの整形、分析を高速に行う

xsvのインストール方法


xsvというコマンドラインツールがあり、このコマンドを使うとCSVデータの整形、分析などが簡単かつ高速にできる。

github.com

インストールの方法だが、下記ページに各OS用の最新版バイナリがあるのでダウンロードして展開すればよい。
Releases · BurntSushi/xsv · GitHub

Macの場合は以下の通り。あとはPATHの通ったディレクトリに置けばよい。

$ curl -sOL https://github.com/BurntSushi/xsv/releases/download/0.10.3/xsv-0.10.3-x86_64-apple-darwin.tar.gz
$ tar xf xsv-0.10.3-x86_64-apple-darwin.tar.gz
$ ./xsv --version
0.10.3


テストCSVデータ


xsvコマンドを試そうにも手頃なCSVデータがないのでREADMEに書いてあったファイルを利用することにする。
下記コマンドでダウンロードできるが約150MB程度あるので注意。

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


xsvの使い方


基本的な使い方はxsv --helpコマンドで確認できる。それぞれのサブコマンドについてもxsv cat --helpなどでヘルプを表示できる。

$ xsv --help

Usage:
    xsv <command> [<args>...]
    xsv [options]

Options:
    --list        List all commands available.
    -h, --help    Display this message
    --version     Print version info and exit

Commands:
    cat         Concatenate by row or column
    count       Count records
    fixlengths  Makes all records have same length
    flatten     Show one field per line
    fmt         Format CSV output (change field delimiter)
    frequency   Show frequency tables
    headers     Show header names
    help        Show this usage message.
    index       Create CSV index for faster access
    input       Read CSV data with special quoting rules
    join        Join CSV files
    sample      Randomly sample CSV data
    search      Search CSV data with regexes
    select      Select columns from CSV
    slice       Slice records from CSV
    sort        Sort CSV data
    split       Split CSV data into many files
    stats       Compute basic statistics
    table       Align CSV data into columns

以下、それぞれのサブコマンドの使い方を見ていく。

cat


列方向、行方向にCSVファイルを結合する。

$ cat test.csv
A,B
1,0.1
2,0.2
$ xsv cat rows test.csv test.csv
A,B
1,0.1
2,0.2
1,0.1
2,0.2
$ xsv cat columns test.csv test.csv
A,B,A,B
1,0.1,1,0.1
2,0.2,2,0.2

count


行数をカウントする(ヘッダは含めない)。ヘッダがないファイルの場合は--no-headersを指定する。

$ xsv count worldcitiespop.csv
3173958
$ xsv count --no-headers worldcitiespop.csv
3173959

fixlengths


データが欠けている場合に修正する。例の場合は、最終行の欠けている要素が埋められていることがわかる。-l 2のように列数を指定して修正することも可能。

$ cat test2.csv
A,B,C
1,0.1,100
2,0.2
$ xsv fixlengths test2.csv
A,B,C
1,0.1,100
2,0.2,
$ xsv fixlengths -l 2 test2.csv
A,B
1,0.1
2,0.2

flatten


縦に並べて表示する。

$ xsv sample 3 worldcitiespop.csv | xsv flatten
Country     ir
City        badi` kheyl
AccentCity  Badi` Kheyl
Region      35
Population
Latitude    36.351506
Longitude   51.749572
#
Country     ru
City        brysina
AccentCity  Brysina
Region      41
Population
Latitude    51.8367
Longitude   34.7219
#
Country     kr
City        saraegi
AccentCity  Saraegi
Region      13
Population
Latitude    37.5307
Longitude   127.1672

fmt


フォーマットを変換する。下記コマンドだとタブ区切りで、デフォルトの引用符(")で囲むようにして出力する。

$ xsv fmt -t "\t" --quote-always worldcitiespop.csv > fmt.csv
$ head -n 3 fmt.csv
"Country"	"City"	"AccentCity"	"Region"	"Population"	"Latitude"	"Longitude"
"ad"	"aixas"	"Aixàs"	"06"	""	"42.4833333"	"1.4666667"
"ad"	"aixirivali"	"Aixirivali"	"06"	""	"42.4666667"	"1.5"

frequency


出現頻度の高い値を出力する。-lは表示する数。例の場合だとPopulationのほとんどが(NULL)だとわかる。

$ xsv frequency -l 3 worldcitiespop.csv | xsv table
field       value        count
Country     cn           238985
Country     ru           215938
Country     id           176546
City        san jose     328
City        san antonio  320
City        santa rosa   296
AccentCity  San Antonio  317
AccentCity  Santa Rosa   296
AccentCity  Santa Cruz   281
Region      04           159916
Region      02           142158
Region      07           126867
Population  (NULL)       3125978
Population  2310         12
Population  2230         11
Latitude    51.15        777
Latitude    51.083333    772
Latitude    51.116667    769
Longitude   23.8         484
Longitude   23.2         477
Longitude   23.05        476

headers


ヘッダ情報を出力する。

$ xsv headers worldcitiespop.csv
1   Country
2   City
3   AccentCity
4   Region
5   Population
6   Latitude
7   Longitude

index


インデックスファイルを作成する。下記コマンドを実行するとworldcitiespop.csv.idxというファイルが作成される。slicestatsコマンドなどはインデックスファイルを作成しておいた方が高速に処理できるとのこと。

$ xsv index worldcitiespop.csv

input


デリミタなどを指定して読み込む。例えば、上記のfmtで変換したファイルで統計情報を表示しようとするとうまくいかないが、デリミタを指定してinputすれば表示できる。

$ xsv stats fmt.csv | xsv table
field     type      sum             min         max             min_length    max_length      mean     stddev
"Country  ""City""  ""AccentCity""  ""Region""  ""Population""  ""Latitude""  ""Longitude"""  Unicode      "ad  ""aixas""  ""Aixàs""  ""06""  """"  ""42.4833333""  ""1.4666667"""  "zw  ""zvishavane""  ""Zvishavane""  ""07""  ""79876""  ""-20.3333333""  ""30.0333333"""  32  218
$ xsv input -d "\t" fmt.csv | xsv stats | xsv table
field       type     sum                 min            max            min_length  max_length  mean                stddev
Country     Unicode                      ad             zw             2           2
 …

join


SQL文のJOIN句のような処理ができる。オプションでLEFT OUTER JOINRIGHT OUTER JOINなども指定できる。

$ cat input1.csv
id,name,genre_id
1,name1,2
2,name2,2
3,name3,1
$ cat input2.csv
id,genre
1,genre1
2,genre2
$ xsv join genre_id input1.csv id input2.csv | xsv table
id  name   genre_id  id  genre
1   name1  2         2   genre2
2   name2  2         2   genre2
3   name3  1         1   genre1

sample


ランダムでサンプリングして出力する。下記コマンドの10は抽出数。

$ xsv sample 10 worldcitiespop.csv | xsv table
Country  City          AccentCity    Region  Population  Latitude     Longitude
us       west end      West End      PA                  39.9519444   -78.7488889
us       rumford       Rumford       ME      8339        44.5536111   -70.5513889
ml       amgoundji     Amgoundji     02                  17.05        -1.1333333
th       ban nong pho  Ban Nong Pho  52                  13.416667    99.8
de       marktgolitz   Marktgölitz   15                  50.55        11.35
mz       djo           Djo           10                  -18.2802778  33.4563889
tr       gultepe       Gültepe       69                  40.046399    39.28264
tr       alacayir      Alacayir      24                  39.80777     38.935108
id       detunabe      Detunabe      18                  -8.6968      121.8149
id       kadukampong   Kadukampong   33                  -6.2506      106.1266


正規表現で検索する。-sで検索する列を指定することも可能。-iは大文字、小文字を区別しない。-vでマッチしない行を出力することも可能。

$ xsv search -s City -i japan worldcitiespop.csv | xsv slice -l 5 | xsv table
Country  City         AccentCity   Region  Population  Latitude   Longitude
bo       nuevo japan  Nuevo Japan  04                  -15.35     -68.0666667
id       ajapanisi    Ajapanisi    38                  -4.5714    120.1593
id       bawakjapan   Bawakjapan   07                  -7.758056  110.676667
id       djapanan     Djapanan     08                  -7.5647    112.6901
id       djapan       Djapan       07                  -7.449167  110.281944

select


出力する列を指定する。列番号、列名での指定、順番の並び替えなども可能。'!1-4'は否定で1-4列目以外のこと。

$ xsv select 1,4 worldcitiespop.csv | xsv slice -l 3 | xsv table
Country  Region
ad       06
ad       06
ad       06
$ xsv select 1-4 worldcitiespop.csv | xsv slice -l 3 | xsv table
Country  City        AccentCity  Region
ad       aixas       Aixàs       06
ad       aixirivali  Aixirivali  06
ad       aixirivall  Aixirivall  06
$ xsv select AccentCity,City worldcitiespop.csv | xsv slice -l 3 | xsv table
AccentCity  City
Aixàs       aixas
Aixirivali  aixirivali
Aixirivall  aixirivall
$ xsv select Country,Region worldcitiespop.csv | xsv slice -l 3 | xsv table
Country  Region
ad       06
ad       06
ad       06
$ xsv select Region-Country worldcitiespop.csv | xsv slice -l 3 | xsv table
Region  AccentCity  City        Country
06      Aixàs       aixas       ad
06      Aixirivali  aixirivali  ad
06      Aixirivall  aixirivall  ad
$ xsv select '!1-4' worldcitiespop.csv | xsv slice -l 3 | xsv table
Population  Latitude    Longitude
            42.4833333  1.4666667
            42.4666667  1.5
            42.4666667  1.5

slice


特定の行を抽出する。-s-eは開始行と終了行、-lは抽出行数。1行だけ抽出したい場合は-iを指定する。

$ xsv slice -s 5000 -e 5003 worldcitiespop.csv
Country,City,AccentCity,Region,Population,Latitude,Longitude
af,`atamohammed kala,`Atamohammed Kala,08,,33.404722,68.474722
af,atamsa kalay,Atamsa Kalay,29,,32.933556,69.44915
af,atamshakalay,Atamshakalay,29,,32.933556,69.44915
$ xsv slice -s 10000 -l 3 worldcitiespop.csv
Country,City,AccentCity,Region,Population,Latitude,Longitude
af,bodana qal`eh-ye yekom,Bodana Qal`eh-ye Yekom,30,,36.52137,66.941631
af,boday,Boday,08,,32.972897,68.358986
af,boday-naw,Boday-naw,18,,34.300289,69.708168
$ xsv slice -i 20000  worldcitiespop.csv
Country,City,AccentCity,Region,Population,Latitude,Longitude
af,dekhmushan,Dekhmushan,09,,34.332854,66.383943

sort


カラムを指定してソートする。

$ xsv sample 10 worldcitiespop.csv | xsv sort -s City | xsv table
Country  City             AccentCity       Region  Population  Latitude     Longitude
af       alamkhel         Alamkhel         37                  33.157147    69.697729
ru       bugristoye       Bugristoye       13                  54.0075      61.6014
es       cruces           Cruces           58                  42.758775    -7.164669
do       gajo de bohio    Gajo de Bohío    23                  19.0833333   -71.3666667
bo       ipira            Ipira            07                  -18.2666667  -65.9333333
cl       molco            Molco            11                  -35.733333   -72.383333
ru       normanka         Normanka         73                  54.954221    48.742891
cn       pingwang         Pingwang         04                  30.976667    120.636111
us       rowland mills    Rowland Mills    NJ                  40.5566667   -74.8541667
cz       slezska ostrava  Slezska Ostrava  85                  49.836902    18.311172

split


ファイルを分割して出力する。下記コマンドは100万行単位でoutput/ディレクトリに出力する例。分割後のファイルにはヘッダも付く。

$ xsv split -s 1000000 output/ worldcitiespop.csv
$ wc -l output/*
 1000001 output/0.csv
 1000001 output/1000000.csv
 1000001 output/2000000.csv
  173959 output/3000000.csv
 3173962 total

stats


統計情報を出力する。

$ xsv stats worldcitiespop.csv | xsv table
field       type     sum                 min            max            min_length  max_length  mean                stddev
Country     Unicode                      ad             zw             2           2
City        Unicode                       bab el ahmar  Þykkvibaer     1           91
AccentCity  Unicode                       Bâb el Ahmar  ïn Bou Chella  1           91
Region      Unicode                      00             Z9             0           2
Population  Integer  2289584999          7              31480498       0           8           47719.570633597126  302885.5592040396
Latitude    Float    86294096.37312101   -54.933333     82.483333      1           12          27.188165808468785  21.95261384912504
Longitude   Float    117718483.57958724  -179.9833333   180            1           14          37.08885989656418   63.223010459241635

--everythingを指定すればmedianmodecardinalityも表示される。

$ xsv stats worldcitiespop.csv --everything | xsv table
field       type     sum                 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  2289584999          7              31480498       0           8           47719.570633597126  302885.5592040396   10779                    28754
Latitude    Float    86294096.37312101   -54.933333     82.483333      1           12          27.188165808468785  21.95261384912504   32.4972221  51.15        1038349
Longitude   Float    117718483.57958724  -179.9833333   180            1           14          37.08885989656418   63.223010459241635  35.28       23.8         1167162

table


データを見やすく整形して表示できる。データ数が多いと時間がかかるので注意。

$ xsv slice -l 5 worldcitiespop.csv | xsv table
Country  City        AccentCity  Region  Population  Latitude    Longitude
ad       aixas       Aixàs       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