# Weighted average between NaNs with movmean, determing window length?

12 views (last 30 days)
Jonathan Marchetto on 6 Sep 2019
Commented: Adam Danz on 6 Sep 2019
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!

the cyclist on 6 Sep 2019
What would the correct output of that input vector be?
Do you just want the average of each section that is separated by NaN? So
output = [2.75 1 3.8 3];
?
Jonathan Marchetto 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 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?

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 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 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 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)