Разработчик#

Этот раздел будет посвящен прикладным применениям pandas.

Хранение объектов pandas DataFrame в формате Apache Parquet#

The Apache Parquet формат предоставляет метаданные в виде ключ-значение на уровне файла и столбца, хранящиеся в нижнем колонтитуле файла Parquet:

5: optional list key_value_metadata

где KeyValue является

struct KeyValue {
  1: required string key
  2: optional string value
}

Так что pandas.DataFrame может быть точно восстановлен, мы сохраняем pandas ключ метаданных в FileMetaData со значением, хранящимся как:

{'index_columns': [, , ...],
 'column_indexes': [, , ..., ],
 'columns': [, , ...],
 'pandas_version': $VERSION,
 'creator': {
   'library': $LIBRARY,
   'version': $LIBRARY_VERSION
 }}

Значения "дескриптора" в 'index_columns' поле являются строками (ссылающимися на столбец) или словарями со значениями, как описано ниже.

The / и так далее являются словарями, содержащими метаданные для каждого столбца, включая столбцы индекса. Это имеет 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__'.

Если индекс имеет не-None 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: 'categorical'

  • Другие объекты Python: 'object'

The numpy_type является физическим типом хранения столбца, который является результатом str(dtype) для базового массива NumPy, который хранит данные. Так что для datetimetz это datetime64[ns] а для категориального это может быть любой из поддерживаемых целочисленных категориальных типов.

The 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'
 }}