读取和写入CSV文件#

Arrow支持读取和写入CSV文件中的列式数据。目前提供的功能如下:

  • 多线程或单线程读取

  • 自动解压缩输入文件(基于文件名扩展名,例如my_data.csv.gz

  • 从CSV文件的第一行获取列名

  • 列式类型推断并转换为以下类型之一:nullint64float64date32time32[s]timestamp[s]timestamp[ns]stringbinary 数据

  • stringbinary 列进行机会性字典编码(默认禁用)

  • 检测各种空值拼写,例如 NaN#N/A

  • 写入 CSV 文件,并提供选项以配置精确的输出格式

用法#

CSV 读取和写入功能可通过 pyarrow.csv 模块使用。在许多情况下,您只需调用 read_csv() 函数,并传入要读取的文件路径即可

>>> from pyarrow import csv
>>> fn = 'tips.csv.gz'
>>> table = csv.read_csv(fn)
>>> table
pyarrow.Table
total_bill: double
tip: double
sex: string
smoker: string
day: string
time: string
size: int64
>>> len(table)
244
>>> df = table.to_pandas()
>>> df.head()
   total_bill   tip     sex smoker  day    time  size
0       16.99  1.01  Female     No  Sun  Dinner     2
1       10.34  1.66    Male     No  Sun  Dinner     3
2       21.01  3.50    Male     No  Sun  Dinner     3
3       23.68  3.31    Male     No  Sun  Dinner     2
4       24.59  3.61  Female     No  Sun  Dinner     4

要写入 CSV 文件,只需调用 write_csv() 函数,并传入 pyarrow.RecordBatchpyarrow.Table 以及路径或类文件对象即可

>>> import pyarrow as pa
>>> import pyarrow.csv as csv
>>> csv.write_csv(table, "tips.csv")
>>> with pa.CompressedOutputStream("tips.csv.gz", "gzip") as out:
...     csv.write_csv(table, out)

注意

写入器尚不支持所有 Arrow 类型。

自定义解析#

如果要更改读取结构异常的 CSV 文件的默认解析设置,则应创建 ParseOptions 实例并将其传递给 read_csv()

import pyarrow as pa
import pyarrow.csv as csv

table = csv.read_csv('tips.csv.gz', parse_options=csv.ParseOptions(
   delimiter=";",
   invalid_row_handler=skip_handler
))

可用的解析选项包括:

分隔符

CSV 数据中分隔各个单元格的字符。

引用字符

可选用于引用 CSV 值的字符(如果不允许引用,则为 False)。

双引号

引用的 CSV 值中的两个引号是否表示数据中的单个引号。

转义字符

可选用于转义特殊字符的字符(如果不允许转义,则为 False)。

值中的换行符

CSV 值中是否允许换行符。

忽略空行

CSV 输入中是否忽略空行。

无效行处理器

无效行的可选处理器。

另请参阅

有关更多示例,请参阅 ParseOptions

自定义转换#

如果要更改 CSV 数据转换为 Arrow 类型和数据的方式,则应创建 ConvertOptions 实例并将其传递给 read_csv()

import pyarrow as pa
import pyarrow.csv as csv

table = csv.read_csv('tips.csv.gz', convert_options=csv.ConvertOptions(
    column_types={
        'total_bill': pa.decimal128(precision=10, scale=2),
        'tip': pa.decimal128(precision=10, scale=2),
    }
))

可用的转换选项包括:

检查 UTF8

是否检查字符串列的 UTF8 有效性。

列类型

显式地将列名映射到列类型。

空值

表示数据中空值的字符串序列。

真值

表示数据中真布尔值的字符串序列。

假值

表示数据中假布尔值的字符串序列。

小数点

用作浮点数和小数数据中小数点的字符。

时间戳解析器

尝试推断或转换时间戳值时按顺序尝试的与 strptime() 兼容的格式字符串序列(也可以提供特殊值 ISO8601())。

字符串可以为空

字符串/二进制列是否可以具有空值。

带引号的字符串可以为空

带引号的值是否可以为空。

自动字典编码

是否尝试自动对字符串/二进制数据进行字典编码。

自动字典最大基数

用于 auto_dict_encode 的最大字典基数。

包含列

要包含在表中的列的名称。

包含缺失列

如果为假,则 include_columns 中但在 CSV 文件中不存在的列将导致错误。

另请参阅

有关更多示例,请参阅 ConvertOptions

增量读取#

对于内存受限的环境,还可以使用 open_csv() 一次读取一个批次的 CSV 文件。

有一些注意事项

  1. 目前,增量读取器始终是单线程的(无论 ReadOptions.use_threads 如何)。

  2. 类型推断是在第一个块上完成的,并且类型随后被冻结;为了确保推断出正确的类型,请将 ReadOptions.block_size 设置为足够大的值,或者使用 ConvertOptions.column_types 显式设置所需的类型。

字符编码#

默认情况下,CSV 文件应使用 UTF8 编码。对于 binary 列,接受非 UTF8 数据。可以使用 ReadOptions 类更改编码

import pyarrow as pa
import pyarrow.csv as csv

table = csv.read_csv('tips.csv.gz', read_options=csv.ReadOptions(
   column_names=["animals", "n_legs", "entry"],
   skip_rows=1
))

可用的读取选项包括:

使用线程

是否使用多个线程来加速读取。

块大小

从输入流中一次处理多少字节。

跳过行

在列名(如果有)和 CSV 数据之前跳过的行数。

跳过列名后的行

在列名之后跳过的行数。

列名

目标表的列名。

自动生成列名

如果 column_names 为空,是否自动生成列名。

编码

编码:对象

另请参阅

有关更多示例,请参阅 ReadOptions

自定义写入#

如果要更改写入使用不同约定的 CSV 文件的默认写入设置,则可以创建 WriteOptions 实例并将其传递给 write_csv()

>>> import pyarrow as pa
>>> import pyarrow.csv as csv
>>> # Omit the header row (include_header=True is the default)
>>> options = csv.WriteOptions(include_header=False)
>>> csv.write_csv(table, "data.csv", options)

增量写入#

要一次写入一个批次的 CSV 文件,请创建一个 CSVWriter。这需要输出(路径或类文件对象)、要写入的数据的架构,以及上面描述的可选写入选项

>>> import pyarrow as pa
>>> import pyarrow.csv as csv
>>> with csv.CSVWriter("data.csv", table.schema) as writer:
>>>     writer.write_table(table)

性能#

由于 CSV 文件的结构,无法期望获得与读取专用二进制格式(如 Parquet)时相同的性能水平。但是,Arrow 努力减少读取 CSV 文件的开销。合理的预期是在性能优良的台式机或笔记本电脑上每核至少 100 MB/s(以源 CSV 字节为单位测量,而不是目标 Arrow 数据字节)。

可以通过 ReadOptions 类控制性能选项。多线程读取是默认设置,可实现最高性能,并有效地将工作负载分配到所有可用内核上。

注意

并发线程数由 Arrow 自动推断。您可以分别使用 cpu_count()set_cpu_count() 函数检查和更改它。