How to vectorize row-wise diagonalization of a matrix
我有一个n×m矩阵,我想将其转换为mn×m矩阵,结果的每个m×m块都包含每一行的对角线。
例如,如果输入为:
输出应为:
1
| [1 0; 0 2; 3 0; 0 4; 5 0; 0 6] |
当然,我不想用for循环一步一步地组装矩阵。
有矢量化的简单方法可以实现这一目标吗?
这是一个简单的矢量化解决方案,假设X是输入矩阵:
另一种替代方法是使用sparse,这可以写成整齐的单线:
-
1:这必须是已被接受的解决方案; 2d步骤是Octave矩阵索引的另一个惊人应用
-
此解决方案比使用bsxfun更可取,因为它不需要传递函数,因此可以在本机代码中更好地进行优化。另外,请考虑使Y稀疏。
-
@dspyz sparse是一个很好的建议,谢谢。我添加了另一个解决方案:-)
对于执行此操作的矢量化方法,将对角元素的线性索引创建到结果矩阵中,然后直接进行赋值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| %# create some input data
inArray = [10 11; 12 13; 14 15];
%# make the index array
[nr,nc ]= size(inArray );
idxArray = reshape(1:nr*nc,nc,nr )';
idxArray = bsxfun (@plus,idxArray, 0:nr*nc:nr*nc^ 2- 1);
%# create output
out = zeros(nr*nc,nc );
out (idxArray ) = inArray (: );
out =
10 0
0 11
12 0
0 13
14 0
0 15 |
- 您能解释一下bsxfun的作用吗?
-
@ ja72:bsxfun自动扩展数组,以便您可以例如将n×1数组添加到n×m数组中。开头的句柄(在这种情况下为@plus)指示要执行的操作。与使用repmat相比,它更快,更方便。
我看到的最简单的方法实际上是非常简单的,使用简单的索引引用和reshape函数:
1 2 3
| I = [1 2; 3 4; 5 6];
J(:, [1, 4]) = I;
K = reshape(J', 2, 6)'; |
如果您检查J,它看起来像这样:
1 2 3 4
| J =
1 0 0 2
3 0 0 4
5 0 0 6 |
矩阵K正是想要的:
1 2 3 4 5 6 7
| K =
1 0
0 2
3 0
0 4
5 0
0 6 |
正如Eitan T在评论中指出的那样,以上内容仅适用于示例,并不涵盖一般解决方案。因此,下面是一般的解决方案,如问题中所述,具有m和n。
如果要对其进行测试以使其正常运行,请使用
注意:如果J已经存在,则可能会导致问题。在这种情况下,您还需要使用
-
-1:这将引发错误:"下标的分配尺寸不匹配。"。即使它可以正常工作,也不是正确的输出。
-
尺寸不匹配是由错字引起的-我说的是J(:,1:4),但应该说是J(:,[1,4])。我抄写不正确,仅此而已。该错误已得到纠正,并且应该可以按预期工作。至于输出,如果您注意的话,我正在描述矩阵J,它不是最终的输出。 K是输出,它看起来与litro要求的完全一样……至少,它在Octave音阶上。
-
现在可以使用了,所以我已经删除了downvote。但是请注意,它不是通用的,因为它仅在I具有两列时才起作用。
-
是的,它不是通用的,就像我写的那样。我将添加一个更通用的解决方案,因为它确实可以很好地概括。
-
完毕。相当有信心它应能按预期工作。不要以为有错字。
-
没有错字1为您的方法。但是,请注意,必须先添加clear J,然后再为其分配新值,以确保一切正常。
这可能不是计算效率最高的解决方案,但这是使用kron的1-liner:
1 2 3 4 5 6 7 8 9
| A = [1 2; 3 4; 5 6];
B = diag(reshape(A', 6, 1) * kron (ones(3, 1), eye(2))
% B =
% 1 0
% 0 2
% 3 0
% 0 4
% 5 0
% 0 6 |
如果A为n x m,则可以概括为: