作为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:
pipe
我已经彻底考虑了这两个问题,所以如果答案可以避免出于一般性的原因,为什么这2个替代方案更好/更安全,我会很感激。
答案 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