我正在预处理一个时间序列数据集,将其形状从2维(数据点,特征)更改为3维(数据点,time_window,特征)。
在这样的透视图中,时间窗口(有时也称为回溯)指示作为输入变量所涉及的先前时间步长/数据点的数量,以预测下一时间段。换句话说,时间窗口是机器学习算法过去要考虑的数据量,以供将来进行单个预测时使用。
这种方法(或至少在我的实现中)存在的问题是,在内存使用方面效率很低,因为它带来了跨窗口的数据冗余,导致输入数据变得非常繁重。
这是我到目前为止一直在使用的功能,用于将输入数据重塑为3维结构。
from sys import getsizeof
def time_framer(data_to_frame, window_size=1):
"""It transforms a 2d dataset into 3d based on a specific size;
original function can be found at:
https://machinelearningmastery.com/time-series-prediction-lstm-recurrent-neural-networks-python-keras/
"""
n_datapoints = data_to_frame.shape[0] - window_size
framed_data = np.empty(
shape=(n_datapoints, window_size, data_to_frame.shape[1],)).astype(np.float32)
for index in range(n_datapoints):
framed_data[index] = data_to_frame[index:(index + window_size)]
print(framed_data.shape)
# it prints the size of the output in MB
print(framed_data.nbytes / 10 ** 6)
print(getsizeof(framed_data) / 10 ** 6)
# quick and dirty quality test to check if the data has been correctly reshaped
test1=list(set(framed_data[0][1]==framed_data[1][0]))
if test1[0] and len(test1)==1:
print('Data is correctly framed')
return framed_data
已建议我使用numpy's strides trick来解决此问题并减小重新成形的数据的大小。不幸的是,到目前为止,我在这个主题上找到的所有资源都集中在实现二维数组上的技巧上,就像excellent tutorial一样。我一直在努力解决涉及3维输出的用例。这是我表现出来的最好的。但是,它不能成功减小framed_data的大小,也不能正确地对数据进行构图,因为它没有通过质量测试。
我非常确定我的错误是在我没有完全理解的 strides 参数上。 new_strides 是我成功成功馈给 as_strided 的唯一值。
from numpy.lib.stride_tricks import as_strided
def strides_trick_time_framer(data_to_frame, window_size=1):
new_strides = (data_to_frame.strides[0],
data_to_frame.strides[0]*data_to_frame.shape[1] ,
data_to_frame.strides[0]*window_size)
n_datapoints = data_to_frame.shape[0] - window_size
print('striding.....')
framed_data = as_strided(data_to_frame,
shape=(n_datapoints, # .flatten() here did not change the outcome
window_size,
data_to_frame.shape[1]),
strides=new_strides).astype(np.float32)
# it prints the size of the output in MB
print(framed_data.nbytes / 10 ** 6)
print(getsizeof(framed_data) / 10 ** 6)
# quick and dirty test to check if the data has been correctly reshaped
test1=list(set(framed_data[0][1]==framed_data[1][0]))
if test1[0] and len(test1)==1:
print('Data is correctly framed')
return framed_data
任何帮助将不胜感激!
答案 0 :(得分:2)
您可以使用我制作的here步幅模板功能window_nd
然后跨越仅需的第一个维度
framed_data = window_nd(data_to_frame, window_size, axis = 0)
尚未找到可以在任意轴上运行的内置窗口函数,因此除非最近在scipy.signal
或skimage
中实现了一个新的窗口函数,否则可能是最好的选择。 / p>
编辑:要查看内存节省情况,您将需要使用@ali_m here所描述的方法,因为基本的ndarray.nbytes
对于共享内存是幼稚的。>
def find_base_nbytes(obj):
if obj.base is not None:
return find_base_nbytes(obj.base)
return obj.nbytes
答案 1 :(得分:1)
为此X
:
In [734]: X = np.arange(24).reshape(8,3)
In [735]: X.strides
Out[735]: (24, 8)
此as_strided
与您的time_framer
产生相同的数组
In [736]: np.lib.stride_tricks.as_strided(X,
shape=(X.shape[0]-3, 3, X.shape[1]),
strides=(24, 24, 8))
Out[736]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]],
[[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]],
[[12, 13, 14],
[15, 16, 17],
[18, 19, 20]]])
它像X
一样跨过最后一个维度。还有第二到最后。第一个前进一行,因此它也得到X.strides[0]
。因此,窗口大小只会影响形状,而不会影响步幅。
因此,在您的as_strided
版本中,只需使用:
new_strides = (data_to_frame.strides[0],
data_to_frame.strides[0] ,
data_to_frame.strides[1])
较小的更正。将默认窗口大小设置为2或更大。 1在测试中产生索引错误。
framed_data[0,1]==framed_data[1,0]
正在寻找getsizeof
:
In [754]: sys.getsizeof(X)
Out[754]: 112
In [755]: X.nbytes
Out[755]: 192
等等,为什么X
的大小小于nbytes
?因为它是view
(请参见上面的[734]行)。
In [756]: sys.getsizeof(X.copy())
Out[756]: 304
如另一SO中所述,必须谨慎使用getsizeof
:
Why the size of numpy array is different?
现在要展开副本了:
In [757]: x2=time_framer(X,4)
...
In [758]: x2.strides
Out[758]: (96, 24, 8)
In [759]: x2.nbytes
Out[759]: 384
In [760]: sys.getsizeof(x2)
Out[760]: 512
和跨步版本
In [761]: x1=strides_trick_time_framer(X,4)
...
In [762]: x1.strides
Out[762]: (24, 24, 8)
In [763]: sys.getsizeof(x1)
Out[763]: 128
In [764]: x1.astype(int).strides
Out[764]: (96, 24, 8)
In [765]: sys.getsizeof(x1.astype(int))
Out[765]: 512
x1
的大小就像一个视图(128是3d一样)。但是,如果我们尝试更改其dtype
,它将进行复制,并且步幅和大小与x2
相同。
在x1
上进行的许多操作都将失去巨大的尺寸优势,x1.ravel()
,x1+1
等。主要是像mean
和sum
这样的归约运算会产生真正节省空间。