3
votes

I want to piecewise-average a vector in Matlab. Vector x looks like this:

x = 1:15;

Respectively:

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

I want to find the mean value over n = 5 elements; therefore, the result-vector y should look like:

y = [1 1.5 2.5 3 4 5 6 7 8 9 10 11 12 13]

The code for generating the vector y should somehow work like this:

y = [
mean ([1])
mean ([1,2])
mean ([1,2,3])
mean ([1,2,3,4])
mean ([1,2,3,4,5])
mean ([2,3,4,5,6])
mean ([3,4,5,6,7])
mean ([4,5,6,7,8])
mean ([5,6,7,8,9])
mean ([6,7,8,9,10])
mean ([7,8,9,10,11])
mean ([8,9,10,11,12])
mean ([9,10,11,12,13])
mean ([10,11,12,13,14])
mean ([11,12,13,14,15])
]

For n < 5 elements, the program should average over n elements. For example, if there are only 3 elements available, the code should average the first 3 elements. For n > 5 elements, the program should average over the last 5 elements.

Any help is appreciated!

4

4 Answers

3
votes

For such sliding summing or averaging operations, a very efficient vectorized approach would be with 1D convolution conv, like so -

n = 5
sums = conv(x,ones(1,n))
out = sums(1:numel(x))./[1:n n*ones(1,numel(x)-n)]
0
votes

Try this:

x = 1:15;
for n = 1:length(x)
    if n <= 5
        y(n) = mean(x(1:n))
    else
        y(n) = mean(x(n-4:n))
    end
end
0
votes

Below is a kind of a brute force method.

for j=1:length(x)
    A=j-4;
    if A<1 
        A=1;
    end;
    y(j)=mean(x(A:j))

end;

or in a more compact form:

for j=1:length(x)
    y(j)=mean(x(max(j-4,1):j));
end;
0
votes

Here is an alternative method make a matrix of all the numbers which you have to take average of in each row, here in bsxfun() function a vector four new rows are creating for each element of 1:15 row by row of previous 4 digits of the current number and then all the non zero elements are ommitted and amde 0

n =

     5

A  = bsxfun(@plus ,[1:15].',-(n -1):0)
A(A<0) = 0
A =

     0     0     0     0     1
     0     0     0     1     2
     0     0     1     2     3
     0     1     2     3     4
     1     2     3     4     5
     2     3     4     5     6
     3     4     5     6     7
     4     5     6     7     8
     5     6     7     8     9
     6     7     8     9    10
     7     8     9    10    11
     8     9    10    11    12
     9    10    11    12    13
    10    11    12    13    14
    11    12    13    14    15

and then divide the sum of each row by number of non-zero elements in each row

>> sum(A,2)./sum(~ismember(A,0),2)

ans =

    1.0000
    1.5000
    2.0000
    2.5000
    3.0000
    4.0000
    5.0000
    6.0000
    7.0000
    8.0000
    9.0000
   10.0000
   11.0000
   12.0000
   13.0000