# Efficient way to calculate backwards average

25 views (last 30 days)
Lorenzo on 29 Sep 2014
Commented: John D'Errico on 1 Oct 2014
Dear all,
I'm looking for an efficient way to calculate a backwards moving average, i.e., giving a vector A I want to calculate a vector A2 for which the element i is equal to mean(A(i:end)).
For the moment I am doing it this way:
A=rand(1,1000);
n=length(A);
A2=zeros(1,n)
for i=1:n
A2(i)=mean(A(i:end));
end
Is there any better way?
Thanks
Lorenzo

John D'Errico on 29 Sep 2014
Edited: John D'Errico on 29 Sep 2014
First of all, what you SAY you are doing makes no sense. A is a 1000x1000 matrix, but A2 only a vector. And you have two i for loops, with only one end. And regardless of what size A is, n=size(A) will produce a vector. So 1:n will yield a problem in the for loop.
The code you show will fail in so many ways I won't bother to count. You should provide working code so someone can know what it is you really want!
Assuming that you really wanted to write this where A is a row vector...
Think about what cumsum does. Then, suppose you flipped the data before calling cumsum.
n = length(A);
A2 = fliplr(cumsum(fliplr(A))./(1:n)));
Of course, this is really not a true moving average, since that would involve a moving window of fixed length. But it is what you asked for.
John D'Errico on 1 Oct 2014
That will work fine, although a minor optimization would be to use bsxfun to do the divide instead of replicating the vector using repmat.
A2=flipud(bsxfun(@rdivide,cumsum(flipud(A)),(1:rows)'));

José-Luis on 29 Sep 2014
numRows = 100;
numCols = 100;
data = rand(numRows,numCols);
result = flipud(bsxfun(@rdivide,cumsum(flipud(data)),(1:numRows)));
Lorenzo on 30 Sep 2014
Thanks José. I'm getting something weird at the end of the signal though… In case of a vector it should be:
result(end)=data(end)
but I'm not getting this with your method…

Chad Greene on 29 Sep 2014
This is a very fast moving average calculator. It centers data, so if you use an N-point moving average, after calculating the moving averaged, you could shift by N/2 to get the "backwards" moving average.
Image Analyst on 29 Sep 2014
He doesn't want a moving average. His window is not constant length, but gets shorter as the index approaches the end of the array.

SK on 29 Sep 2014
Edited: SK on 29 Sep 2014
s = sum(A);
n = length(A);
A2 = (s - cumsum(A))/n;
is a little more elegant and I would think faster. But you have to add s/N to the beginning of A2 and remove the 0 at the end of A2.
The last operation (removing the zero) is misleadingly innocent:
A2(end) = [];
But you may soon get to know the consequences of it.
Lorenzo on 30 Sep 2014
Thanks SK. This doesn't seem to do what I need though… not sure what it is supposed to do…

Lorenzo on 30 Sep 2014
Edited: Lorenzo on 30 Sep 2014
With a vector of 50k elements I get the following run time:
my method: 10.17 s
John's method: 0.006 s
Stephen23 on 30 Sep 2014
Unless you are actually answering your own question, write a comment to your original question or one of the answers. There is no guarantee that the answers remain in any particular order...