Create overlapping and non-overlapping sliding win

2019-03-01 13:26发布

问题:

I am trying to create overlapping and non-overlapping blocks of data from an array Data containingN elements. How can I correctly form sub-arrays of Data for any N and any blksze? The following code is for non-overlapping blocks throws error because of the number of elements exceed when creating sub-blocks. For example, let Data = [1,2,3,4,5,6], then

  • for overlapping case I should get : block size blksze = 2, I would get block1 = [1,2], block2 = [2,3], block3 = [3,4], block4 = [4,5], block5 = [5,6]

  • for non-overlapping : block size blksze = 2, I would get block1 = [1,2], block2 = [3,4], block3 = [5,6]

Code snippet

N= 100;
n = 4;
Data = randi([1 n],1,N);
blksze = 10;
Nblocks = N / blksze;
counter = 1;
for i = 1 : Nblocks
    block{i} = Data(counter : counter + blksze - 1);
    counter = blksze + 1;
end

回答1:

To extract out overlapping blocks, I recommend using bsxfun to create the indices and subset the matrix whereas non-overlapping blocks you can simply use reshape.

Overlapping

ind = bsxfun(@plus, (1 : blksze), (0 : numel(Data) - blksze).');

The advantage of this method is that it uses broadcasting to generate the right indices per block. This would thus be a 2D matrix where each row are the indices required to grab the data for the right block and the number of columns is dictated by the block size.

Non-overlapping

ind = reshape(1 : numel(Data), [], numel(Data) / blksze).';

This simply reshapes the vector so that each row would be a unique set of indices that increases by 1 and the number of columns is dictated by the block size.


Finally, just index into Data to get what you need:

blocks = Data(ind);

Here's a running example using 6 elements:

>> rng(123); Data = rand(1, 6)

Data =

    0.6965    0.2861    0.2269    0.5513    0.7195    0.4231

With a block size of 2, or blksze = 2, here's what we get for both overlapping and non-overlapping:

>> blksze = 2;
>> indno = reshape(1 : numel(Data), [], numel(Data) / blksze).';
>> indo = bsxfun(@plus, (1 : blksze), (0 : numel(Data) - blksze).');
>> blockno = Data(indno)

blockno =

    0.6965    0.2861
    0.2269    0.5513
    0.7195    0.4231

>> blocko = Data(indo)

blocko =

    0.6965    0.2861
    0.2861    0.2269
    0.2269    0.5513
    0.5513    0.7195
    0.7195    0.4231

Caveat

This code does no error checking in that we assume that there are enough blocks to capture all of your data. If you have the number of elements in Data to be incompatible with the block size to capture all of the data in blocks of all the same size, an error will occur upon indexing.