【问题标题】:Reindexing and filling on one level of a hierarchical index in pandas在 pandas 的层次索引的一级上重新索引和填充
【发布时间】:2013-10-22 23:15:24
【问题描述】:

我有一个带有两级分层索引(“item_id”和“日期”)的 pandas 数据框。每行都有特定月份中特定项目的各种指标的列。这是一个示例:

                    total_annotations  unique_tags
date       item_id
2007-04-01 2                       30           14
2007-05-01 2                       32           16
2007-06-01 2                       36           19
2008-07-01 2                       81           33
2008-11-01 2                       82           34
2009-04-01 2                       84           35
2010-03-01 2                       90           35
2010-04-01 2                      100           36
2010-11-01 2                      105           40
2011-05-01 2                      106           40
2011-07-01 2                      108           42
2005-08-01 3                      479          200
2005-09-01 3                      707          269
2005-10-01 3                      980          327
2005-11-01 3                     1176          373
2005-12-01 3                     1536          438
2006-01-01 3                     1854          497
2006-02-01 3                     2206          560
2006-03-01 3                     2558          632
2007-02-01 3                     5650         1019

如您所见,每个项目的所有连续月份都没有观测值。我想要做的是重新索引数据框,以便每个项目在指定范围内都有每个月的行。现在,对于任何给定的项目,这很容易实现。所以,以 item_id 99 为例:

baseDateRange = pd.date_range('2005-07-01','2013-01-01',freq='MS')
data.xs(99,level='item_id').reindex(baseDateRange,method='ffill')

但是使用这种方法,我必须遍历所有 item_id,然后将所有内容合并在一起,这似乎过于复杂了。

那么我如何将其应用于完整的数据框,填充观察结果(还有 item_id 索引),以便每个 item_id 都正确填充了 baseDateRange 中所有日期的行?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    基本上针对您要重新索引和填充的每个组。应用程序传递了一个数据框,其中 item_id 和日期仍在索引中,因此重置,然后设置并重新索引填充。 idx 是上面的 baseDateRange。

    In [33]: df.groupby(level='item_id').apply(
          lambda x: x.reset_index().set_index('date').reindex(idx,method='ffill')).head(30)
    Out[33]: 
                        item_id  annotations  tags
    item_id                                       
    2       2005-07-01      NaN          NaN   NaN
            2005-08-01      NaN          NaN   NaN
            2005-09-01      NaN          NaN   NaN
            2005-10-01      NaN          NaN   NaN
            2005-11-01      NaN          NaN   NaN
            2005-12-01      NaN          NaN   NaN
            2006-01-01      NaN          NaN   NaN
            2006-02-01      NaN          NaN   NaN
            2006-03-01      NaN          NaN   NaN
            2006-04-01      NaN          NaN   NaN
            2006-05-01      NaN          NaN   NaN
            2006-06-01      NaN          NaN   NaN
            2006-07-01      NaN          NaN   NaN
            2006-08-01      NaN          NaN   NaN
            2006-09-01      NaN          NaN   NaN
            2006-10-01      NaN          NaN   NaN
            2006-11-01      NaN          NaN   NaN
            2006-12-01      NaN          NaN   NaN
            2007-01-01      NaN          NaN   NaN
            2007-02-01      NaN          NaN   NaN
            2007-03-01      NaN          NaN   NaN
            2007-04-01        2           30    14
            2007-05-01        2           32    16
            2007-06-01        2           36    19
            2007-07-01        2           36    19
            2007-08-01        2           36    19
            2007-09-01        2           36    19
            2007-10-01        2           36    19
            2007-11-01        2           36    19
            2007-12-01        2           36    19
    

    【讨论】:

    • 太棒了,但有两个澄清:首先,当你这样做时,我在 item_id 索引顶部留下了一个多余的 item_id 列。但是,看来我可以通过将您的代码修改为df.groupby(level='item_id').apply(lambda x: x.reset_index(level='item_id',drop=True).reset_index().set_index('date').reindex(idx,method='ffill')) 来解决这个问题。这看起来合理吗?第二:为什么日期不再像原始数据框中那样在标头中显示为索引?我不认为这是一个问题,但你能解释一下发生了什么吗?数据框是否仍然具有分层索引或...?
    • 对您的第一部分的回答是肯定的,这是合理的,您可以放弃 reset_index 以不进行重复。其次,我认为由于您聚合的方式,应用对索引有点困惑(因此它正在删除索引的名称)。你可以在apply里面再做一个reset_index,然后在最后(apply之后.reset_index(drop=True).set_index(['date','item_id']),所以reset mi
    • 嗯...这实际上似乎不起作用(我认为日期索引适用于每个组,因此无法作为实际数据帧的索引访问)。但我认为这无论如何都有效。谢谢。
    【解决方案2】:

    根据 Jeff 的回答,我认为这更具可读性。由于只使用了 droplevel 和 reindex 方法,因此效率也大大提高。

    df = df.set_index(['item_id', 'date'])
    
    def fill_missing_dates(x, idx=all_dates):
       x.index = x.index.droplevel('item_id')
       return x.reindex(idx, method='ffill')
    
    
    filled_df = (df.groupby('item_id')
                   .apply(fill_missing_dates))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-17
      • 1970-01-01
      • 2016-11-30
      • 1970-01-01
      • 2018-04-17
      • 1970-01-01
      • 2017-12-22
      • 2021-08-27
      相关资源
      最近更新 更多