Pandas:使用 groupby 中的日期重新索引,filling/maintaining 值视情况而定

Pandas: reindex with dates in groupby, filling/maintaining values as appropriate

我有以下数据框。

>>> df = pd.DataFrame(data={'date': ['2010-05-01', '2010-07-01', '2010-06-01', '2010-10-01'], 'id': [1,1,2,2], 'val': [50,60,70,80], 'other': ['uno', 'uno', 'dos', 'dos']})
>>> df['date'] = df['date'].apply(lambda d: pd.to_datetime(d))
>>> df
        date  id other  val
0 2010-05-01   1   uno   50
1 2010-07-01   1   uno   60
2 2010-06-01   2   dos   70
3 2010-10-01   2   dos   80

我想扩展此 DataFrame,使其包含 2010 年所有月份的行。

我想要的结果如下:

         date  id other  val
0  2010-01-01   1   uno    0
1  2010-02-01   1   uno    0
2  2010-03-01   1   uno    0
3  2010-04-01   1   uno    0
4  2010-05-01   1   uno    50
5  2010-06-01   1   uno    0
6  2010-07-01   1   uno    60
7  2010-08-01   1   uno    0
8  2010-09-01   1   uno    0
9  2010-10-01   1   uno    0
10 2010-11-01   1   uno    0
11 2010-12-01   1   uno    0
12 2010-01-01   2   dos    0
13 2010-02-01   2   dos    0
14 2010-03-01   2   dos    0
15 2010-04-01   2   dos    0
16 2010-05-01   2   dos    0
17 2010-06-01   2   dos    70
18 2010-07-01   2   dos    0
19 2010-08-01   2   dos    0
20 2010-09-01   2   dos    0
21 2010-10-01   2   dos    80
22 2010-11-01   2   dos    0
23 2010-12-01   2   dos    0

我尝试过的:

我试过groupby('id'),然后申请。应用的函数重新索引该组。但是我还没有设法既用零填充 val 又保持 other.

您可以通过自定义函数使用 groupbyreindex 并填充 NaNs - 在 otherffillbfill (向前和向后填充)和在 val 中通过 fillna 通过常量:

def f(x):
    x = x.reindex(pd.date_range('2010-01-01', '2010-12-01', freq='MS'))
    x['other'] = x['other'].ffill().bfill()
    x['val'] = x['val'].fillna(0)
    return (x)


df = df.set_index('date')
       .groupby('id')
       .apply(f).rename_axis(('id','date'))
       .drop('id', 1).reset_index()

print (df)
    id       date other   val
0    1 2010-01-01   uno   0.0
1    1 2010-02-01   uno   0.0
2    1 2010-03-01   uno   0.0
3    1 2010-04-01   uno   0.0
4    1 2010-05-01   uno  50.0
5    1 2010-06-01   uno   0.0
6    1 2010-07-01   uno  60.0
7    1 2010-08-01   uno   0.0
8    1 2010-09-01   uno   0.0
9    1 2010-10-01   uno   0.0
10   1 2010-11-01   uno   0.0
11   1 2010-12-01   uno   0.0
12   2 2010-01-01   dos   0.0
13   2 2010-02-01   dos   0.0
14   2 2010-03-01   dos   0.0
15   2 2010-04-01   dos   0.0
16   2 2010-05-01   dos   0.0
17   2 2010-06-01   dos  70.0
18   2 2010-07-01   dos   0.0
19   2 2010-08-01   dos   0.0
20   2 2010-09-01   dos   0.0
21   2 2010-10-01   dos  80.0
22   2 2010-11-01   dos   0.0
23   2 2010-12-01   dos   0.0

另一个解决方案是创建 MultiIndex.from_product 并通过它重建索引:

mux = pd.MultiIndex.from_product([df['id'].unique(),
                                  pd.date_range('2010-01-01', '2010-12-01', freq='MS')], 
                                  names=('id','date'))

df = df.set_index(['id','date']).reindex(mux).reset_index()
df['val'] = df['val'].fillna(0)
df['other'] = df.groupby('id')['other'].apply(lambda x: x.ffill().bfill())

print (df)
    id       date other   val
0    1 2010-01-01   uno   0.0
1    1 2010-02-01   uno   0.0
2    1 2010-03-01   uno   0.0
3    1 2010-04-01   uno   0.0
4    1 2010-05-01   uno  50.0
5    1 2010-06-01   uno   0.0
6    1 2010-07-01   uno  60.0
7    1 2010-08-01   uno   0.0
8    1 2010-09-01   uno   0.0
9    1 2010-10-01   uno   0.0
10   1 2010-11-01   uno   0.0
11   1 2010-12-01   uno   0.0
12   2 2010-01-01   dos   0.0
13   2 2010-02-01   dos   0.0
14   2 2010-03-01   dos   0.0
15   2 2010-04-01   dos   0.0
16   2 2010-05-01   dos   0.0
17   2 2010-06-01   dos  70.0
18   2 2010-07-01   dos   0.0
19   2 2010-08-01   dos   0.0
20   2 2010-09-01   dos   0.0
21   2 2010-10-01   dos  80.0
22   2 2010-11-01   dos   0.0
23   2 2010-12-01   dos   0.0