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

      

+3


source to share


3 answers


Use colfilt with nanmean :

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

+1


source


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

      

0


source


If you have R2016a or higher, you can use the functionmovmean

with the option 'omitnan'

.

0


source







All Articles