Pandas 在数据帧中识别组之间的差异

Pandas 在数据帧中识别组之间的差异,pandas,dataframe,array-difference,Pandas,Dataframe,Array Difference,我有一个按日期和ID索引的熊猫数据框。我想: 标识日期之间添加和删除的ID 将ID添加到另一个带有添加/删除日期的数据框中 期望输出: date ID flag 1/31/2011 22 addition 1/31/2011 11 addition 1/31/2011 2 deletion 1/31/2011 4 deletion 我试过了。我无法让它在分组数据帧上工作。我不确定如何循环每个组,并与前一组进行比较。您可以使用duplicated,找

我有一个按日期和ID索引的熊猫数据框。我想:

  • 标识日期之间添加和删除的ID
  • 将ID添加到另一个带有添加/删除日期的数据框中
  • 期望输出:

    date        ID  flag
    1/31/2011   22  addition
    1/31/2011   11  addition
    1/31/2011   2   deletion
    1/31/2011   4   deletion
    

    我试过了。我无法让它在分组数据帧上工作。我不确定如何循环每个组,并与前一组进行比较。

    您可以使用
    duplicated
    ,找到不同的值

    s=df[~df.index.get_level_values(1).duplicated(keep=False)]
    pd.DataFrame({'date':['1/31/2011']*len(s),'ID':s.index.get_level_values(1),'flag':(s.index.get_level_values(0)=='1/31/2011')}).replace({False:'deletion',True:'addition'})
    Out[529]: 
       ID       date      flag
    0   2  1/31/2011  deletion
    1   4  1/31/2011  deletion
    2  22  1/31/2011  addition
    3  11  1/31/2011  addition
    

    我创建了一个helper函数,它可以移动pandas.MultiIndex的第一级。有了这个,我可以将它与原始索引进行区别,以确定添加和删除

    def shift_level(idx):
        level = idx.levels[0]
        mapping = dict(zip(level[:-1], level[1:]))
        idx = idx.set_levels(level.map(mapping.get), 0)
        return idx[idx.get_level_values(0).notna()].remove_unused_levels()
    
    idx = df.index
    fidx = shift_level(idx)
    
    additions = fidx.difference(idx)
    deletions = idx[idx.labels[0] > 0].difference(fidx)
    
    pd.Series('+', additions).append(
        pd.Series('-', deletions)).rename('flag').reset_index()
    
            date  ID flag
    0 2011-01-31   2    +
    1 2011-01-31   4    +
    2 2011-01-31  11    -
    3 2011-01-31  22    -
    

    非常感谢。代码
    s=df[~df.index.get_level_values(1).duplicated(keep=False)]
    有效。但是,我如何循环几个日期,即数据框中的100个组?工作!唯一值得一提的是,您的解决方案中添加的内容将添加到上个月(2010年12月31日),而不是添加的月份(2011年1月31日)。但我可以考虑修改。这很好,而且比我预期的还要复杂。我对pandas很陌生,很惊讶它没有一个本地的方法来比较索引级别/组。有其他方法可以通过取消堆叠和移动来做到这一点。但是,如果您最终得到了任何规模较大的数据帧,那么从性能的角度来看,这应该保持稳定。
    def shift_level(idx):
        level = idx.levels[0]
        mapping = dict(zip(level[:-1], level[1:]))
        idx = idx.set_levels(level.map(mapping.get), 0)
        return idx[idx.get_level_values(0).notna()].remove_unused_levels()
    
    idx = df.index
    fidx = shift_level(idx)
    
    additions = fidx.difference(idx)
    deletions = idx[idx.labels[0] > 0].difference(fidx)
    
    pd.Series('+', additions).append(
        pd.Series('-', deletions)).rename('flag').reset_index()
    
            date  ID flag
    0 2011-01-31   2    +
    1 2011-01-31   4    +
    2 2011-01-31  11    -
    3 2011-01-31  22    -