在 MATLAB 中用列向量给出的索引创建矩阵的向量化方法

Vectorized approach to creating a matrix with 1s in indices given by a column vector in MATLAB

假设我得到一个 1000x1 的列向量,其值范围为 1-10。现在我想把它变成一个 1000x10 矩阵,其中对于每一行,列向量中的值给定的列中都有一个 1。我在下面有一个正确的实现,但是有没有一种优雅的方法可以在没有 for 循环的情况下做到这一点?

ymat = zeros(1000, 10);
y = randi([1,10],1000,1);
for i=1:1000
    ind = y(i);
    ymat(i,ind)=1;
end

当然可以。使用 repmatbsxfun。例如,

bsxfun(@eq,repmat(1:10,numel(y),1),repmat(y,1,10))

答案:

 ...
 0     0     0     1     0     0     0     0     0     0
 0     0     0     0     0     0     0     0     1     0
 0     0     0     0     0     0     0     1     0     0
 0     0     0     0     0     0     0     0     1     0
 0     0     0     0     0     1     0     0     0     0
 0     0     0     0     0     0     1     0     0     0
 0     0     0     0     0     0     0     0     0     1
 0     0     0     0     1     0     0     0     0     0
 1     0     0     0     0     0     0     0     0     0
 0     0     0     0     0     0     0     0     1     0

>> 

您有一组列索引,对应的行索引应该是1:1000

有两个选项可以从中生成矩阵。

  1. accumarray

  2. 稀疏

acccumarray 将生成 full 矩阵,sparse 将生成 sparse 矩阵。

在您的情况下,生成的矩阵密度为 10%,可以视为稀疏矩阵。

% Full matrix using accumarray
ymat = accumarray([(1:1000).', y], ones(1000,1), [1000, 10]);

% Sparse matrix using sparse
ymat = sparse(1:1000, y, ones(1000,1), 1000, 10, 1000);

计算时间

我 运行 带有 y = 1000 x 1y = 10000 x 1 的代码。

  1. y = 1000 x 1

  1. y = 10000 x 1

我添加了@transversality 条件建议的代码。

原来accumarray最快,sparse最慢

accumarray 显示较小尺寸的更好性能,但 accumarraybsxfun(@eq) 之间的差距随着我们增加数组的大小而变小。

我们可以使用这些条目的“linear index”一次访问 ymat 中条目的任何子集。由于我们已经有了包含列坐标的y,而行坐标只是1:100,我们可以很容易地用sub2ind得到它们的线性索引值,然后将[=中的所有索引值设置为1 12=]:

ymat(sub2ind([1000 10], (1:1000)', y)) = 1

但是请注意,必须事先创建具有适当大小的 ymat

您还可以使用ind2vec函数:

ymat=full(ind2vec(y.').')