【问题标题】:Adding rows for missing year by group in pandas在熊猫中按组添加缺失年份的行
【发布时间】:2020-12-06 18:32:12
【问题描述】:

我有一个看起来像这样的数据框

pd.DataFrame({'A': ['C1', 'C1', 'C1', 'C1', 'C2', 'C2', 'C3', 'C3'],
   ...:                    'date': [date(2019, 12, 31), date(2018, 12, 31), date(2017, 12, 31), date(2016, 12, 31), date(2017, 12, 31), date(2016, 12, 31), date(2018, 12, 31), date(2016, 12, 31)],
   ...:                    'value': [9, 9, 8, 4, 8, 3, 6, 4]})
Out[13]: 
    A        date  value
0  C1  2019-12-31      9
1  C1  2018-12-31      9
2  C1  2017-12-31      8
3  C1  2016-12-31      4
4  C2  2017-12-31      8
5  C2  2016-12-31      3
6  C3  2018-12-31      6
7  C3  2016-12-31      4

first_year = date(2016, 12, 31)
last_year = date(2019, 12, 31)

对于每个组,我需要在“A”列中为每个组添加缺失的年份,并取上一年的“值”。我想通过输入变量说我的第一年和最后一年应该是什么。我生成的数据框应该是这样的

     A        date  value
 0  C1  2019-12-31      9
 1  C1  2018-12-31      9
 2  C1  2017-12-31      8
 3  C1  2016-12-31      4
 4  C2  2019-12-31      8
 5  C2  2018-12-31      8
 6  C2  2017-12-31      8
 7  C2  2016-12-31      3
 8  C3  2019-12-31      6
 9  C3  2018-12-31      6
10  C3  2017-12-31      4
11  C3  2016-12-31      4

以下逻辑适用(按 A 列中的组)

C1 = 2016 年至 2019 年之间的所有年份均已可用

C2 = 缺少 2018 年和 2019 年,需要添加并从 2017 年的最后一个可用年份获取值 = 8

C3 = 缺少 2017 年,从 2016 年获取值。缺少 2019 年,从 2018 年获取值

【问题讨论】:

    标签: python pandas pandas-groupby


    【解决方案1】:

    使用groupby + groupby.applyreindex + ffill 的另一个可能的想法:

    i = pd.date_range(first_year, last_year, freq='Y', name='date')
    df = df.set_index('date').groupby('A',group_keys=False)\
           .apply(lambda s: s.reindex(i).ffill()).reset_index()
    

    结果:

             date   A  value
    0  2016-12-31  C1    4.0
    1  2017-12-31  C1    8.0
    2  2018-12-31  C1    9.0
    3  2019-12-31  C1    9.0
    4  2016-12-31  C2    3.0
    5  2017-12-31  C2    8.0
    6  2018-12-31  C2    8.0
    7  2019-12-31  C2    8.0
    8  2016-12-31  C3    4.0
    9  2017-12-31  C3    4.0
    10 2018-12-31  C3    6.0
    11 2019-12-31  C3    6.0
    

    【讨论】:

      【解决方案2】:

      IIUC,你可以这样做:

      idx = pd.MultiIndex.from_product([df['A'].unique(), 
                                        pd.date_range(first_year, 
                                                      last_year, 
                                                      freq='A')], 
                                       names=['A','date'])
      
      df.set_index(['A','date'])\
        .reindex(idx)\
        .groupby(level=0)\
        .ffill()\
        .sort_index(level=[0,1], ascending=[True, False])\
        .reset_index()
      

      输出:

           A       date  value
      0   C1 2019-12-31    9.0
      1   C1 2018-12-31    9.0
      2   C1 2017-12-31    8.0
      3   C1 2016-12-31    4.0
      4   C2 2019-12-31    8.0
      5   C2 2018-12-31    8.0
      6   C2 2017-12-31    8.0
      7   C2 2016-12-31    3.0
      8   C3 2019-12-31    6.0
      9   C3 2018-12-31    6.0
      10  C3 2017-12-31    4.0
      11  C3 2016-12-31    4.0
      

      使用pd.MultiIndex.from_product 创建您的“A”和日期范围的产品。使用该索引,使用从产品创建的索引设置或您的数据框和reindex 的索引。最后,ffill 前向填充并使用数据框,然后是 reset_index

      【讨论】:

      • 我认为在使用 ffill 之前,我们需要在 level=0 上使用 groupby
      • @ShubhamSharma 您正确地防止填充“A”级别。好点。我刚从电话桌旁走开。欢迎您测试和编辑。如果你愿意。
      • 已编辑,实际上我也在考虑类似的答案:),顺便说一句,答案不错 +1。
      猜你喜欢
      • 1970-01-01
      • 2017-10-03
      • 1970-01-01
      • 1970-01-01
      • 2022-09-23
      • 2018-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多