我有一个DataFrame,它以第二个间隔表示特征值的时间序列
>>> df
FeatA FeatB FeatC
0 1 6 11
1 2 7 12
2 3 8 13
3 4 9 14
4 5 10 15
我想用它来为Scikit-Learn模型构建训练数据集。我想在每行中以以下格式添加前15分钟(900行)的特征值
>>> df
FeatA FeatB FeatC FeatA_T1 FeatB_T1 FeatC_T1 FeatA_T2 FeatB_T2 ...
0 1 6 11 NaN NaN NaN NaN NaN
1 2 7 12 1 6 11 NaN NaN
2 3 8 13 2 7 12 1 6
3 4 9 14 3 8 13 2 7
4 5 10 15 4 9 14 3 8
当前我使用的代码本质上是
for i in range(1, 900):
for feature in ["FeatA", "FeatB", "FeatC"]:
df[f"{feature}_T{i}"] = df[feature].shift(i)
原始DataFrame中有23400行,并且有137个功能,因此该方法效率低下且无法使用。由于这将被馈送到Scikit-Learn,因此最终数据必须是一个numpy数组(如下所示)。我可以肯定的是,用numpy代替pandas进行这些操作会更快,但是我发现的所有示例都使用了pandas shift函数。
如何从原始DataFrame高效地构建此数据集?是numpy数组函数吗?
预期结果
array([[ 1., 6., 11., nan, nan, nan, nan, nan, nan],
[ 2., 7., 12., 1., 6., 11., nan, nan, nan],
[ 3., 8., 13., 2., 7., 12., 1., 6., 11.],
[ 4., 9., 14., 3., 8., 13., 2., 7., 12.],
[ 5., 10., 15., 4., 9., 14., 3., 8., 13.]])
最终,我计划分割数组的前900行和最后900行,这样不包含它们的任何结果都将起作用。
答案 0 :(得分:4)
我们可以利用基于np.lib.stride_tricks.as_strided
的scikit-image's view_as_windows
来将滑动窗口视图获取到输入的NaNs
填充版本中,成为一个视图将在内存和性能上有效。
实现看起来像这样-
from skimage.util.shape import view_as_windows
def sliding_windows_grouped(a, W, fillval = np.nan):
# W : Number of rows to be grouped for each row in output array
m,n = a.shape
ext = np.full((W-1)*n, fillval)
a_ext = np.concatenate((a[::-1].ravel(),ext))
return view_as_windows(a_ext,n*W,step=n)[::-1]
More info on use of as_strided
based view_as_windows
。
Samanple运行-
In [63]: a
Out[63]:
array([[55, 58],
[75, 78],
[78, 20],
[94, 32],
[47, 98]])
In [64]: sliding_windows_grouped(a, W=2)
Out[64]:
array([[55., 58., nan, nan],
[75., 78., 55., 58.],
[78., 20., 75., 78.],
[94., 32., 78., 20.],
[47., 98., 94., 32.]])
In [65]: sliding_windows_grouped(a, W=3)
Out[65]:
array([[55., 58., nan, nan, nan, nan],
[75., 78., 55., 58., nan, nan],
[78., 20., 75., 78., 55., 58.],
[94., 32., 78., 20., 75., 78.],
[47., 98., 94., 32., 78., 20.]])
In [66]: sliding_windows_grouped(a, W=4)
Out[66]:
array([[55., 58., nan, nan, nan, nan, nan, nan],
[75., 78., 55., 58., nan, nan, nan, nan],
[78., 20., 75., 78., 55., 58., nan, nan],
[94., 32., 78., 20., 75., 78., 55., 58.],
[47., 98., 94., 32., 78., 20., 75., 78.]])
我们可以使用np.lib.stride_tricks.as_strided
跳过先前提出的解决方案的最后一步,就像这样-
def sliding_windows_grouped_v2(a, W, fillval = np.nan):
# W : Number of rows to be grouped for each row in output array
m,n = a.shape
ext = np.full((W-1)*n, fillval)
a_ext = np.concatenate((a[::-1].ravel(),ext))
strided = np.lib.stride_tricks.as_strided
s = a_ext.strides[0]
return strided(a_ext[(m-1)*n:],strides=(-n*s,s), shape=(m,W*n))