【问题标题】:Moving average ignoring NaN忽略 NaN 的移动平均线
【发布时间】:2017-06-28 12:51:07
【问题描述】:

我正在尝试计算矩阵多列的移动平均值。在阅读了关于 stackoverflow 的一些答案后,即this one,似乎filter 函数是要走的路。但是,它不会忽略NaN 元素,我想本着函数nanmean 的精神忽略NaN 元素。下面是一个示例代码:

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

【问题讨论】:

  • 为了清楚起见,您希望将 NaN 保持在各自的位置,并且仅出于每个均值的目的而忽略它们,而不是完全删除它们并取结果的滚动平均值?
  • 没错。因此,如果连续有 7 个 NaN,则结果平均值应为 NaN。如果存在序列 [NaN NaN NaN NaN NaN 5 10],则结果平均值应为 7.5。
  • 我认为你不能使用过滤器,并且可能需要循环思考这个。由于 FFT 的特性,您可以使用过滤器,但 NaN 没有数学公式
  • 整个目标是避免使用效率低下的循环,因为我需要为几个大型矩阵计算它。我正在尝试 accumarray,但还没有弄清楚该怎么做。
  • 函数movmean有一个nan标志。

标签: matlab nan moving-average


【解决方案1】:

colfiltnanmean 一起使用:

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

(如果您只关心“完整”块,请选择内部行/列)

或者,您也可以使用nlfilter,但您需要明确(通过匿名函数句柄)您将要对块做什么;特别是,要使用 nanmean 使其从整个块产生标量输出,您需要在匿名函数中调用 nanmean 之前将每个块转换为列向量:

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

但是,作为记录,matlab 声称 colfilt 通常会更快,因此通常 nlfilter 更好地保留在处理每个块时将输入转换为列没有意义的情况。

另请参阅 sliding operations in general 上的 matlab 手册页/章节。

【讨论】:

    【解决方案2】:

    如果您有 R2016a 或更高版本,您可以使用 the movmean function'omitnan' 选项。

    【讨论】:

      【解决方案3】:

      试试

      MeanMA = filter(ones(1, windowlenght) / windowlenght, 1, X(find(~isnan(X)));
      

      这将从 X 中提取非 nan 值。

      问题是……您还有有效的过滤器处理吗?如果 X 被迭代填充,每个时间步一个元素,那么“NaN-Elimination”将产生一个较短的向量,其值不再与原始时间向量对齐。

      编辑

      要仍然有一个有效的均值计算,必须根据非 NaN 值的数量更新过滤器参数。

      values = X(find(~isnan(X));
      templength = length(values);
      MeanMA = filter(ones(1, templength ) / templength , 1, values );
      

      【讨论】:

      • 感谢您的回答。我确实需要将生成的向量 MeanMA 与原始向量 X 对齐。
      • 那么窗口长度呢?您不必将其设置为可能缩短的向量的长度吗?
      • 见我上面的评论。假设窗口为 7,在该窗口中向量为 [NaN NaN NaN NaN NaN 5 10],然后与 10 对齐,我的平均值应该为 7.5。
      • 我不这么认为。如果您的过滤器参数仍然是 1/10,那么结果是 1.5。您必须根据非 NaN 值的数量调整过滤器参数.....这里:1/2
      • 对不起...窗口长度是 7,而不是 10。所以值将是大约。 2.143,而不是应有的 7.5。
      猜你喜欢
      • 1970-01-01
      • 2012-09-03
      • 2017-09-01
      • 2013-12-22
      • 2018-09-15
      • 1970-01-01
      • 2022-01-26
      • 2014-09-03
      相关资源
      最近更新 更多