时间序列数据预处理-numpy迈步以节省内存

时间:2018-09-03 12:05:22

标签: python numpy data-structures time-series

我正在预处理一个时间序列数据集,将其形状从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

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:2)

您可以使用我制作的here步幅模板功能window_nd

然后跨越仅需的第一个维度

framed_data = window_nd(data_to_frame, window_size, axis = 0)

尚未找到可以在任意轴上运行的内置窗口函数,因此除非最近在scipy.signalskimage中实现了一个新的窗口函数,否则可能是最好的选择。 / 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等。主要是像meansum这样的归约运算会产生真正节省空间。

相关问题