guskenny83
guskenny83

Reputation: 1373

Can someone help vectorise this matlab loop?

i am trying to learn how to vectorise matlab loops, so im just doing a few small examples.

here is the standard loop i am trying to vectorise:

function output = moving_avg(input, N)
    output = [];
    for n = N:length(input) % iterate over y vector
        summation = 0;
            for ii = n-(N-1):n % iterate over x vector N times
                summation += input(ii);
            endfor
        output(n) = summation/N;
    endfor 
endfunction

i have been able to vectorise one loop, but cant work out what to do with the second loop. here is where i have got to so far:

function output = moving_avg(input, N)
    output = [];
    for n = N:length(input) % iterate over y vector
        output(n) = mean(input(n-(N-1):n));
    endfor 
endfunction

can someone help me simplify it further?

EDIT:
the input is just a one dimensional vector and probably maximum 100 data points. N is a single integer, less than the size of the input (typically probably around 5)

i don't actually intend to use it for any particular application, it was just a simple nested loop that i thought would be good to use to learn about vectorisation..

Upvotes: 0

Views: 90

Answers (3)

Luis Mendo
Luis Mendo

Reputation: 112679

For a sliding average, you can use cumsum to minimize the number of operations:

x = randi(10,1,10);                      %// example input
N = 3;                                   %// window length
y = cumsum(x);                           %// compute cumulative sum of x
z = zeros(size(x));                      %// initiallize result to zeros
z(N:end) = (y(N:end)-[0 y(1:end-N)])/N;  %// compute order N difference of cumulative sum

Upvotes: 0

Jason Newton
Jason Newton

Reputation: 1211

Matlab as a language does this type of operation poorly - you will always require an outside O(N) loop/operation involving at minimum O(K) copies which will not be worth it in performance to vectorize further because matlab is a heavy weight language. Instead, consider using the filter function where these things are typically implemented in C which makes that type of operation nearly free.

Upvotes: 0

Divakar
Divakar

Reputation: 221564

Seems like you are performing convolution operation there. So, just use conv -

output = zeros(size(input1))
output(N:end) = conv(input1,ones(1,N),'valid')./N

Please note that I have replaced the variable name input with input1, as input is already used as the name of a built-in function in MATLAB, so it's a good practice to avoid such conflicts.


Generic case: For a general case scenario, you can look into bsxfun to create such groups and then choose your operation that you intend to perform at the final stage. Here's how such a code would look like for sliding/moving average operation -

%// Create groups of indices for each sliding interval of length N
idx = bsxfun(@plus,[1:N]',[0:numel(input1)-N])  %//'

%// Index into input1 with those indices to get grouped elements from it along columns
input1_indexed = input1(idx)

%// Finally, choose the operation you intend to perform and apply along the
%// columns. In this case, you are doing average, so use mean(...,1).
output = mean(input1_indexed,1)
%// Also pre-append with zeros if intended to match up with the expected output

Upvotes: 1

Related Questions