我正在使用一个将pandas系列转储到yaml文件的脚本:

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


然后是另一个脚本,该脚本打开了pandas系列的yaml文件:

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


我正在尝试safe_load系列,但出现构造函数错误。如何指定熊猫系列可以安全加载?

最佳答案

使用PyYAML的load时,您指定要加载的YAML文档中的所有内容都是安全的。这就是为什么您需要使用yaml.safe_load的原因。

在您的情况下,这会导致错误,因为safe_load不知道如何构造在YAML文档中具有标签的熊猫内部构件,例如:

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




!!python/tuple


等等

您需要为所有对象提供构造函数,将它们添加到SafeLoader,然后执行a_series = yaml.load(f)
这样做可能需要很多工作,特别是因为对系列中使用的数据进行的微小更改可能需要您添加构造函数。

您可以转储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)

最好使用two step constructor,它允许您构造自引用数据结构。但是Series.append()似乎不适用于此:

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





如果通过字典转储Series不够好(因为它简化了系列数据),并且如果您不关心生成的YAML的可读性,则可以使用.to_dict()代替to_pickle()但您必须使用临时文件,因为该方法不够灵活,无法处理类似对象的文件,并且需要文件名字符串作为参数。

10-07 19:15
查看更多