开发者#
本节将重点介绍 pandas 的下游应用。
将 pandas DataFrame 对象存储在 Apache Parquet 格式中#
Apache Parquet 格式在文件和列级别提供键值元数据,存储在 Parquet 文件的页脚中:
5: optional list<KeyValue> key_value_metadata
其中 KeyValue
是
struct KeyValue {
1: required string key
2: optional string value
}
为了能够忠实地重建 pandas.DataFrame
,我们在 FileMetaData
中存储了一个 pandas
元数据键,其值存储为 :
{'index_columns': [<descr0>, <descr1>, ...],
'column_indexes': [<ci0>, <ci1>, ..., <ciN>],
'columns': [<c0>, <c1>, ...],
'pandas_version': $VERSION,
'creator': {
'library': $LIBRARY,
'version': $LIBRARY_VERSION
}}
'index_columns'
字段中的 <descr0>
“描述符” 值是字符串(引用一列)或字典,其值如下所述。
<c0>
/<ci0>
等等是包含每列元数据的字典,包括索引列。其形式为 JSON:
{'name': column_name,
'field_name': parquet_column_name,
'pandas_type': pandas_type,
'numpy_type': numpy_type,
'metadata': metadata}
有关这些的详细规范,请参见下文。
索引元数据描述符#
RangeIndex
可以仅作为元数据存储,不需要序列化。这些的描述符格式如下:
index = pd.RangeIndex(0, 10, 2)
{
"kind": "range",
"name": index.name,
"start": index.start,
"stop": index.stop,
"step": index.step,
}
其他索引类型必须与 DataFrame 的其他列一起序列化为数据列。这些的元数据是一个字符串,指示数据列中字段的名称为,例如 '__index_level_0__'
。
如果一个索引有一个非空的 name
属性,并且没有其他列的名称与该值匹配,那么可以使用 index.name
值作为描述符。否则(对于未命名的索引和名称与其他列名冲突的索引)应使用模式匹配 __index_level_\d+__
的消除歧义的名称。在作为数据列的命名索引的情况下,name
属性总是如上所述存储在列描述符中。
列元数据#
pandas_type
是列的逻辑类型,并且是以下之一:
布尔值:
'bool'
整数:
'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64'
浮点数:
'float16', 'float32', 'float64'
日期和时间类型:
'datetime', 'datetimetz'
,'timedelta'
字符串:
'unicode', 'bytes'
分类:
'categorical'
其他 Python 对象:
'object'
numpy_type
是列的物理存储类型,这是底层NumPy数组保存数据时 str(dtype)
的结果。因此,对于 datetimetz
,这是 datetime64[ns]
,而对于分类,可能是任何支持的整数分类类型。
metadata
字段除了以下情况外,都是 None
:
datetimetz
:{'timezone': zone, 'unit': 'ns'}
, 例如{'timezone', 'America/New_York', 'unit': 'ns'}
.'unit'
是可选的,如果省略则假定为纳秒。categorical
:{'num_categories': K, 'ordered': is_ordered, 'type': $TYPE}
这里
'type'
是可选的,并且可以是一个嵌套的 pandas 类型规范(但不是分类类型)
unicode
:{'encoding': encoding}
编码是可选的,如果不存在则是 UTF-8
object
:{'encoding': encoding}
. 对象可以被序列化并存储在BYTE_ARRAY
Parquet 列中。编码可以是以下之一:'pickle'
'bson'
'json'
timedelta
:{'unit': 'ns'}
。'unit'
是可选的,如果省略则假定为纳秒。这个元数据完全是可选的。
对于这些类型以外的类型,可以省略 'metadata'
键。如果键不存在,实现可以假设为 None
。
作为一个完整的元数据示例:
{'index_columns': ['__index_level_0__'],
'column_indexes': [
{'name': None,
'field_name': 'None',
'pandas_type': 'unicode',
'numpy_type': 'object',
'metadata': {'encoding': 'UTF-8'}}
],
'columns': [
{'name': 'c0',
'field_name': 'c0',
'pandas_type': 'int8',
'numpy_type': 'int8',
'metadata': None},
{'name': 'c1',
'field_name': 'c1',
'pandas_type': 'bytes',
'numpy_type': 'object',
'metadata': None},
{'name': 'c2',
'field_name': 'c2',
'pandas_type': 'categorical',
'numpy_type': 'int16',
'metadata': {'num_categories': 1000, 'ordered': False}},
{'name': 'c3',
'field_name': 'c3',
'pandas_type': 'datetimetz',
'numpy_type': 'datetime64[ns]',
'metadata': {'timezone': 'America/Los_Angeles'}},
{'name': 'c4',
'field_name': 'c4',
'pandas_type': 'object',
'numpy_type': 'object',
'metadata': {'encoding': 'pickle'}},
{'name': None,
'field_name': '__index_level_0__',
'pandas_type': 'int64',
'numpy_type': 'int64',
'metadata': None}
],
'pandas_version': '1.4.0',
'creator': {
'library': 'pyarrow',
'version': '0.13.0'
}}