Hub documentation
PyArrow
PyArrow
Arrow 是一种列式格式,也是用于快速数据交换和内存分析的工具箱。
由于 PyArrow 支持使用 fsspec 来读写远程数据,因此您可以使用 Hugging Face 路径(hf://)来读写 Hub 上的数据。
这对于 Parquet 数据尤其有用,因为 Parquet 是 Hugging Face 上最常见的文件格式。
事实上,得益于其结构、类型、元数据和压缩特性,Parquet 的效率非常高。
加载表格
您可以从本地文件或 Hugging Face Datasets 等远程存储中加载数据。PyArrow 支持多种格式,包括 CSV、JSON,以及更重要的 Parquet:
>>> import pyarrow.parquet as pq
>>> table = pq.read_table("path/to/data.parquet")要从 Hugging Face 加载文件,路径必须以 hf:// 开头。例如,stanfordnlp/imdb 数据集仓库的路径为 hf://datasets/stanfordnlp/imdb。Hugging Face 上的该数据集包含多个 Parquet 文件。Parquet 文件格式旨在高效地读写数据帧,并便于在不同数据分析语言之间共享数据。以下是如何将文件 plain_text/train-00000-of-00001.parquet 加载为 pyarrow Table(需要 pyarrow>=21.0):
>>> import pyarrow.parquet as pq
>>> table = pq.read_table("hf://datasets/stanfordnlp/imdb/plain_text/train-00000-of-00001.parquet")
>>> table
pyarrow.Table
text: string
label: int64
----
text: [["I rented I AM CURIOUS-YELLOW from my video store because of all the controversy that surrounded it (... 1542 chars omitted)", ...],...,[..., "The story centers around Barry McKenzie who must go to England if he wishes to claim his inheritan (... 221 chars omitted)"]]
label: [[0,0,0,0,0,...,0,0,0,0,0],...,[1,1,1,1,1,...,1,1,1,1,1]]如果不想加载完整的 Parquet 数据,可以获取 Parquet 元数据,或者按行组逐个加载:
>>> import pyarrow.parquet as pq
>>> pf = pq.ParquetFile("hf://datasets/stanfordnlp/imdb/plain_text/train-00000-of-00001.parquet")
>>> pf.metadata
<pyarrow._parquet.FileMetaData object at 0x1171b4090>
created_by: parquet-cpp-arrow version 12.0.0
num_columns: 2
num_rows: 25000
num_row_groups: 25
format_version: 2.6
serialized_size: 62036
>>> for i in pf.num_row_groups:
... table = pf.read_row_group(i)
... ...有关 Hugging Face 路径及其实现方式的更多信息,请参阅 HfFileSystem 的客户端库文档。
保存表格
您可以使用 pyarrow.parquet.write_table 将 pyarrow Table 保存到本地文件或 Hugging Face。
要在 Hugging Face 上保存 Table,您首先需要使用您的 Hugging Face 账户登录,例如使用:
hf auth login然后你可以创建数据集仓库,例如使用:
from huggingface_hub import HfApi
HfApi().create_repo(repo_id="username/my_dataset", repo_type="dataset")最后,你可以在 PyArrow 中使用 Hugging Face 路径:
import pyarrow.parquet as pq
pq.write_table(table, "hf://datasets/username/my_dataset/imdb.parquet", use_content_defined_chunking=True)
# or write in separate files if the dataset has train/validation/test splits
pq.write_table(table_train, "hf://datasets/username/my_dataset/train.parquet", use_content_defined_chunking=True)
pq.write_table(table_valid, "hf://datasets/username/my_dataset/validation.parquet", use_content_defined_chunking=True)
pq.write_table(table_test , "hf://datasets/username/my_dataset/test.parquet", use_content_defined_chunking=True)请注意,Hugging Face 上的 Parquet 文件经过优化,以提升存储效率、加快下载和上传速度,并支持高效的数据集流式处理和编辑:
- Parquet 内容定义分块针对 Hugging Face 的存储后端 Xet 优化了 Parquet。它通过基于分块的重复数据删除加速了上传和下载,并支持高效的文件编辑
- Page index 在流式传输时加速过滤,并支持高效的随机访问,例如在 Dataset Viewer 中。
PyArrow 需要额外的参数来写入优化后的 Parquet 文件:
import pyarrow.parquet as pq
pq.write_table(
table,
"hf://datasets/username/my_dataset/imdb.parquet",
# Optimize for Xet
use_content_defined_chunking=True,
write_page_index=True,
)use_content_defined_chunking=True以启用 Parquet Content Defined Chunking,用于去重和编辑(需要pyarrow>=21.0)write_page_index=True以在 Parquet 元数据中包含页面索引,用于流式处理和随机访问
内容定义分块(CDC)使 Parquet 写入器以特定方式对数据页进行分块,从而确保重复数据被分块并以相同方式压缩。 如果没有 CDC,数据页会被任意分块,因此由于压缩的存在,无法检测出重复数据。 得益于 CDC,从 Hugging Face 上传和下载 Parquet 文件的速度更快,因为重复数据只需上传或下载一次。
有关 Xet 的更多信息,请参见此处。
利用 Xet 去重功能处理 Parquet
经过优化的 Parquet 文件采用 Content Defined Chunking 进行写入,从而实现去重。 这加快了上传速度,因为 Hugging Face 上已存在的数据块无需再次上传,从而大幅节省了 I/O。
例如,此代码上传 table 的内容,然后对于 edited_table,由于只上传了发生更改的块,因此上传速度更快:
import pyarrow.parquet as pq
pq.write_table(
table,
"hf://datasets/username/my_dataset/imdb.parquet",
# Optimize for Xet
use_content_defined_chunking=True,
write_page_index=True,
)
edited_table = ... # e.g. with added/modified/removed rows or columns
pq.write_table(
edited_table,
"hf://datasets/username/my_dataset/imdb.parquet",
# Optimize for Xet
use_content_defined_chunking=True,
write_page_index=True,
)数据块大小约为 64kB,而 Parquet 按列存储数据,因此实际编辑优化后的 Parquet 文件时,会发生以下情况:
- 添加新列 -> 仅上传新列的块
- 添加/编辑/删除一行 -> 每列上传一个数据块
此外,包含元数据的 Parquet 文件尾块也会被上传。
使用图像
您可以加载一个包含元数据文件的文件夹,该文件中有一个字段用于存储图像的名称或路径,其结构如下:
Example 1: Example 2:
folder/ folder/
├── metadata.parquet ├── metadata.parquet
├── img000.png └── images
├── img001.png ├── img000.png
... ...
└── imgNNN.png └── imgNNN.png您可以按以下方式迭代图像路径:
from pathlib import Path
import pyarrow as pq
folder_path = Path("path/to/folder")
table = pq.read_table(folder_path + "metadata.parquet")
for file_name in table["file_name"].to_pylist():
image_path = folder_path / file_name
...由于数据集采用受支持的结构(一个包含file_name字段的metadata.parquet文件),您可以将该数据集保存到 Hugging Face,Dataset Viewer 会同时显示元数据和图像。
from huggingface_hub import HfApi
api = HfApi()
api.upload_folder(
folder_path=folder_path,
repo_id="username/my_image_dataset",
repo_type="dataset",
)在 Parquet 中嵌入图像
PyArrow 提供了一种二进制类型,允许在 Arrow 表中存储图像的字节数据。因此,它支持将数据集保存为单个 Parquet 文件,其中同时包含图像(字节和路径)以及样本元数据:
import pyarrow as pa
import pyarrow.parquet as pq
# Embed the image bytes in Arrow
image_array = pa.array([
{
"bytes": (folder_path / file_name).read_bytes(),
"path": file_name,
}
for file_name in table["file_name"].to_pylist()
])
table.append_column("image", image_array)
# (Optional) Set the HF Image type for the Dataset Viewer and the `datasets` library
features = {"image": {"_type": "Image"}} # or using datasets.Features(...).to_dict()
schema_metadata = {"huggingface": {"dataset_info": {"features": features}}}
table = table.replace_schema_metadata(schema_metadata)
# Save to Parquet
# (Optional) with use_content_defined_chunking for faster uploads and downloads
pq.write_table(table, "data.parquet", use_content_defined_chunking=True)在 Arrow 架构元数据中设置图像类型,可以让其他库和 Hugging Face 数据集查看器知道“image”字段包含的是图像,而不仅仅是二进制数据。
使用 Audios
您可以加载一个包含元数据文件的文件夹,该文件中有一个字段用于存储音频的名称或路径,其结构如下:
Example 1: Example 2:
folder/ folder/
├── metadata.parquet ├── metadata.parquet
├── rec000.wav └── audios
├── rec001.wav ├── rec000.wav
... ...
└── recNNN.wav └── recNNN.wav您可以像这样迭代音频路径:
from pathlib import Path
import pyarrow as pq
folder_path = Path("path/to/folder")
table = pq.read_table(folder_path + "metadata.parquet")
for file_name in table["file_name"].to_pylist():
audio_path = folder_path / file_name
...由于数据集采用受支持的结构(一个包含file_name字段的metadata.parquet文件),您可以将其保存到 Hugging Face,Hub 数据集查看器将同时显示元数据和音频。
from huggingface_hub import HfApi
api = HfApi()
api.upload_folder(
folder_path=folder_path,
repo_id="username/my_audio_dataset",
repo_type="dataset",
)在 Parquet 中嵌入音频
PyArrow 提供了一种二进制类型,允许在 Arrow 表中存储音频字节。因此,它支持将数据集保存为单个 Parquet 文件,其中同时包含音频(字节和路径)以及样本元数据:
import pyarrow as pa
import pyarrow.parquet as pq
# Embed the audio bytes in Arrow
audio_array = pa.array([
{
"bytes": (folder_path / file_name).read_bytes(),
"path": file_name,
}
for file_name in table["file_name"].to_pylist()
])
table.append_column("audio", audio_array)
# (Optional) Set the HF Audio type for the Dataset Viewer and the `datasets` library
features = {"audio": {"_type": "Audio"}} # or using datasets.Features(...).to_dict()
schema_metadata = {"huggingface": {"dataset_info": {"features": features}}}
table = table.replace_schema_metadata(schema_metadata)
# Save to Parquet
# (Optional) with use_content_defined_chunking for faster uploads and downloads
pq.write_table(table, "data.parquet", use_content_defined_chunking=True)在 Arrow 架构元数据中设置 Audio 类型,可让其他库和 Hugging Face Dataset Viewer 识别出“audio”包含的是音频数据,而不仅仅是二进制数据。
Update on GitHub