4

Suppose I have a long data vector y, plus some indices into it. I want to extract a short snippet or window around every index.

For example, suppose I want to construct a matrix containing 64 samples before and 64 samples after every value that is below three. This is trivial to do in a for-loop:

WIN_SIZE = 64;

% Sample data with padding
data = [nan(WIN_SIZE,1); randn(1e6,1); nan(WIN_SIZE,1)];

% Sample events, could be anything
index = find(data < 3); 

snippets = nan(length(index), 2*WIN_SIZE + 1);
for ii=1:length(index)
   snippets(ii,:) = data((index(ii)-WIN_SIZE):(index(ii)+WIN_SIZE));
end

However,this is not blazingly fast. Is there any way to vectorize (or otherwise speed up) this operation?

(In case this is unclear, the index could be anything and may not necessarily be a property of the data; I just wanted something simple to illustrate the idea.)

Matt Krause
  • 1,113
  • 14
  • 31
  • `index` is a (column) vector. You don't need a for-loop, you can vectorize it, see [Get vector indices before-and-after (window +/- 1) given indices](https://stackoverflow.com/questions/48881754/get-vector-indices-before-and-after-window-1-given-indices) – smci Feb 21 '18 at 14:52
  • Note that this question is 2+ years old and that doesn't work in anything older than 2016b. – Matt Krause Feb 21 '18 at 19:00
  • Matt, ok then how should we handle this obsolete question and answer? I suggest we close-as-duplicate into [Get vector indices before-and-after (window +/- 1) given indices](https://stackoverflow.com/questions/48881754/get-vector-indices-before-and-after-window-1-given-indices) – smci Feb 21 '18 at 23:34
  • Possible duplicate of [Get vector indices before-and-after (window +/- 1) given indices](https://stackoverflow.com/questions/48881754/get-vector-indices-before-and-after-window-1-given-indices) – smci Feb 21 '18 at 23:35
  • For what it's worth, I feel like this question gives a better explanation of the problem/use case (which is actually slightly different--I want the a small window of data around some indices, not the indices; I rolled back your edit conflating the two). I'm also a little confused as to how an older question could possibly be a duplicate of a newer one. – Matt Krause Feb 22 '18 at 00:03
  • MattKrause why did you remove the word 'window'? since that's what this is about. (Getting the indices, vs the data at those indices, is essentially the same). As to duplicate, I don't see that the age of question matters; both this question and its answer are obsolete post-2016 now that there is implicit singleton expansion; also mine asked for both Matlab + Octave syntaxes (see Wolfie's comments on where they differ and why the Octave answer can be a one-liner). I also encouraged @Wolfie to repost his answer here then. – smci Feb 22 '18 at 00:51
  • 1
    @smci Who says the question/answer are obsolete? The answer still works, even though later MATLAB versions provide an *additional* way to handle it. – beaker Feb 23 '18 at 23:41

1 Answers1

7

Use bsxfun -

snippets = data(bsxfun(@plus,index(:),[-WIN_SIZE:WIN_SIZE]))
Divakar
  • 218,885
  • 19
  • 262
  • 358
  • 1
    I just wanted to come up with a double `repmat`-answer. But this solution with `bsxfun` is better and _slightly_ faster as well. – Matt Jan 25 '16 at 20:14
  • 1
    @Matt That would follow the pattern of performance numbers seen in [`Comparing BSXFUN and REPMAT`](http://stackoverflow.com/questions/29719674/comparing-bsxfun-and-repmat) that shows `20-40%` improvement with `bsxfun(@plus` over a repmat version. – Divakar Jan 25 '16 at 20:16
  • 1
    You are perfectly right on this. Btw: That's a really nice comparison of `bsxfun`and `repmat`! – Matt Jan 25 '16 at 20:31
  • 2
    @Matt Took me few days to compile and assemble those comparison results and seems like it's coming to some use huh! :) – Divakar Jan 25 '16 at 20:33
  • 1
    Thanks! For the record, this is about 10x faster than the naive for-loop! – Matt Krause Jan 25 '16 at 20:47