【问题标题】:Replace non-NaN values with their row indices within matrix用矩阵中的行索引替换非 NaN 值
【发布时间】:2025-11-22 09:25:02
【问题描述】:

我有 4x2 矩阵 A:

A = [2 NaN 5 8; 14 NaN 23 NaN]';

我想用 A 中每一列中的相关索引替换非 NaN 值。输出如下所示:

out = [1 NaN 3 4; 1 NaN 3 NaN]'; 

我知道如何手动为每一列执行此操作,但我想要一个自动解决方案,因为我要处理更大的矩阵。有人有任何想法吗?

【问题讨论】:

    标签: matlab matrix


    【解决方案1】:
    out = bsxfun(@times, A-A+1, (1:size(A,1)).');
    

    它是如何工作的:

    • A-A+1A 中的实际数字替换为1,并将NaN 保留为NaN
    • (1:size(A,1)).' 是行索引的列向量
    • bsxfun(@times, ...) 将上述两者与单例扩展相乘。

    正如@thewaywewalk 所指出的,在Matlab R2016 及以后的版本中,bsxfun(@times...) 可以替换为.*,因为默认情况下启用了单例扩展:

    out = (A-A+1) .* (1:size(A,1)).';
    

    @Dev-Il 建议的替代方案是

    out = bsxfun(@plus, A*0, (1:size(A,1)).');
    

    这是可行的,因为乘以 0 会用 0 替换实际数字,并保持 NaN 不变。

    【讨论】:

    • 使用 Matlab 2016b 只是 (A-A+1) .* (1:size(A,1)).' 不是吗?
    • 使用A-A 而不是zeros(...) 非常聪明。不错的代码打高尔夫球。
    • @rayryeng 谢谢!实际上它甚至更高尔夫球:A-A 给出零 NaN 取决于输入:-)
    • @LuisMendo 哈!我不知道。有趣的。什么时候给NaN
    • 啊!嗯,这实际上是一个非常有用的功能。谢谢!
    【解决方案2】:

    ind2sub 应用于使用isnan 创建的蒙版即可。

    mask = find(~isnan(A));
    [rows,~] = ind2sub(size(A),mask)
    A(mask) = rows;
    

    请注意,ind2sub 的第二个输出需要请求(但 ~ 忽略)以及 [rows,~] 以表明您需要二维矩阵的输出。


    A =
    
         1     1
       NaN   NaN
         3     3
         4   NaN
    
    A.' =
    
         1   NaN     3     4
         1   NaN     3   NaN
    

    还要小心使用两个不同的转置运算符'.'


    另类

    [n,m] = size(A);
    B = ndgrid(1:n,1:m);
    B(isnan(A)) = NaN;
    

    甚至(Luis Mendo 的一点启发)

    [n,m] = size(A);
    B = A-A + ndgrid(1:n,1:m)
    

    或一行

    B = A-A + ndgrid(1:size(A,1),1:size(A,2))
    

    【讨论】:

    • 等效:[rows,cols] = find(~isnan(A)); A(sub2ind(size(A), rows, cols)) = rows;
    • 最后两个备选方案在零处失败。 A./A 为 0,NaNNaN
    • @thewaywewalk 您可以在此处删除 1B = A-A + ndgrid(1:n,1:m) :-)
    • @LuisMendo 不完全是,除非我将其更改为附加项
    • @thewaywewalk 感谢您的回答以及关于两个不同转置运算符符号之间差异的提示。
    【解决方案3】:

    这可以使用repmatisnan 来完成,如下所示:

    A = [ 2  NaN   5    8; 
         14  NaN  23  NaN];
    out=repmat([1:size(A,2)],size(A,1),1); % out contains indexes of all the values
    out(isnan(A))= NaN                     % Replacing the indexes where NaN exists with NaN
    

    输出:

     1   NaN     3     4
     1   NaN     3   NaN
    

    如果你愿意,你可以进行转置。

    【讨论】:

      【解决方案4】:

      我添加另一个答案有几个原因:

      1. 因为矫枉过正 (*ahem* kron *ahem*) 很有趣。
      2. 证明A*0A-A的作用相同。

      A = [2 NaN 5 8; 14 NaN 23 NaN].';
      out = A*0 + kron((1:size(A,1)).', ones(1,size(A,2)))
      
      out =
      
           1     1
         NaN   NaN
           3     3
           4   NaN
      

      【讨论】:

        最近更新 更多