python – 通过连接传播pandas系列元数据

我希望能够将元数据附加到一系列数据帧(特别是原始文件名),以便在连接两个数据帧后,我可以看到每个系列来自哪里的元数据.

我看到有关_Metadata(here,here)的github问题,包括一些与当前_Metadata属性(here)相关的问题,但在pandas文档中没有任何内容.

到目前为止,我可以修改_Metadata属性以允许保留元数据,但在连接后获取AttributeError.

df1 = pd.DataFrame(np.random.randint(0, 4, (6, 3)))
df2 = pd.DataFrame(np.random.randint(0, 4, (6, 3)))
df1._Metadata.append('filename')
df1[df1.columns[0]]._Metadata.append('filename')

for c in df1:
    df1[c].filename = 'fname1.csv'
    df2[c].filename = 'fname2.csv'

df1[0]._Metadata  # ['name', 'filename']
df1[0].filename  # fname1.csv
df2[0].filename  # fname2.csv
df1[0][:3].filename  # fname1.csv

mgd = pd.merge(df1, df2, on=[0])
mgd['1_x']._Metadata  # ['name', 'filename']
mgd['1_x'].filename  # raises AttributeError

有什么方法可以保留这个?

更新:结语

正如here所讨论的那样,__ finalize__无法跟踪作为数据帧成员的Series,只能跟踪独立序列.因此,现在我将通过维护附加到数据帧的元数据字典来跟踪系列级元数据.我的代码看起来像:

def cust_merge(d1, d2):
    "Custom merge function for 2 dicts"
    ...

def finalize_df(self, other, method=None, **kwargs):
    for name in self._Metadata:
        if method == 'merge':
            lMeta = getattr(other.left, name, {})
            rMeta = getattr(other.right, name, {})
            newMeta = cust_merge(lMeta, rMeta)
            object.__setattr__(self, name, newMeta)
        else:
            object.__setattr__(self, name, getattr(other, name, None))
    return self

df1.filenames = {c: 'fname1.csv' for c in df1}
df2.filenames = {c: 'fname2.csv' for c in df2}
pd.DataFrame._Metadata = ['filenames']
pd.DataFrame.__finalize__ = finalize_df

解决方法:

我觉得这样的东西会起作用(如果不是这样的话,请提交一个bug报告,虽然支持它有点混淆边缘,但是有可能连接方法不会一直调用它.这有点未经测试).

有关更详细的示例/错误修复,请参阅此issue.

DataFrame._Metadata = ['name','filename']


def __finalize__(self, other, method=None, **kwargs):
    """
    propagate Metadata from other to self

    Parameters
    ----------
    other : the object from which to get the attributes that we are going
        to propagate
    method : optional, a passed method name ; possibly to take different
        types of propagation actions based on this

    """

    ### you need to arbitrate when their are conflicts

    for name in self._Metadata:
        object.__setattr__(self, name, getattr(other, name, None))
    return self

    DataFrame.__finalize__ = __finalize__

因此,这将替换DataFrame的认终结器与您的自定义终结器.在我指出的地方,您需要放置一些可以在冲突之间进行仲裁的代码.这是认情况下不会这样做的原因,例如frame1的名称为’foo’,frame2的名称为’bar’,当方法为__add__时你会怎么做,另一种方法怎么办?让我们知道您的工作以及工作原理.

这只是替换DataFrame(如果你愿意,你可以简单地执行认操作),这是为了自我传播;除特殊情况下,你也不能设置任何东西.

如果是子类,这个方法应该被覆盖,这就是你在这里进行猴子修补的原因(而不是大多数时候过度杀戮的子分类).

相关文章

转载:一文讲述Pandas库的数据读取、数据获取、数据拼接、数...
Pandas是一个开源的第三方Python库,从Numpy和Matplotlib的基...
整体流程登录天池在线编程环境导入pandas和xrld操作EXCEL文件...
 一、numpy小结             二、pandas2.1为...
1、时间偏移DateOffset对象DateOffset类似于时间差Timedelta...
1、pandas内置样式空值高亮highlight_null最大最小值高亮背景...