pandas 重新索引缺失日期

pandas re-indexing with missing dates

from dateutil.rrule import rrule, MONTHLY

def fread_year_month(strt_dt, end_dt):
        dates = [dt for dt in rrule(MONTHLY, dtstart=strt_dt, until=end_dt)]
        return dates

df = pd.DataFrame({
'value' : [4,2,5,6,7,8,6,5,4,1,2,4],
'date': fread_year_month(dt.datetime(2015, 1, 1),dt.datetime(2015, 12, 1)),
'stock': ['amzn']*12
},columns=[
'value', 'date', 'stock'] )

df2 = pd.DataFrame({
'value' : [1,1,1,1,1],
'date': fread_year_month(dt.datetime(2015, 1, 1),dt.datetime(2015, 5, 1)),
'stock': ['msft']*5
},columns=[
'value', 'date', 'stock'] )

df = df.append(df2)

df.set_index(['stock', 'date'], inplace=True)

我有上面的 pandas 数据框。如您所见,amzn 的可用数据数量与 msft 不同。在此示例中,日期是连续的,但不必如此(日期可以是任何日期)。

如果可用日期的范围是我拥有 AMZN 数据的日期,那么我如何为我的数据框中的所有其他股票添加这些确切日期,其中包含 NaN 或 NA。

在示例中,我想在索引中插入 msft 缺失的日期,并为这些日期索引的值插入 NaN 或 NA。

如果您想将代码作为列使用,可以执行 unstack,如下所示:

In [71]: df.unstack(level=0)
Out[71]: 
           value     
stock       amzn msft
date                 
2015-01-01   4.0  1.0
2015-02-01   2.0  1.0
2015-03-01   5.0  1.0
2015-04-01   6.0  1.0
2015-05-01   7.0  1.0
2015-06-01   8.0  NaN
2015-07-01   6.0  NaN
2015-08-01   5.0  NaN
2015-09-01   4.0  NaN
2015-10-01   1.0  NaN
2015-11-01   2.0  NaN
2015-12-01   4.0  NaN

为了重新索引到相同的形状,下面的 from_product 创建了一个新的 MultiIndex,其中包含日期/代码的所有组合。

In [75]: df.reindex(pd.MultiIndex.from_product(df.index.levels))
Out[75]: 
                 value
amzn 2015-01-01    4.0
     2015-02-01    2.0
     2015-03-01    5.0
     2015-04-01    6.0
     2015-05-01    7.0
     2015-06-01    8.0
     2015-07-01    6.0
     2015-08-01    5.0
     2015-09-01    4.0
     2015-10-01    1.0
     2015-11-01    2.0
     2015-12-01    4.0
msft 2015-01-01    1.0
     2015-02-01    1.0
     2015-03-01    1.0
     2015-04-01    1.0
     2015-05-01    1.0
     2015-06-01    NaN
     2015-07-01    NaN
     2015-08-01    NaN
     2015-09-01    NaN
     2015-10-01    NaN
     2015-11-01    NaN
     2015-12-01    NaN

在合并之前,您可以这样做(从 Pandas 0.17 开始):

>>> df2.set_index('date').reindex(df.date)
            value stock
date                   
2015-01-01      1  msft
2015-02-01      1  msft
2015-03-01      1  msft
2015-04-01      1  msft
2015-05-01      1  msft
2015-06-01    NaN   NaN
2015-07-01    NaN   NaN
2015-08-01    NaN   NaN
2015-09-01    NaN   NaN
2015-10-01    NaN   NaN
2015-11-01    NaN   NaN
2015-12-01    NaN   NaN