我正在按照下面描述的方案在MATLAB中使用向量形成矩阵:
给定的是包含任意顺序的1和0的向量x
,例如,
x = [0 1 1 0 1];
由此,我想形成一个矩阵Y
,描述如下:
Y
有m
行,其中m
是x
中的数量(这里:3
)。Y
的每一行都填充了k
条目中的一行,其中k
是矢量x
中的一个位置(此处:k = 2,3,5
)x
,这将导致:
Y = [0 1 0 0 0;
0 0 1 0 0;
0 0 0 0 1]
这与已消除其(x=0
)行的单位矩阵相同。我目前通过以下代码实现此目的:
x = [0,1,1,0,1]; %example from above
m = sum(x==1);
Y = zeros(m,numel(x));
p = 1;
for n = 1:numel(x)
if x(n) == 1
Y(p,n) = 1;
p = p+1;
end
end
它有效,但我对它不满意,因为它似乎相当低效和不优雅。任何更平滑的实现的想法,可能使用一些矩阵乘法等,是受欢迎的。
以下是一些单行替代方案:
sparse
:
Y = full(sparse(1:nnz(x), find(x), 1));
accumarray
:
Y = accumarray([(1:nnz(x)).' find(x(:))], 1);
eye
和索引。这假设Y
以前未定义:
Y(:,logical(x)) = eye(nnz(x));
使用find
获取x
中的索引,这些索引也是Y
中的列的下标。通过Y
找到矢量adding的所有元素的x
行数。使用这些来初始化Y
作为zero matrix。现在找到使用sub2ind
放置1s的线性指数。 Use these indices将Y
的元素改为1。
cols = find(x);
noofones = sum(x);
Y = zeros(noofones, size(x,2));
Y(sub2ind(size(Y), 1:noofones, cols)) = 1;
这是使用矩阵乘法的替代方法:
x = [0,1,1,0,1];
I = eye(numel(x));
% construct identity matrix with zero rows
Y = I .* x; % uses implicit expansion from 2016b or later
Y = Y(logical(x), :); % take only non-zero rows of Y
结果:
Y =
0 1 0 0 0
0 0 1 0 0
0 0 0 0 1
感谢@ SardarUsama关于简化代码的评论。
谢谢大家的好选择!我尝试了所有的解决方案,平均执行时间超过1e4执行随机(1000条目)x向量。结果如下:
full(sparse(1:nnz(x), find(x), 1));
cols = find(x);
noofones = sum(x);
Y = zeros(noofones, size(x,2));
Y(sub2ind(size(Y), 1:noofones, cols)) = 1;
Y = accumarray([(1:nnz(x)).' find(x(:))], 1);
I = speye(numel(x));
Y = I .* x;
Y = full(Y(logical(x), :));
Y(:,logical(x)) = eye(nnz(x));
从你的评论“这与一个单位矩阵相同,它消除了第(x = 0)行。”,你也可以明确地生成它:
Y = eye(length(x));
Y(x==0, :) = [];
长x
非常慢的选项,但它的full(sparse(...
比我的计算机上有10个元素的x
略快。