在 pandas 或 numpy 中按组在值之间填充 N/A

Fill N/A between values, by group, in pandas or numpy

我有一个 DF 看起来像

df=pd.DataFrame.from_items([('i', [1, 1, 2,2]), ('j', [3, 3, 3,3]), ('t', [20170101, 20170115, 20170108,20170129]), ('x', [1.2, 1.4, 8,8.3])])

>>> df
   i  j          t    x
0  1  3  20170101  1.2
1  1  3  20170115  1.4
2  2  3  20170108  8.0
3  2  3  20170129  8.3

列 i 和 j 标识数据的一个维度(认为人和地点),t 表示 i、j 的另一个维度(时间)。时间频率以 Y、M、D 格式每周一次。 x 列是数据(也可能有包含其他数据等的 y 列)。

我需要做的是为每个 i、j 填写缺失的日期,但根据 DF 中的内容允许不同的开始和结束时间。在此示例中,1,3 缺少 20170108,2,3 缺少 20170115 和 20170122。因此,填写的 DF 应如下所示:

>>> df
   i  j          t    x
0  1  3  20170101  1.2
1  1  3  20170108  N/A
2  1  3  20170115  1.4
3  2  3  20170108  8.0
4  2  3  20170115  N/A
5  2  3  20170122  N/A
6  2  3  20170129  8.3

实际上,更好的方法是将 N/A 替换为周围观测值的平均值,或者可能只是结转最后观测到的 x。后一种情况是这样的

>>> df
   i  j          t    x
0  1  3  20170101  1.2
1  1  3  20170108  1.2
2  1  3  20170115  1.4
3  2  3  20170108  8.0
4  2  3  20170115  8.0
5  2  3  20170122  8.0
6  2  3  20170129  8.3

这似乎是 pd.resample 的更复杂版本,但我不知道如何只在基于 i、j 的观察端点之间进行填充。实际的 DF 非常大(数千万行)。

numpy 中的解决方案也很好。

更新:下面 Scott 的解决方案效果很好。但是,在2000万个obs的样本数据集中,df需要30多分钟才能扩展到3000万行以进行第一次索引重置。

让我们将 DateTimeIndex 与 resample 结合使用。 首先,我们需要将列 t 转换为 datetime dtype 并将列 t 设置为索引。 接下来,我们groupbyresample以每周数据填补空白:

df=pd.DataFrame.from_items([('i', [1, 1, 2,2]), ('j', [3, 3, 3,3]), ('t', [20170101, 20170115, 20170108,20170129]), ('x', [1.2, 1.4, 8,8.3])])
df['t'] = pd.to_datetime(df.t, format=('%Y%m%d')) 

中间输出:

df.set_index('t').groupby(['i','j'])['x'].resample('W').asfreq().reset_index()

   i  j          t    x
0  1  3 2017-01-01  1.2
1  1  3 2017-01-08  NaN
2  1  3 2017-01-15  1.4
3  2  3 2017-01-08  8.0
4  2  3 2017-01-15  NaN
5  2  3 2017-01-22  NaN
6  2  3 2017-01-29  8.3

然后你可以使用 ffilldt.strftime 得到你的最终输出:

df = df.set_index('t').groupby(['i','j'])['x'].resample('W').ffill().reset_index()
df['t'] = df['t'].dt.strftime('%Y%m%d)

最终输出:

   i  j         t    x
0  1  3  20170101  1.2
1  1  3  20170108  1.2
2  1  3  20170115  1.4
3  2  3  20170108  8.0
4  2  3  20170115  8.0
5  2  3  20170122  8.0
6  2  3  20170129  8.3