如果我们将日期沿一维对齐,则更容易查看常用值(在索引上)和填充位置(在列上)。我们可以通过pivot_table 做到这一点。 (这里的 value 只是一个占位符,包含所有 1s。)
>>> tab = df.assign(value=1).pivot_table(index='key', columns='date', values='value')
>>> tab
date 20181001 20181003 20181004
key
Hello 1 1 1
No 1 1 1
melt 允许我们进行相反的转换:
>>> tab.reset_index().melt(id_vars='key').drop(columns='value')
key date
0 Hello 20181001
1 No 20181001
2 Hello 20181003
3 No 20181003
4 Hello 20181004
5 No 20181004
所以如果我们想要一个中间步骤来添加缺失的日期,我们应该先将它们转换为日期并使用pd.date_range:
>>> avail_dates = pd.to_datetime(tab.columns, format='%Y%m%d')
>>> avail_dates
DatetimeIndex(['2018-10-01', '2018-10-03', '2018-10-04'], dtype='datetime64[ns]', name='date', freq=None)
>>> all_dates = pd.date_range(avail_dates.min(), avail_dates.max(), freq='D')
>>> tab_filled = tab.reindex(all_dates.strftime('%Y%m%d').astype(int), axis='columns')
>>> tab_filled
20181001 20181002 20181003 20181004
key
Hello 1 NaN 1 1
No 1 NaN 1 1
最后只得到新的列,然后做我们melt的把戏:
>>> missing = tab_filled.drop(columns=tab.columns).reset_index().melt('key').drop(columns=['value'])
>>> missing
key variable
0 Hello 20181002
1 No 20181002
这是一个基于相同原理的较短变体,我们首先构建日期,然后是我们可以melt 的合成数据框:
>>> dates = pd.date_range(
... *pd.to_datetime(df['date'], format='%Y%m%d').agg(['min', 'max']), freq='D'
... ).strftime('%Y%m%d').astype(int)
>>> dates
Int64Index([20181001, 20181002, 20181003, 20181004], dtype='int64')
>>> pd.DataFrame(index=pd.Index(df['key'].unique(), name='key'),
... columns=dates.difference(df['date']))\
... .reset_index().melt('key').drop(columns=['value'])
key variable
0 Hello 20181002
1 No 20181002