在熊猫中按组添加缺少年份的行

时间:2020-08-17 15:28:06

标签: python pandas pandas-groupby

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

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年获得价值

2 个答案:

答案 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

答案 1 :(得分:2)

使用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