在不平衡面板中为每个缺少年份观察值的 ID 添加观察值

Adding observations for each id with missing year observations in unbalanced panel

假设我们正在使用一个看起来像下面数据框的不平衡面板。

df = pd.DataFrame({'id': ['1', '1', '1', '2', '2', '3', '4', '4'], 'Year': [2000, 2001, 2003, 2004, 2005, 2002, 2001, 2003], 'Var': [1, 4, 6, 8, 10, 12, 15, 17]})

print(df)
  id  Year  Var
0  1  2000    1
1  1  2001    4
2  1  2003    6
3  2  2004    8
4  2  2005   10
5  3  2002   12
6  4  2001   15
7  4  2003   17

objective是为不包含连续观察值的id添加变量列为零的行。例如,由于 id =1 有一行报告了 2000、2001 和 2003,我们需要将以下行添加到数据框

df_append = pd.DataFrame({'id':[1], 'Year':[2002], 'Var':[0]})

我们还需要为 id 4 执行此操作。

df_append2 = pd.DataFrame({'id':[4], 'Year':[2002], 'Var':[0]})

然后我们将检索以下数据帧:

  id  Year  Var
0  1  2000    1
1  1  2001    4
2  1  2002    0
3  1  2003    6
4  2  2004    8
5  2  2005   10
6  3  2002   12
7  4  2001   15
8  4  2002   0
9  4  2003   17

正在考虑在 forloop 中执行此操作,但不知道如何检索由缺少观察值的那些组成的 id 和 year 字典。

一个选项是 complete from pyjanitor:

# pip install pyjanitor
import janitor
import pandas as pd
new_year = {'Year':lambda year: range(year.min(), year.max()+1)}

df.complete(new_year, by = 'id', fill_value=0)
Out[79]:
  id  Year  Var
0  1  2000    1
1  1  2001    4
2  1  2002    0
3  1  2003    6
4  2  2004    8
5  2  2005   10
6  3  2002   12
7  4  2001   15
8  4  2002    0
9  4  2003   17

您可以避免使用 pyjanitor 并使用 groupby:

(df
.set_index('Year')
.groupby('id')
.apply(lambda df: df.reindex(range(df.index.min(), 
                                   df.index.max() + 1), 
                             fill_value=0))
.drop(columns='id')
.reset_index()
)

  id  Year  Var
0  1  2000    1
1  1  2001    4
2  1  2002    0
3  1  2003    6
4  2  2004    8
5  2  2005   10
6  3  2002   12
7  4  2001   15
8  4  2002    0
9  4  2003   17