How do I select n elements of a sequence in window

2019-02-24 01:54发布

问题:

Quick MATLAB question. What would be the best/most efficient way to select a certain number of elements, 'n' in windows of 'm'. In other words, I want to select the first 50 elements of a sequence, then elements 10-60, then elements 20-70 ect. Right now, my sequence is in vector format(but this can easily be changed).

EDIT: The sequences that I am dealing with are too long to be stored in my RAM. I need to be able to create the windows, and then call upon the window that I want to analyze/preform another command on.

回答1:

Do you have enough RAM to store a 50-by-nWindow array in memory? In that case, you can generate your windows in one go, and then apply your processing on each column

%# idxMatrix has 1:50 in first col, 11:60 in second col etc
idxMatrix = bsxfun(@plus,(1:50)',0:10:length(yourVector)-50); %'#

%# reshapedData is a 50-by-numberOfWindows array
reshapedData = yourVector(idxMatrix);

%# now you can do processing on each column, e.g.
maximumOfEachWindow = max(reshapedData,[],1);


回答2:

To complement Kerrek's answer: if you want to do it in a loop, you can use something like

n = 50
m = 10;
for i=1:m:length(v)
    w = v(i:i+n);
    % Do something with w
end


回答3:

There's a slight issue with the description of your problem. You say that you want "to select the first 50 elements of a sequence, then elements 10-60..."; however, this would translate to selecting elements:

  • 1-50
  • 10-60
  • 20-70
  • etc.

That first sequence should be 0-10 to fit the pattern which of course in MATLAB would not make sense since arrays use one-indexing. To address this, the algorithm below uses a variable called startIndex to indicate which element to start the sequence sampling from.

You could accomplish this in a vectorized way by constructing an index array. Create a vector consisting of the starting indices of each sequence. For reuse sake, I put the length of the sequence, the step size between sequence starts, and the start of the last sequence as variables. In the example you describe, the length of the sequence should be 50, the step size should be 10 and the start of the last sequence depends on the size of the input data and your needs.

>> startIndex = 10;
>> sequenceSize = 5;
>> finalSequenceStart = 20;

Create some sample data:

>> sampleData = randi(100, 1, 28)

sampleData =

  Columns 1 through 18

     8    53    10    82    82    73    15    66    52    98    65    81    46    44    83     9    14    18

  Columns 19 through 28

    40    84    81     7    40    53    42    66    63    30

Create a vector of the start indices of the sequences:

>> sequenceStart = startIndex:sequenceSize:finalSequenceStart

sequenceStart =

    10    15    20

Create an array of indices to index into the data array:

>> index = cumsum(ones(sequenceSize, length(sequenceStart)))

index =

     1     1     1
     2     2     2
     3     3     3
     4     4     4
     5     5     5

>> index = index + repmat(sequenceStart, sequenceSize, 1) - 1

index =

    10    15    20
    11    16    21
    12    17    22
    13    18    23
    14    19    24

Finally, use this index array to reference the data array:

>> sampleData(index)

ans =

    98    83    84
    65     9    81
    81    14     7
    46    18    40
    44    40    53


回答4:

Use (start : step : end) indexing: v(1:1:50), v(10:1:60), etc. If the step is 1, you can omit it: v(1:50).



回答5:

Consider the following vectorized code:

x = 1:100;                                     %# an example sequence of numbers

nwind = 50;                                    %# window size
noverlap = 40;                                 %# number of overlapping elements
nx = length(x);                                %# length of sequence

ncol = fix((nx-noverlap)/(nwind-noverlap));    %# number of sliding windows
colindex = 1 + (0:(ncol-1))*(nwind-noverlap);  %# starting index of each

%# indices to put sequence into columns with the proper offset
idx = bsxfun(@plus, (1:nwind)', colindex)-1;   %'

%# apply the indices on the sequence
slidingWindows = x(idx)

The result (truncated for brevity):

slidingWindows =
     1    11    21    31    41    51
     2    12    22    32    42    52
     3    13    23    33    43    53
    ...
    48    58    68    78    88    98
    49    59    69    79    89    99
    50    60    70    80    90   100

In fact, the code was adapted from the now deprecated SPECGRAM function from the Signal Processing Toolbox (just do edit specgram.m to see the code).

I omitted parts that zero-pad the sequence in case the sliding windows do not evenly divide the entire sequence (for example x=1:105), but you can easily add them again if you need that functionality...