在 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 设置为索引。
接下来,我们groupby
和resample
以每周数据填补空白:
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
然后你可以使用 ffill
和 dt.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
我有一个 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 设置为索引。
接下来,我们groupby
和resample
以每周数据填补空白:
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
然后你可以使用 ffill
和 dt.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