Делаем панды серии безопасными YAML - PullRequest
0 голосов
/ 08 июня 2018

Я работаю с одним сценарием, который выводит серию панд в файл yaml:

with open('ex.py','w') as f:
    yaml.dump(a_series,f)

И затем другой сценарий, который открывает файл yaml для серии панд:

with open('ex.py','r') as f:
    yaml.safe_load(a_series,f)

Я пытаюсь безопасно загрузить серию, но получаю ошибку конструктора.Как я могу указать, что серия панд безопасна для загрузки?

1 Ответ

0 голосов
/ 09 июня 2018

Когда вы используете PyYAML load, вы указываете, что все в загружаемом вами документе YAML является безопасным.Вот почему вам нужно использовать yaml.safe_load.

В вашем случае это приводит к ошибке, потому что safe_load не знает, как сконструировать внутренние элементы панд, которые имеют теги в документе YAML, такие как:

!!python/name:pandas.core.indexes.base.Index

и

!!python/tuple

и т. Д.

Вам потребуется предоставить конструкторы для всех объектов, добавить их в SafeLoader и затем выполнить a_series = yaml.load(f).Для этого может потребоваться много работы, особенно если учесть, что небольшое изменение в данных, используемых в вашей серии, может потребовать добавления конструкторов.

Вы можете вывести DICT-представление вашего Series и загрузитьчто обратно.Конечно, некоторая информация теряется в этом процессе, я не уверен, что это приемлемо:

import sys
import yaml
from pandas import Series

def series_representer(dumper, data):
    return dumper.represent_mapping(u'!pandas.series', data.to_dict())

yaml.add_representer(Series, series_representer, Dumper=yaml.SafeDumper)

def series_constructor(loader, node):
    d = loader.construct_mapping(node)
    return Series(data)

yaml.add_constructor(u'!pandas.series', series_constructor, Loader=yaml.SafeLoader)

data = Series([1,2,3,4,5], index=['a', 'b', 'c', 'd', 'e'])

with open('ex.yaml', 'w') as f:
    yaml.safe_dump(data, f)

with open('ex.yaml') as f:
    s = yaml.safe_load(f)

print(s)
print(type(s))

, что дает:

a    1
b    2
c    3
d    4
e    5
dtype: int64
<class 'pandas.core.series.Series'>

И файл ex.yaml содержит:

!pandas.series {a: 1, b: 2, c: 3, d: 4, e: 5}

Следует отметить несколько вещей:

  • Документы YAML обычно записываются в файлы с расширением .yaml.Использование .py обязательно приведет вас в замешательство, или вам придется перезаписать некоторые исходные файлы программы в какой-то момент.

  • yaml.load() и yaml.safe_load() принимают поток в качестве первого используемого параметраони как:

    data = yaml.safe_load(stream)
    

    и не как:

    yaml.safe_load(data, stream)
    
  • Было бы лучше иметь двухступенчатый конструктор , который позволяетвам построить самоссылочные структуры данных.Однако Series.append(), похоже, не работает для этого:

    def series_constructor(loader, node):
        d = Series()
        yield d
        d.append(Series(loader.construct_mapping(node)))
    

Если сброс Series через словарь не достаточно хорош (потому что это упрощает серию'data), и если вас не волнует читаемость сгенерированного YAML, вы можете вместо .to_dict() использовать для to_pickle(), но вам придется работать с временными файлами, так как этот метод недостаточно гибок для обработкиfile like объекты и ожидает строку имени файла в качестве аргумента.

...