如何pickle numpy MaskedArray子类

时间:2013-12-29 23:25:33

标签: python numpy pickle

我无法让NumPy MaskedArray子类通过pickle往返并保留额外的子类属性。这是一个例子:

import numpy as np
import cPickle as pickle
from numpy import ma


class SubArray(np.ndarray):
    """Defines a generic np.ndarray subclass, that stores some metadata
    in the  dictionary `info`."""
    def __new__(cls, arr, info={}):
        x = np.asanyarray(arr).view(cls)
        x.info = info
        return x

    def __array_finalize__(self, obj):
        self.info = getattr(obj, 'info', {'ATTR': 'MISSING'})
        return


class MSubArray(SubArray, ma.MaskedArray):
    def __new__(cls, data, info={}, mask=ma.nomask, dtype=None):
        subarr = SubArray(data, info)
        _data = ma.MaskedArray.__new__(cls, data=subarr, mask=mask, dtype=dtype)
        _data.info = subarr.info
        return _data

    def __array_finalize__(self, obj):
        ma.MaskedArray.__array_finalize__(self, obj)
        SubArray.__array_finalize__(self, obj)
        return

ms = MSubArray([1, 2], info={'a': 1})
print('Pre-pickle:', ms.info, ms.data.info)

pkl = pickle.dumps(ms)
ms_from_pkl = pickle.loads(pkl)
print('Post-pickle:', ms_from_pkl.info, ms_from_pkl.data.info)

这会产生:

Pre-pickle: {'a': 1} {'a': 1}
Post-pickle: {} {}

任何关于我做错的提示都会非常感激!

1 个答案:

答案 0 :(得分:1)

看看:https://mail.python.org/pipermail/python-list/2011-April/601275.html

你遇到的问题是腌制C扩展类型(ndarray子类型)的结果。我不是numpy数组内部工作的专家,但我猜测那里的代码可以手动处理酸洗numpy数据。由于您的SubArray类是ndarray的子​​类,因此您需要覆盖numpy使用的酸洗方法。

所以,AFAIK你的选择是:

  1. 在pickle.dumps和pickle.loads上放一个垫片(在它进入C级之前)
  2. 更新numpy酸洗方法,以便检查子类。
  3. 创建object的所有类子类,并让它们包含您需要能够挑选/取消选择的相应数据。
  4. 如果你要坚持使用pickle进行转储和加载数据,那么选项#3就是我的选择。 pickle模块的设计考虑了纯python对象,而不是扩展类型。