Weighted average between NaNs with movmean, determing window length?

6 views (last 30 days)
I am trying to calculated a weighted average using movmean that takes the values between NaNs in a column of data. However, I the number of elements between NaNs, and the number of consecutive NaNs varies throughout the dataset.
For instance, one column of data may look like [1, 3 ,2 ,5 , NaN, NaN, 1, NaN, NaN, NaN, NaN, 4, 4, 7, 1, 3, NaN, 2, 5, 2, 3].
After reading through the documentation, I am still confused as to the proper window length settings, as the number of elements will change throughout the column.
If I set it to say, 3, I will get averages that I am not interested in (e.g. I don't need the average of 1,3,2 and 3,2,5).
Sorry if this is a simple question!
  3 Comments
JM
JM on 6 Sep 2019
Hello,
I would like the final output to be a single value that is a moving average which weights the averages of each group of data between the NaNs. I.e. the 2.75 would be weighted proportionaly to the number of values, so that (for instance) the 1 wouldn't skew the average.
Hope that makes sense.
Adam Danz
Adam Danz on 6 Sep 2019
What you're asking for isn't exactly a moving average which usually consists of a set window size. In any case, if you want the average of each segment between NaN values, then the output will have n values where n is the number of segments.
"the 2.75 would be weighted proportionaly to the number of values"
That's what an average does in the first place. How would you like to add additional weights?

Sign in to comment.

Answers (3)

the cyclist
the cyclist on 6 Sep 2019
If my guess above is correct, then
input = [1, 3 ,2 ,5 , NaN, NaN, 1, NaN, NaN, NaN, NaN, 4, 4, 7, 1, 3, NaN, 2, 5, 2, 3];
[B, N, BI] = RunLength(not(isnan(input)));
N = N(B);
BI = BI(B);
numberSeq = numel(N);
inputMovMean = zeros(numberSeq,1);
for ns = 1:numberSeq
inputMovMean(ns) = mean(input(BI(ns):BI(ns)+N(ns)-1));
end
You'll need to download the nice RunLength utility from the File Exchange.

Adam Danz
Adam Danz on 6 Sep 2019
Edited: Adam Danz on 6 Sep 2019
This approach breaks up the vector x into a cell array of non-nan segments and then calculates the mean of each segment. xMeans(i) is the mean of the i_th non-nan segment which is stored in xSplit{i}.
% inputs
x = [1, 3 ,2 ,5 , NaN, NaN, 1, NaN, NaN, NaN, NaN, 4, 4, 7, 1, 3, NaN, 2, 5, 2, 3];
xdiff = diff(isnan([nan,x,nan])); % -1 is start of non-nan, +1 is start of NaN, 0 is no change
nonNanLengths = find(xdiff==1) - find(xdiff==-1); %lenght of each non-nan segment
xSplit = mat2cell(x(~isnan(x)),1,nonNanLengths); %cell array conaining non-nan segments
xMeans = cellfun(@mean, xSplit); %means of each segment
Result
xMeans =
2.75 1 3.8 3

the cyclist
the cyclist on 6 Sep 2019
You really lost me when you commented that the output would be a single value. How is that a moving average? Do you just want the average of the non-NaN values? Then, it as simple as
nanmean(input)
  1 Comment
Adam Danz
Adam Danz on 6 Sep 2019
or for those without the stats toolbox
mean(x,'omitnan') % for r2015a and later
mean(x(~isnan(x))) % for earlier version (and later)

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!