带有滑动窗口元素的矩阵

Posted

技术标签:

【中文标题】带有滑动窗口元素的矩阵【英文标题】:Matrix with sliding window elements 【发布时间】:2016-08-16 11:43:19 【问题描述】:

我有时间序列,我将一些用户定义的函数应用于时间序列中的每个 W 元素。

现在我只是使用 for 循环,大小为 W 的滑动窗口,并在每次迭代时将我的函数应用于窗口中的元素。

我正在使用 Matlab,它的“for 循环”效率非常低,所以我很想对这个操作进行矢量化。

作为一种解决方案,我看到将长度为 N 的信号转换为大小为 (N - 1, W) 的矩阵,其中每一行是不同窗口中的时间序列,并将函数应用于该矩阵。

所以,我的问题是:

    如何将我的初始时间序列转换为这样的矩阵? 假设我正在使用步骤 X 滑动窗口。因此不会出现 (N - 1, W) 矩阵,而是 ((N - 1) / X, W)。 ([1] 中矩阵的每 X 行)

例子:

假设我的时间序列是:

T = [1, 5, 6, 8, 10, 14, 22]
W = 3
X = 1

=> 我很想得到

[[1, 5, 6], 
[5, 6, 8], 
[6, 8, 10],
[8, 10, 14],
[10, 14, 22]]

如果

W = 3
X = 2

=> 我很想得到

[[1, 5, 6], 
[6, 8, 10],
[10, 14, 22]]

【问题讨论】:

在矢量化之前需要有更多的先验信息。尽管如此,我没有看到没有 for 循环的方法...... 你需要计算什么样的操作?卷积对您没有帮助吗? 不要这么快关闭循环;有时它们比替代品更快。但我同意之前的 cmets,我们需要更多关于您需要在这些窗口上执行的操作的信息。 【参考方案1】:

使用bsxfun 创建正确的索引肯定会有所帮助:

ind = bsxfun(@plus, 1:W, (0:X:numel(T)-W).');
out = T(ind);  

创建正确的索引是第一步,由第一行代码描述。这段代码所做的是它创建了一个 2D 矩阵,其中每一行是每个感兴趣的窗口要访问的元素。如果您想直观了解代码如何生成索引,请专门查看X = 1;W = 3; 的第一种情况。

我们可以看到第一行由访问元素 1、2、3 组成。第二行由访问元素 2、3、4...直到最后一行组成,即 5、6、7。我们可以看到我们必须访问窗口中的相邻元素,因此基本索引需要从 1、2、3,或者通常从 1 到 W。我们现在需要偏移这些索引,以便它们在每个窗口的T 中以正确的元素为中心。第一个窗口的偏移量仅为 0,第二个窗口的下一个偏移量仅为 1,直到最后一行为 3。我们看到,对于每一行,随着行数的增加,我们向基本索引添加 1。因此,我们为第二行的每个基本索引加 1,然后为第三行的每个基本索引加 2,依此类推。如果您将基本索引与偏移索引相加,您最终会获得正确的索引来访问T 中的正确元素。

类似地,如果 X = 2;W = 3;,我们看到我们仍然有 1、2、3 的基本索引。但是,现在要访问的正确元素是第一行的 1、2、3,然后是 3, 4, 5 代表第二排,然后 5, 6, 7 代表第三排。对于每一行,我们现在将基本索引偏移 2 而不是 1。因此,我们将第二行的每个基本索引加 2,然后我们将第三行的每个基本索引加 4,以此类推。

一般来说,基本索引是使用向量1:W 创建的,偏移索引是使用向量0:X:numel(T)-W 创建的。 W 的减法是必需的,这样我们在按要求对信号进行采样时就不会越界。为了创建我们刚才谈到的这些索引,bsxfun 为我们处理了这个问题。

我们创建了一个1:W 的行向量,它对应于基本索引和一个(0:X:numel(T)-W).' 的列向量,它对应于每个窗口的偏移量。请注意,第一个偏移量从 0 开始,然后我们递增 X 数量以确保计算出正确的中心以放置我们的基本索引。我们停下来,直到我们达到numel(T)-W 元素,这是你所说的条件。通过使用bsxfun,创建了两个临时二维矩阵,其中行向量复制的行数与列向量中的行数相同,列向量的列数与行向量中的列数相同.将这两个矩阵相加后,即可得到结果索引矩阵。

使用W = 3;X = 1; 运行代码给出:

>> T = [1, 5, 6, 8, 10, 14, 22];
>> X = 1;
>> W = 3;
>> ind = bsxfun(@plus, 1:W, (0:X:numel(T)-W).')

ind =

     1     2     3
     2     3     4
     3     4     5
     4     5     6
     5     6     7

同样,如果W = 3;X = 2; 我们也得到:

>> T = [1, 5, 6, 8, 10, 14, 22];
>> X = 2;
>> W = 3;
>> ind = bsxfun(@plus, 1:W, (0:X:numel(T)-W).')

ind =

     1     2     3
     3     4     5
     5     6     7

您可以自己验证这些索引是否对应于T 中的正确元素,以便在这种情况下创建所需的矩阵。

我们最终使用它来索引我们的矩阵以获取正确的元素:

out = T(ind);

X = 1;W = 3; 执行此操作会得到:

>> out = T(ind)

out =

     1     5     6
     5     6     8
     6     8    10
     8    10    14
    10    14    22

X = 2;W = 3; 的情况类似:

>> out = T(ind)

out =

     1     5     6
     6     8    10
    10    14    22

【讨论】:

【参考方案2】:

根据 rayryeng 的回答,我编写了一个完全可以做到这一点的函数,以及一些额外的功能。它旨在为单变量时间序列上的自回归生成索引。通过简单地使用相同的索引并连接引用的数据,它可以很容易地用于多变量情况。

它将索引返回到预测变量 X(根据您的要求)和回归变量 y 也一样。此外,您可以选择在滑动窗口时对预测变量 X 应用“掩码”。例如,对于 21 步的窗口,您可以为 X 选择 [T-2 T-3 T-5 T-8 T-13 T-21] 和T 代表 y

您还可以更改预测范围 - y 的索引未来的步数。例如 X = [T-1 T-2] 和 y = T+2

希望其他人会发现这很有用。

%   get_Sliding_Indexes:
%       Useful for autoregression on a univariate time series.
%       Returns the indexes for the predictor and response variables
%       according to a sliding window.
%
%   Copyright (C) 20016  Florin Schimbinschi
%
%   Parameters:
%       numRecords - the number of records in the dataset
%
%       windowLag - number of past samples to take - it will be equal to 
%           the size of the predictor vector X. Default 10
%
%       predHorizon - the prediction horizon is the number of steps into 
%           the future that predictions are to be made. Default 1
%
%       windowPattern - by default the window will take all consecutive 
%           values in the past over the window lag size, however it is
%           possible to sample using a custom pattern. 
%           For example taking every second value can be done by setting
%           this parameter to 1:2:5. Default 1:windowLag
%
%       stepSize - number of steps taken when window is moved. Default 1
%   
%   Returns:
%       indX - predictor variable indexes
%       indY - response variable indexes
%
%
%      windowPattern = 1:2:9   __ structure between [] is moved to
%             /     \         /   the right by stepSize units
%   >------[(9-7-5-3-1)---(y)]--------------->
%            \_______/ \_/
%         X = [13579]   predHorizon = 3
%
%
%   Example on a multivariate time series (two) with 6 records:
%
%     data2d = [ .1  .2  .3  .4  .5  .6 
%               .11 .22 .33 .44 .55 .66]';
% 
%     [X, y] = getSlidingIndexes(size(data2d,1), 4)
%       X =
%            1     2     3     4
%            2     3     4     5
%       y =
%            5
%            6
%
%     Assuming we are interested in the second series (column):
%
%     series2 = data2d(:,2);
%
%     series2(X)
%     ans =
%         0.1100    0.2200    0.3300    0.4400
%         0.2100    0.3300    0.4400    0.5500
% 
%     series2(y)
%     ans =
%         0.5500
%         0.6600
%
function [indX, indY] = get_Sliding_Indexes(numRecords, ...
                        windowLag, predHorizon, windowPattern, stepSize)

    if ~exist('numRecords','var') || isempty(numRecords)
        error('The number of records in the dataset is not specified');
    end
    if ~exist('stepSize','var') || isempty(stepSize)
        stepSize = 1; % steps taken when moving the window
    end
    if ~exist('predHorizon','var') || isempty(predHorizon) 
        predHorizon = 1; % aiming to predict this many steps in the future
    end  
    if ~exist('windowLag','var') || isempty(windowLag) 
        windowLag = 10; % number of time steps to look back
    end
    if exist('windowLag','var') && (windowLag > numRecords)
        error('The size of the window is larger than the number of observations');
    end
    if ~exist('windowPattern','var') || isempty(windowPattern) 
        windowPattern = 1:windowLag; % pattern of sampling data
    end
    if exist('windowPattern','var') && windowPattern(end) > windowLag
        error('The window pattern must stop at the window lag specified');
    end

    % the number of samples in the window
    maxSample = max(windowPattern);

    indX = bsxfun(@plus, windowPattern, ...
        (0:stepSize:(numRecords - maxSample - predHorizon))');
    indY = bsxfun(@plus, max(windowPattern) + predHorizon, ...
        (0:stepSize:(numRecords - maxSample - predHorizon))');
end

您也可以在这里找到代码:https://au.mathworks.com/matlabcentral/fileexchange/58730-get-sliding-indexes-numrecords--windowlag--predhorizon--windowpattern--stepsize-

【讨论】:

以上是关于带有滑动窗口元素的矩阵的主要内容,如果未能解决你的问题,请参考以下文章

Apache Spark - 处理临时 RDD 上的滑动窗口

带有 UiSplitview 的滑动窗口,例如横向和纵向的 gmail iPad 应用程序

滑动窗口

Pyspark 将数组列分解为带有滑动窗口的子列表

如何从列表列表中选择元素的滑动窗口?

活动识别的滑动​​窗口算法