在矩阵中用其行索引替换非NaN值

12

我有一个4x2矩阵A:

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

我想用每列中各自索引替换A中的非NaN值。输出结果如下:

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

我知道如何手动为每一列做到这一点,但是我希望有一种自动解决方案,因为我需要处理更大的矩阵。 有人有任何想法吗?

4个回答

11
out = bsxfun(@times, A-A+1, (1:size(A,1)).');

工作原理:

  • A-A+11 替换 A 中的实际数字,并将 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不变。


3
对于Matlab 2016b而言,它只是(A-A+1) .* (1:size(A,1)).',是吗? - Robert Seifert
3
使用“A-A”而不是“zeros(...)”相当聪明。漂亮的代码压缩。 - rayryeng
@rayryeng 谢谢!实际上它甚至更加高尔夫:A-A 根据输入可以得到零或 NaN :-) - Luis Mendo
@LuisMendo 哈哈! 我不知道那个。有趣。什么时候会出现 NaN - rayryeng
@rayryeng 对于任何数字,x-x 都是零,但对于 infNaN 不是。因此,A-A 在原有数字的位置插入零,并保留 NaN 条目。 - Luis Mendo
1
啊!那真是一个非常有用的功能。谢谢! - rayryeng

8

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; - Luis Mendo
最后两个选择在零处失败。对于0,A./A和NaN会得到NaN。 - erfan
@thewaywewalk 你可以在这里删除那个 1B = A-A + ndgrid(1:n,1:m) :-) - Luis Mendo
@LuisMendo 嗯,不完全是,除非我把它改成加法。 - Robert Seifert
@thewaywewalk,感谢您的回答,并感谢您提供有关两个不同转置运算符符号之间区别的提示。 - Bowecho

6

以下是使用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

如果需要的话,您可以进行转置。


2
我为以下几个原因添加了另一个答案:
  1. 因为过度复杂(*咳咳* kron *咳咳*)很有趣。
  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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接