关于 xsv
xsv 是一个高性能的 CSV 处理工具,提供索引、切片、连接和统计分析功能。以 Rust 编写,设计用于高效处理大型 CSV 文件。
主要功能
- 01索引和搜索 CSV 文件中的列和行
- 02计算统计信息(计数、求和、均值等)
- 03连接、拼接和转换多个 CSV 文件
适用场景
- 01编码 Agent 在数据处理工作流中高效处理 CSV 文件
- 02开发人员分析和转换日志、配置或数据导出文件
安装
选择你的系统或包管理器,复制命令到终端运行。
安装完成后运行xsv --version确认安装成功。
命令示例
常用命令按使用顺序排列。
详细介绍
xsv 现已停止维护
xsv 是一个用于索引、切片、分析、拆分和合并 CSV 文件的命令行程序。命令应当简单、快速且可组合:
- 简单任务应当易于完成。
- 应在命令行界面中体现性能方面的权衡。
- 组合使用不应以牺牲性能为代价。
除了快速浏览几个命令外,本 README 还介绍了如何
安装 xsv。
采用 MIT 或 UNLICENSE 双重许可。
可用命令
- cat - 按行或按列串联 CSV 文件。
- count - 统计 CSV 文件中的行数。(存在索引时可瞬间完成。)
- fixlengths - 通过填充或截断记录,强制 CSV 文件中的记录长度一致。
- flatten - 以扁平格式查看 CSV 记录。适合逐条查看记录。例如:
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 - 将一个 CSV 文件拆分为多个包含 N 个数据块的 CSV 文件。
- stats - 显示 CSV 文件中每一列的基本类型和统计信息。(例如,均值、标准差、中位数、范围等。)
- table - 使用 弹性制表位显示 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,还有一列不再需要的 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 列”。由于我们先与 countrynames.csv 执行了联接,第一个 Country 名称(完整名称)现在已包含在 CSV 数据中。
这条 xsv join 命令在我的机器上大约需要 7 秒。它的高性能得益于为给定的某个 CSV 数据文件构建了一个非常简单的哈希索引。join 命令默认执行内联接,但也支持左、右和全外联接。
安装
可从 Github 下载适用于 Windows、Linux 和 macOS 的二进制文件。
如果你是 macOS Homebrew 用户,可以从 homebrew-core 安装 xsv:
$ brew install xsv
如果你是 macOS MacPorts 用户,可以从官方 ports安装 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 是一种糟糕的格式。
- 如果你的数据有数 GB,那么 CSV 就不是合适的存储类型。
- 各种 SQL 数据库都能提供
xsv中的所有操作,而且索引支持更加完善,性能也好上无数倍。
我相信还有更多批评,但启动这个项目的契机,是有人交给我一个 40GB 的 CSV 文件。我需要弄清楚其中数据的结构,并想办法将其集成到我们现有的系统中。那时我意识到,我所知道的每一种 CSV 工具都远远不够用。它们要么太慢,要么缺乏足够的灵活性。(我参与的另一个项目包含几十个 CSV 文件。它们都不到 40GB,但本应表示同一类数据。可它们的列和列名各不相同,列名也不直观。实用的 CSV 检查工具在这里至关重要,而且速度必须足够快。)
帮助我完成这项任务的关键功能包括索引、随机采样、搜索、切片和选择列。这些功能都让处理 40GB 的 CSV 数据(或几十个 CSV 文件)变得更容易一些。
仅仅是一次接手一个大型 CSV 文件,就足以让我踏上这段探索之旅。从我与他人的交流来看,这么大的 CSV 数据文件似乎并不少见。因此,我相信仍有空间开发一种有望处理如此大规模数据的工具。
名称冲突
本项目与另一个名称相同的类似项目无关: https://mj.ucw.cz/sw/xsv/