在不改变原始对象的情况下对DataFrame进行子类化

时间:2017-12-19 01:43:19

标签: python python-3.x pandas inheritance

作为mentioned a while back by @piRSquared,按照文档中建议的方式或geopandas' GeoDataFrame对pandas DataFrame进行子类化,可能会导致原始对象发生意外突变:

class SubFrame(pd.DataFrame):

    def __init__(self, *args, **kwargs):
        attr = kwargs.pop('attr', None)
        super(SubFrame, self).__init__(*args, **kwargs)
        self.attr = attr

    @property
    def _constructor(self):
        return SubFrame

    def somefunc(self):
        """Add some extended functionality."""
        pass

df = pd.DataFrame([[1, 2], [3, 4]])
sf = SubFrame(df, attr=1)

sf[:] = np.nan  # Modifies `df`
print(df)

#     0   1
# 0 NaN NaN
# 1 NaN NaN

容易出错的“修复”是在实例化时传递副本:

sf = SubFrame(df.copy(), attr=1)

但这很容易受到用户错误的影响。 我的问题是:我可以在self内创建class SubFrame(传递的DataFrame)的副本吗?  我该怎么做呢?

如果答案是“不”,我也很感激,所以我可以在浪费时间之前废弃这项努力。

礼貌请求

pandas docs suggest two alternatives

  1. pipe
  2. 的可扩展方法链
  3. 组合物
  4. 我已经彻底考虑了这两个问题,所以如果答案可以避免出于一般性的原因,为什么这2个替代方案更好/更安全,我会很感激。

1 个答案:

答案 0 :(得分:1)

Self不是您传递的数据帧。无论如何,您可以在init函数中执行复制。

例如

import copy

def __init__(self, farg, **kwargs):
    farg = copy.deepcopy(farg)
    attr = kwargs.pop('attr', None)
    super().__init__(farg)
    self.attr = attr

应该告诉你farg是你传递的df。

我不太了解子类化DataFrame,所以如果你想保留原始的 init 结构,你可以复制所有的* args。无法说明这种方法的安全性。

def __init__(self, *args, **kwargs):
    cargs = tuple(copy.deepcopy(arg) for arg in args)
    attr = kwargs.pop('attr', None)
    super().__init__(*cargs, **kwargs)
    self.attr = attr