Python 按组添加熊猫中缺失年份的行
我有一个像这样的数据框Python 按组添加熊猫中缺失年份的行,python,pandas,pandas-groupby,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
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 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”列中添加每个组缺少的年份,并取上一年的“值”。我想通过输入变量说明我的第一年和最后一年应该是什么。生成的数据帧应该如下所示
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 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年获得价值,你可以这样做:
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”和日期范围的产品。使用该索引,设置或您的数据帧的索引,并使用从产品创建的索引重新索引。最后,F向前填充数据帧,然后重置索引。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”和日期范围的产品。使用该索引,设置或您的数据帧的索引,并使用从产品创建的索引重新索引。最后,ffill向前填充并使用数据帧,然后重置索引。使用groupby+groupby.apply和reindex+ffill的另一个可能想法: 结果:
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
使用groupby+groupby.apply和reindex+ffill的另一个可能的想法是: 结果:
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
我认为在使用ffill之前,我们需要级别为0的groupby。@ShubhamSharma您正确地阻止了跨“A”级别的填充。很好。我刚在电话里离开办公桌。欢迎您进行测试和编辑。如果您愿意。编辑,实际上我也在考虑类似的答案:,顺便说一句,答案很好+1。我认为在使用ffill之前,我们需要级别为0的groupby。@ShubhamSharma您正确地阻止跨“A”级别填充。很好。我刚在电话里离开办公桌。欢迎您进行测试和编辑。如果你愿意。编辑,实际上我也在考虑类似的答案:,顺便说一句,不错的答案+1。