根据部分填充的向量形成“部分”单位矩阵

问题描述 投票:2回答:5

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

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

x = [0 1 1 0 1]; 

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

  • Ym行,其中mx中的数量(这里: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

它有效,但我对它不满意,因为它似乎相当低效和不优雅。任何更平滑的实现的想法,可能使用一些矩阵乘法等,是受欢迎的。

arrays matlab matrix vector matrix-multiplication
5个回答
5
投票

以下是一些单行替代方案:

  • 使用sparseY = full(sparse(1:nnz(x), find(x), 1));
  • 类似但与accumarrayY = accumarray([(1:nnz(x)).' find(x(:))], 1);
  • 使用eye和索引。这假设Y以前未定义: Y(:,logical(x)) = eye(nnz(x));

4
投票

使用find获取x中的索引,这些索引也是Y中的列的下标。通过Y找到矢量adding的所有元素的x行数。使用这些来初始化Y作为zero matrix。现在找到使用sub2ind放置1s的线性指数。 Use these indicesY的元素改为1。

cols = find(x);
noofones = sum(x);
Y = zeros(noofones, size(x,2));
Y(sub2ind(size(Y), 1:noofones, cols)) = 1;

4
投票

这是使用矩阵乘法的替代方法:

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关于简化代码的评论。


1
投票

谢谢大家的好选择!我尝试了所有的解决方案,平均执行时间超过1e4执行随机(1000条目)x向量。结果如下:

  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));

1
投票

从你的评论“这与一个单位矩阵相同,它消除了第(x = 0)行。”,你也可以明确地生成它:

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

x非常慢的选项,但它的full(sparse(...比我的计算机上有10个元素的x略快。

© www.soinside.com 2019 - 2024. All rights reserved.