Python 制作熊猫系列安全YAML

Python 制作熊猫系列安全YAML,python,pandas,yaml,pyyaml,Python,Pandas,Yaml,Pyyaml,我正在使用一个脚本将pandas系列转储到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) 我试图安全加载该系列,但我得到了一个构造函数错误。如何指定pandas系列可以安全加载?当您使用PyYAML的加载时,您可以指定正在加载的YAML文档中的所有内

我正在使用一个脚本将pandas系列转储到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)

我试图安全加载该系列,但我得到了一个构造函数错误。如何指定pandas系列可以安全加载?

当您使用PyYAML的
加载时,您可以指定正在加载的YAML文档中的所有内容都是安全的。这就是为什么需要使用
yaml.safe\u load

在您的情况下,这会导致一个错误,因为
safe\u load
不知道如何构造在YAML文档中具有标记的内部构件,如:

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

等等

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

您可以转储
系列
的dict表示并将其加载回去。当然,在这个过程中会丢失一些信息,我不确定这是否可以接受:

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'>
有几件事需要注意:

  • 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)))
    


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

Ok,所以在转储/加载之前最好将内容分解为基本数据类型?谢谢你的详尽回答。@big11mac不一定。将YAML与标记一起使用需要一些努力,但是从您的文档中可以清楚地看到,这些标记应该作为特殊类型加载。如果分解数据并仅另存为原语(映射、序列、标量),则加载后重新创建适当类型的所有逻辑都必须在程序中。如果您的数据结构是可预测的、平坦的(即没有任意的树结构),并且不会太大而无法在内存中容纳两次,则可以选择不使用标记。
yaml.safe_load(data, stream)
def series_constructor(loader, node):
    d = Series()
    yield d
    d.append(Series(loader.construct_mapping(node)))