如何有效地填充时间序列?
Posted
技术标签:
【中文标题】如何有效地填充时间序列?【英文标题】:How to efficiently fill a time series? 【发布时间】:2019-09-29 22:59:04 【问题描述】:我的一般问题是我有一个数据框,其中列对应于特征值。数据框中还有一个日期列。每个特征列可能缺少 NaN 值。我想用一些填充逻辑填充一列,例如“fill_mean”或“填充零”。
但我不想只将填充逻辑应用于整个列,因为如果较早的值之一是 NaN,我不希望我为这个特定 NaN 填充的平均值被后来的平均值所污染on,什么时候模型应该不知道。本质上,这是一个常见问题,即不向您的模型泄露有关未来的信息 - 特别是在尝试填充我的时间序列时。
无论如何,我已将问题简化为几行代码。这是我对上述一般问题的简化尝试:
#assume ts_values is a time series where the first value in the list is the oldest value and the last value in the list is the most recent.
ts_values = [17.0, np.NaN, 12.0, np.NaN, 18.0]
nan_inds = np.argwhere(np.isnan(ts_values))
for nan_ind in nan_inds:
nan_ind_value = nan_ind[0]
ts_values[nan_ind_value] = np.mean(ts_values[0:nan_ind_value])
上述脚本的输出为:
[17.0, 17.0, 12.0, 15.333333333333334, 18.0]
这正是我所期望的。
我对此的唯一问题是,它与数据集中的 NaN 数量呈线性关系。有没有办法在我不迭代 nan 索引值的常量或日志时间内做到这一点。
【问题讨论】:
我认为没有循环是不行的,我们可以尝试使用numba来加快速度 【参考方案1】:如果您想在熊猫系列s
上将nan
值替换为滚动平均值(全窗口),请注意WeNYoBen 在填充期间不会继续滚动平均值计算。 (所以你的 15.3 变成了 12.0)。
s.fillna(s.expanding(1).mean())
如果您希望在 nans 被填充时更新滚动平均值,这个就地 numba
解决方案可能会有所帮助
import numpy as np
import numba
from numba import jit
@jit(nopython=True)
def rolling_fill(a):
for i, e in enumerate(a):
if np.isnan(e):
a[i] = np.mean(a[:i])
ts_values = np.array([17.0, np.NaN, 12.0, np.NaN, 18.0])
rolling_fill(ts_values)
print(ts_values)
这给了
[17. 17. 12. 15.33333333 18. ]
您可以通过保留总和而不是每次都调用.mean
来改善这一点。
时间复杂度
这不是log
或constant
时间,因为您必须从长度为n
的数组中插入最多n-2
缺失的项目@ 987654336@ - 但它应该被充分优化(通过避免在本机 python) 并且您不能 理论上 做得更好,但是上述的较低级别的实现将使这大大加快。
编辑:我最初误读并认为您在询问插值
你想interpolate
这个系列,熊猫直接支持这个。
>>> s = pd.Series([0, 1, np.nan, 5])
>>> s
0 0.0
1 1.0
2 NaN
3 5.0
dtype: float64
>>> s.interpolate()
0 0.0
1 1.0
2 3.0
3 5.0
dtype: float64
或者如果您不想使用pandas
,因为您的示例是ndarray
,那么请相应地使用numpy.interp
。
【讨论】:
请检查您的输出。 不错的捕获@WeNYoBen - 不知道如何在没有循环的情况下解决它。可能需要一些 jit以上是关于如何有效地填充时间序列?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用python有效地填充“缺失时间模式”和“填充它们”具有特定值?