我有以下熊猫数据帧:
df = pd.DataFrame([
['A', 2017, 1],
['A', 2019, 1],
['B', 2017, 1],
['B', 2018, 1],
['C', 2016, 1],
['C', 2019, 1],
], columns=['ID', 'year', 'number'])
并且正在寻找最有效的方法来使用number
列的默认值0来填充缺少的年份
预期输出为:
ID year number
0 A 2017 1
1 A 2018 0
2 A 2019 1
3 B 2017 1
4 B 2018 1
5 C 2016 1
6 C 2017 0
7 C 2018 0
8 C 2019 1
数据帧,我有比较大,所以我正在寻找一个高效的解决方案。
编辑:
这是我到目前为止得到的代码:
min_max_dict = df[['ID', 'year']].groupby('ID').agg([min, max]).to_dict('index')
new_ix = [[], []]
for id_ in df['ID'].unique():
for year in range(min_max_dict[id_][('year', 'min')], min_max_dict[id_][('year', 'max')]+1):
new_ix[0].append(id_)
new_ix[1].append(year)
df.set_index(['ID', 'year'], inplace=True)
df = df.reindex(new_ix, fill_value=0).reset_index()
结果
ID year number
0 A 2017 1
1 A 2018 0
2 A 2019 1
3 B 2017 1
4 B 2018 1
5 C 2016 1
6 C 2017 0
7 C 2018 0
8 C 2019 1
比使用explode
稍快的方法是使用pd.series构造函数。 如果年份已经从最早到最晚排序,则可以使用。iloc。
idx = df.groupby('ID')['year'].apply(lambda x: pd.Series(np.arange(x.iloc[0], x.iloc[-1]+1))).reset_index()
df.set_index(['ID','year']).reindex(pd.MultiIndex.from_arrays([idx['ID'], idx['year']]), fill_value=0).reset_index()
输出:
ID year number
0 A 2017 1
1 A 2018 0
2 A 2019 1
3 B 2017 1
4 B 2018 1
5 C 2016 1
6 C 2017 0
7 C 2018 0
8 C 2019 1
下面是另一种使用reindex
的方法
u = df.groupby('ID')['year'].apply(lambda x: range(x.min(),x.max()+1)).explode()
out = (df.set_index(['ID','year']).reindex(u.reset_index().to_numpy(),fill_value=0)
.reset_index())
ID year number
0 A 2017 1
1 A 2018 0
2 A 2019 1
3 B 2017 1
4 B 2018 1
5 C 2016 1
6 C 2017 0
7 C 2018 0
8 C 2019 1
t = df.groupby('ID')['year'].agg(['min','max']).reset_index()
t['missing'] = t.transform(lambda x: [y for y in range(x['min'], x['max']+1) if y not in x.values], axis=1)
t = t[['ID','missing']].explode('missing').dropna()
t['number'] = 0
t.columns = ['ID','year','number']
pd.concat([df,t]).sort_values(by=['ID','year'])
输出量
ID year number
0 A 2017 1
0 A 2018 0
1 A 2019 1
2 B 2017 1
3 B 2018 1
4 C 2016 1
2 C 2017 0
2 C 2018 0
5 C 2019 1