在MATLAB中重塑/转换一个上三角矩阵

4

我有一个上三角矩阵(不包括对角线),如下:

M = [0 3 2 2 0 0; 0 0 8 6 3 2; 0 0 0 3 2 1; 0 0 0 0 2 1; 0 0 0 0 0 0]

生成的矩阵应该长这样:
R = [0 0 0 0 0 0; 0 2 0 0 0 0; 2 3 1 0 0 0; 2 6 2 1 0 0; 3 8 3 2 0 0]

由于我找不到一个简单的解释来描述我的目标,因此我尝试用图像来可视化它:

enter image description here

我已经尝试了许多不同的组合,如rot90transposeflipud等,但我找不到正确的转换方式,使我得到矩阵R

编辑:

矩阵M的行并不总是像上面的示例那样排序。对于另一个矩阵M_2

M_2 = [0 2 3 1 0 0; 0 0 3 6 3 9; 0 0 0 1 2 4; 0 0 0 0 2 6; 0 0 0 0 0 0]

生成的矩阵 R_2 需要如下所示:

R_2 = [0 0 0 0 0 0; 0 9 0 0 0 0; 1 3 4 0 0 0; 3 6 2 6 0 0; 2 3 1 2 0 0]

再次展示下面的可视化图表: enter image description here

1
sort(M')怎么样? - Dan
你确定要把那一行零放在右边,而不是在顶部吗?否则,@Dan的解决方案应该可以解决。 - Dennis Jaheruddin
嗯...是的,维度需要相同,但sort似乎是一个不错的开始。 - Schnigges
3个回答

5
编辑:

编辑:受到@Dan评论中的提示启发,它可以进一步简化为

R = reshape(rot90(M), size(M));

这应该是一个简单的方法来做到这一点。
F = rot90(M);
R = F(reshape(1:numel(M), size(M)))

这句话的意思是“返回哪个”。
R =
     0     0     0     0     0     0
     0     2     0     0     0     0
     2     3     1     0     0     0
     2     6     2     1     0     0
     3     8     3     2     0     0

这句话的意思是:当你旋转矩阵时,你会得到...
>> F = rot90(M)
F =
     0     2     1     1     0
     0     3     2     2     0
     2     6     3     0     0
     2     8     0     0     0
     3     0     0     0     0
     0     0     0     0     0

这是一个6行5列的矩阵。如果您考虑在线性索引F上的相应索引,则它们是:
>> reshape(1:30, size(F))
     1     7    13    19    25
     2     8    14    20    26
     3     9    15    21    27
     4    10    16    22    28
     5    11    17    23    29
     6    12    18    24    30

"如果你将元素6、11、12、16、17、18以及...都变成零,然后将其重塑为一个5行6列的矩阵,你会得到:"
>> reshape(1:30, size(M))
     1     6    11    16    21    26
     2     7    12    17    22    27
     3     8    13    18    23    28
     4     9    14    19    24    29
     5    10    15    20    25    30

现在,对应于零值的元素位于顶部,正是我们想要的。因此,通过将这个索引数组传递给 F,我们得到了所需的 R

很好,这很容易理解。 - Schnigges
4
为什么不直接使用R = reshape(F, size(M)) - Dan
@Dan 这实际上是真的。我太专注于解释它了,完全忘记了它可以进一步简化。谢谢! - Mohsen Nosratinia

4

不依赖于顺序(只需旋转彩色条并将它们推到底部)。

第一种解决方案:请注意,如果“数据”值之间存在零(例如,在给定的示例中M(1,3)0),则该方法无法起作用。如果可能存在零,请参阅下面的第二个解决方案:

[nRows nCols]= size(M);
R = [flipud(M(:,2:nCols).') zeros(nRows,1)];
[~, rowSubIndex] = sort(~~R);
index = sub2ind([nRows nCols],rowSubIndex,repmat(1:nCols,nRows,1));
R = R(index);

第二种解决方案:即使数据中存在零,也可以使用该方法:
[nRows nCols]= size(M);
S = [flipud(M(:,2:nCols).') zeros(nRows,1)];
mask = 1 + fliplr(tril(NaN*ones(nRows, nCols)));
S = S .* mask;
[~, rowSubIndex] = sort(~isnan(S));
index = sub2ind([nRows nCols],rowSubIndex,repmat(1:nCols,nRows,1));
R = S(index);
R(isnan(R)) = 0;

@Shai 只是一种快速编写 R~=0 的方法。 - Luis Mendo
@NLuisMendo从技术上讲并不更快,因为它需要评估两个布尔运算而不是一个... - Eitan T
@EitanT 我的意思是输入快,而不是执行快 :-) 在计算时间方面,使用 logical(R) 可能是最快的。 - Luis Mendo
@LuisMendo 实际上,我在使用 logical 时遇到了糟糕的性能问题,所以我怀疑它是否更快,但欢迎您自行验证这个说法 :) - Eitan T
@ElianT 使用function nada R = [0 0 0 0 0 0; 0 9 0 0 0 0; 1 3 4 0 0 0; 0 6 2 6 0 0; 2 3 1 2 0 0]; tic, for n=1:1e6, logical(R); end, toc tic, for n=1:1e6, R~=0; end, toc我得到的结果是经过了0.370217秒。 经过了0.378757秒。所以,在R2010b和Win7上,logical似乎稍微快一点。 - Luis Mendo
@ElianT 实际上那里有一个新行,但在评论中无法正确显示。 - Luis Mendo

1

替代选项,使用循环:

[nRows nCols]= size(M);
R = zeros(nRows,nCols);
for n = 1:nRows
  R((n+1):nCols,n)=fliplr(M(n,(n+1):nCols));
end

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