Matlab: Rolling-window matrix with different intervals between columns

I have a vector of data for 21 years with daily data and want to create a rolling window of 365 days such as the next period stars one month (30 days) after the previous one. In the question, n_interval defines the difference between the first data point of the next window and the last observation of the previous series.

Let's assume my daily data start from Jan. 1 2000, then the first column would be Jan. 1, 2000 -Jan.1, 2001 and the second column starts from Feb. 1, 2000. and ends on Feb. 1, 2001. and ... the last column will cover Jan. 1, 2017 to Jan. 1, 2018. for example if:

vec = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17]

for a given variable n_interval = 3, with window_size=5, the output matrix should look like:

mat = [[1 4 7  10  13],
       [2 5 8  11  14],
       [3 6 9  12  15],
       [4 7 10 13  16],
       [5 8 11 14  17]]

Any help would be appreciated.

1 answer

  • answered 2018-01-13 20:27 jodag

    Given your example vector

    vec = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17];
    

    we can create an indexing scheme by as follows:

    First, we need to determine how many rows there will be in the mat. Assuming we want every element of vec to be expressed in mat at least once then we need to make sure that last index in the last row is greater than or equal to the size of vec. It's fairly easy to see that the index of the last column in mat is described by

    last_index = n_interval*(n_rows-1) + n_columns
    

    We want to ensure that last_index >= numel(vec). Substituting in the above expression into the inequality and solving for n_rows gives

    n_rows >= (numel(vec) - n_columns)/n_interval + 1
    

    We assign n_rows to be the ceil of this bound so that it is the smallest integer which satisfies the inequality. Now that we know the number of rows we generate the list of starting indices for each row

    start_index = 1:n_interval:(n_interval*(n_rows-1)+1);
    

    In the index matrix we want each column to be 1 plus the previous column. In other words we want to offset the column according to the array index_offset = 0:(n_interval-1).

    Using bsxfun we generate the index matrix by computing the sums of all pairs between the start_index and index_offset arrays

    index = bsxfun(@plus, index_offset, start_index');
    

    The final thing we need to worry about is going out of bounds. To handle this we apply the mod function to wrap the out of bounds indicies:

    index_wrapped = mod(index-1, numel(vec))+1;
    

    Then we simply sample the vector according to index_wrapped

    mat = vec(index_wrapped);
    

    The complete code is

    n_interval = 3;
    n_columns = 5;
    vec = 1:17;
    
    n_rows = ceil((numel(vec)-n_columns)/n_interval + 1);
    start_index = 1:n_interval:(n_interval*(n_rows-1)+1);
    index_offset = 0:(n_columns-1);
    index = bsxfun(@plus, index_offset, start_index');
    index_wrapped = mod(index-1, numel(vec))+1;
    mat = vec(index_wrapped);