根据部分填充的向量形成 'partial' 单位矩阵

Forming a 'partial' identity-matrix according to a partially filled vector

我目前正在 MATLAB 中按照下面描述的方案从向量形成矩阵:

给定一个向量 x 包含任意顺序的 1 和 0,例如

x = [0 1 1 0 1]; 

据此,我想形成一个矩阵Y,描述如下:

我目前正在通过以下代码实现此目的:

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

它可以工作,但我对它有点不满意,因为它看起来效率低下且不够优雅。欢迎任何关于更流畅实施的想法,例如使用一些矩阵乘法等。

find to obtain the indices of ones in x which are also the column subscripts of ones in Y. Find the number of rows of Y by adding all the elements of the vector x. Use these to initialise Y as a zero matrix. Now find the linear indices to place 1s using sub2ind. Use these indicesY的元素改成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 对代码进行了一些简化的评论。

这里有几个单行选项:

  • 使用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));
    

感谢大家提供不错的选择!我尝试了您所有的解决方案,并为随机(1000 个条目)x 向量执行了超过 1e4 次的平均执行时间。以下是结果:

  1. (7.3e-4 秒)full(sparse(1:nnz(x), find(x), 1));
  2. (7.5e-4 秒)cols = find(x); noofones = sum(x); Y = zeros(noofones, size(x,2)); Y(sub2ind(size(Y), 1:noofones, cols)) = 1;
  3. (7.7e-4 秒)Y = accumarray([(1:nnz(x)).' find(x(:))], 1);
  4. (1.7e-3 秒)I = speye(numel(x)); Y = I .* x; Y = full(Y(logical(x), :));
  5. (3.1e-3 秒)Y(:,logical(x)) = eye(nnz(x));

根据您的评论 "This is identical to an identity matrix, that has its (x=0)th rows eliminated.",好吧,您也可以这样明确地生成它:

Y = eye(length(x));
Y(x==0, :) = [];

x 的选项非常慢,但在我的计算机上有 10 个元素的 x 时,它的运行速度比 full(sparse(... 稍快。