Moving average ignore NaN
I am trying to compute a moving average over multiple columns of a matrix. After reading some answers on stackoverflow namely this , it seemed like a function filter
is the way to go. However, it does not ignore elements NaN
, and I would like to do so by ignoring elements NaN
in the spirit of a function nanmean
. Below is a sample code:
X = rand(100,100); %generate sample matrix X(sort(randi([1 100],1,10)),sort(randi([1 100],1,10))) = NaN; %put some random NaNs windowlenght = 7; MeanMA = filter(ones(1, windowlenght) / windowlenght, 1, X);
source to share
>> A = [1 2 3 4 5; 2 nan nan nan 6; 3 nan nan nan 7; 4 nan nan nan 8; 5 6 7 8 9]
A =
1 2 3 4 5
2 NaN NaN NaN 6
3 NaN NaN NaN 7
4 NaN NaN NaN 8
5 6 7 8 9
>> colfilt(A, [3,3], 'sliding', @nanmean)
ans =
0.6250 1.1429 1.5000 2.5714 1.8750
1.1429 2.2000 3.0000 5.0000 3.1429
1.5000 3.0000 NaN 7.0000 3.5000
2.5714 5.0000 7.0000 7.8000 4.5714
1.8750 3.1429 3.5000 4.5714 3.1250
(if you only want full blocks then select inner rows / columns accordingly)
Alternatively, you can also use nlfilter , but then you need to be explicit (via the anonymous function handle) about what you are going to do with the block; in particular to work with nanmean so that it will produce scalar output from the entire block, you will need to convert each block to a column vector before calling nanmean in your anonymous function:
>> nlfilter(A, [3,3], @(x) nanmean(x(:)))
ans =
0.6250 1.1429 1.5000 2.5714 1.8750
1.1429 2.2000 3.0000 5.0000 3.1429
1.5000 3.0000 NaN 7.0000 3.5000
2.5714 5.0000 7.0000 7.8000 4.5714
1.8750 3.1429 3.5000 4.5714 3.1250
However, for the record, matlab claims that colfilt will generally be faster, so nlfilter is generally better reserved for situations where it doesn't need to make sense to convert to a column to process your input when processing each block.
Also see the matlab man page / chapter on sliding operations in general .
source to share
Try
MeanMA = filter(ones(1, windowlenght) / windowlenght, 1, X(find(~isnan(X)));
This will extract non-nan values ββfrom X.
Question ... do you still have valid filter processing? If X is filled iteratively, one element at a time, then "NaN-Elimination" will generate a shorter vector whose values ββare no longer aligned with the original time vector.
EDIT
To still have a valid average calculation, the filter parameters must be updated according to the number of values ββother than NaN.
values = X(find(~isnan(X));
templength = length(values);
MeanMA = filter(ones(1, templength ) / templength , 1, values );
source to share
If you have R2016a or higher, you can use the functionmovmean
with the option 'omitnan'
.
source to share