# 数据集特性

[Features](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Features) 定义了数据集的内部结构，用于指定底层的序列化格式。但更值得关注的是，[Features](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Features) 包含了从列名和类型到 [ClassLabel](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.ClassLabel) 的高层信息。你可以将 [Features](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Features) 视为数据集的骨架。

[Features](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Features) 格式很简单：`dict[column_name, column_type]`。它是一个由列名和列类型组成的字典。列类型提供了丰富的选项，用于描述您拥有的数据类型。

让我们来看看 GLUE 基准测试中 MRPC 数据集的特性：

```py
>>> from datasets import load_dataset
>>> dataset = load_dataset('nyu-mll/glue', 'mrpc', split='train')
>>> dataset.features
{'idx': Value('int32'),
 'label': ClassLabel(names=['not_equivalent', 'equivalent']),
 'sentence1': Value('string'),
 'sentence2': Value('string'),
}
```

[Value](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Value) 功能会告诉 🤗 Datasets：

- `idx` 的数据类型为 `int32`。
- `sentence1` 和 `sentence2` 的数据类型为 `string`。

🤗 Datasets 还支持许多其他数据类型，例如 `bool`、`float32` 和 `binary`，仅举几例。

> [!TIP]
> 有关支持的数据类型的完整列表，请参阅 [Value](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Value)。

[ClassLabel](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.ClassLabel) 功能告知 🤗 Datasets，`label` 列包含两个类别。这两个类别分别标记为 `not_equivalent` 和 `equivalent`。标签在数据集中以整数形式存储。当你获取标签时，[ClassLabel.int2str()](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.ClassLabel.int2str) 和 [ClassLabel.str2int()](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.ClassLabel.str2int) 负责执行整数值与标签名称之间的相互转换。

如果您的数据类型包含对象列表，那么您需要使用 [List](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.List) 功能。还记得 SQuAD 数据集吗？

```py
>>> from datasets import load_dataset
>>> dataset = load_dataset('rajpurkar/squad', split='train')
>>> dataset.features
{'id': Value('string'),
 'title': Value('string'),
 'context': Value('string'),
 'question': Value('string'),
 'answers': {'text': List(Value('string')),
  'answer_start': List(Value('int32'))}}
```

`answers` 字段使用特征字典构建，因为它包含两个子字段 `text` 和 `answer_start`，它们分别是 `string` 和 `int32` 类型的列表。

> [!TIP]
> 请参阅 [flatten](./process#flatten) 部分，了解如何将嵌套的子字段提取为独立的列。

数组特征类型适用于创建各种大小的数组。您可以使用 [Array2D](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Array2D) 创建二维数组，甚至可以使用 [Array5D](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Array5D) 创建五维数组。

```py
>>> features = Features({'a': Array2D(shape=(1, 3), dtype='int32')})
```

数组类型还允许数组的第一维是动态的。这在处理变长序列（如句子）时非常有用，因为无需将输入填充或截断为统一的形状。

```py
>>> features = Features({'a': Array3D(shape=(None, 5, 2), dtype='int32')})
```

## 音频特征

音频数据集包含一个类型为 [Audio](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Audio) 的列，其中包含三个重要字段：

- `array`：表示为一维数组的解码音频数据。
- `path`：下载的音频文件的路径。
- `sampling_rate`：音频数据的采样率。

加载音频数据集并调用音频列时，[Audio](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Audio) 特征会自动解码并重采样音频文件：

```py
>>> from datasets import load_dataset, Audio

>>> dataset = load_dataset("PolyAI/minds14", "en-US", split="train")
>>> dataset[0]["audio"]
<datasets.features._torchcodec.AudioDecoder object at 0x11642b6a0>
```

> [!WARNING]
> 首先使用行索引，然后使用 `audio` 列来索引音频数据集 - `dataset[0]["audio"]` - 以避免解码和重采样数据集中的所有音频文件。否则，如果数据集较大，这可能是一个缓慢且耗时的过程。

使用 `decode=False` 时，[Audio](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Audio) 类型仅返回音频文件的路径或字节数据，而不会将其解码为 torchcodec 的 `AudioDecoder` 对象，

```py
>>> dataset = load_dataset("PolyAI/minds14", "en-US", split="train").cast_column("audio", Audio(decode=False))
>>> dataset[0]
{'audio': {'bytes': None,
  'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav'},
 'english_transcription': 'I would like to set up a joint account with my partner',
 'intent_class': 11,
 'lang_id': 4,
 'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav',
 'transcription': 'I would like to set up a joint account with my partner'}
```

## 图像特征

图像数据集包含一个类型为 [Image](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Image) 的列，该列从以字节形式存储的图像中加载 `PIL.Image` 对象：

加载图像数据集并调用图像列时，[Image](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Image) 特征会自动解码图像文件：

```py
>>> from datasets import load_dataset, Image

>>> dataset = load_dataset("AI-Lab-Makerere/beans", split="train")
>>> dataset[0]["image"]
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=500x500 at 0x125506CF8>
```

> [!WARNING]
> 使用行索引先对图像数据集进行索引，然后再访问 `image` 列 - `dataset[0]["image"]` - 以避免解码数据集中的所有图像文件。否则，如果数据集较大，这可能是一个缓慢且耗时的过程。

使用 `decode=False` 时，[Image](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Image) 类型仅返回图像文件的路径或字节数据，而不会将其解码为 `PIL.Image`，

```py
>>> dataset = load_dataset("AI-Lab-Makerere/beans", split="train").cast_column("image", Image(decode=False))
>>> dataset[0]["image"]
{'bytes': None,
 'path': '/Users/username/.cache/huggingface/datasets/downloads/extracted/772e7c1fba622cff102b85dd74bcce46e8168634df4eaade7bedd3b8d91d3cd7/train/healthy/healthy_train.265.jpg'}
```

根据数据集的不同，您可能会获取到本地下载图像的路径，或者如果数据集不是由单个文件组成的，则获取图像内容的字节数据。

您也可以从 numpy 数组定义一个图像数据集：

```python
>>> ds = Dataset.from_dict({"i": [np.zeros(shape=(16, 16, 3), dtype=np.uint8)]}, features=Features({"i": Image()}))
```

在这种情况下，numpy 数组会被编码为 PNG（如果像素值的精度很重要，则编码为 TIFF）。

对于 RGB 或 RGBA 等多通道数组，仅支持 uint8。如果使用更高的精度，系统会发出警告，并将数组向下转换为 uint8。对于灰度图像，只要精度与 `Pillow` 兼容，您可以使用所需的整数或浮点精度。如果图像的整数或浮点精度过高，系统会显示警告，此时数组会被向下转换：int64 数组会被向下转换为 int32，float64 数组会被向下转换为 float32。

## Mesh 功能

Mesh 数据集包含一个类型为 [Mesh](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Mesh) 的列，该列将 3D 网格文件加载为 `trimesh` 对象。

加载网格数据集并调用网格列时，[Mesh](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Mesh) 特征会自动解码网格文件：

```py
>>> from datasets import load_dataset, Mesh

>>> dataset = load_dataset("VINAY-UMRETHE/My-Mesh-Dataset", split="train")
>>> dataset[0]["mesh"]
<trimesh.Scene(len(geometry)=33)>
```

根据文件内容，`trimesh` 可能返回一个 `trimesh.Trimesh` 对象或一个 `trimesh.Scene` 对象。

> [!WARNING]
> 使用行索引先索引到网格数据集，然后索引到 `mesh` 列 - `dataset[0]["mesh"]` - 以避免解码数据集中的所有网格文件。否则，如果数据集较大，这可能是一个缓慢且耗时的过程。

使用 `decode=False` 时，[Mesh](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Mesh) 类型会返回网格文件的路径或字节内容，而不会使用 `trimesh` 对其进行解码：

```py
>>> dataset = load_dataset("VINAY-UMRETHE/My-Mesh-Dataset", split="train").cast_column("mesh", Mesh(decode=False))
>>> dataset[0]["mesh"]
{'bytes': b'...',
 'path': '00001.glb'}
```

[Mesh](/docs/datasets/v5.2.0/zh/package_reference/main_classes#datasets.Mesh) 功能支持 `.glb`、`.gltf`、`.ply` 和 `.stl` 文件。对于嵌入的字节，将使用存储的 `path` 来推断网格文件类型。

## Json 功能

Datasets 基于 Arrow（一种列式格式），因此要求每个示例具有相同的类型和子类型，并且字典具有相同的键和值类型。加载数据集时，如果字段类型不匹配，则会抛出错误；对于字典中缺失的字段，会填充为 None，以确保所有字典具有相同的键和值类型。

为避免此问题并允许混合类型而不报错，您可以使用 `on_mixed_types="use_json"` 或指定 `features=` 并使用 [Json](/docs/datasets/v5.2.0/zh/package_reference/loading_methods#datasets.Json) 类型：

```python
>>> ds = Dataset.from_dict({"a": [0, "foo", {"subfield": "bar"}]})
Traceback (most recent call last):
  ...
  File "pyarrow/error.pxi", line 92, in pyarrow.lib.check_status
pyarrow.lib.ArrowInvalid: Could not convert 'foo' with type str: tried to convert to int64

>>> features = Features({"a": Json()})
>>> ds = Dataset.from_dict({"a": [0, "foo", {"subfield": "bar"}]}, features=features)
>>> ds.features
{'a': Json()}
>>> list(ds["a"])
[0, "foo", {"subfield": "bar"}]
```

对于具有任意键和值的字典列表，这也很有用，可以避免用 None 填充缺失的字段：

```python
>>> ds = Dataset.from_dict({"a": [[{"b": 0}, {"c": 0}]]})
>>> ds.features
{'a': List({'b': Value('int64'), 'c': Value('int64')})}
>>> list(ds["a"])
[[{'b': 0, 'c': None}, {'b': None, 'c': 0}]]  # missing fields are filled with None

>>> features = Features({"a": List(Json())})
>>> ds = Dataset.from_dict({"a": [[{"b": 0}, {"c": 0}]]}, features=features)
>>> ds.features
{'a': List(Json())}
>>> list(ds["a"])
[[{'b': 0}, {'c': 0}]]  # OK
```

另一个使用工具调用数据以及 `on_mixed_types="use_json"` 参数的示例（无需手动指定 `features=`，非常有用）：

```python
>>> messages = [
...     {"role": "user", "content": "Turn on the living room lights and play my electronic music playlist."},
...     {"role": "assistant", "tool_calls": [
...         {"type": "function", "function": {
...             "name": "control_light",
...             "arguments": {"room": "living room", "state": "on"}
...         }},
...         {"type": "function", "function": {
...             "name": "play_music",
...             "arguments": {"playlist": "electronic"}  # mixed-type here since keys ["playlist"] and ["room", "state"] are different
...         }}]
...     },
...     {"role": "tool", "name": "control_light", "content": "The lights in the living room are now on."},
...     {"role": "tool", "name": "play_music", "content": "The music is now playing."},
...     {"role": "assistant", "content": "Done!"}
... ]
>>> ds = Dataset.from_dict({"messages": [messages]}, on_mixed_types="use_json")
>>> ds.features
{'messages': List({'role': Value('string'), 'content': Value('string'), 'tool_calls': List(Json()), 'name': Value('string')})}
>>> ds[0][1]["tool_calls"][0]["function"]["arguments"]
{"room": "living room", "state": "on"}
```

