对bsxfun 的一个非常简单的调用就可以解决问题:
>> n = 3;
>> v = [1,1,3,2].';
>> M = bsxfun(@eq, v, 1:n)
M =
1 0 0
1 0 0
0 0 1
0 1 0
代码的工作原理实际上非常简单。 bsxfun 是所谓的 Binary Singleton EXpansion 函数。这样做是您提供两个任意大小的数组/矩阵,只要它们是可广播的。这意味着它们需要能够扩展大小,以使它们的大小相等。在这种情况下,v 是您感兴趣的向量并且是第一个参数 - 请注意它是转置的。第二个参数是一个从 1 到 n 的向量。现在将发生的情况是列向量v 被replicated / expands 的值与n 一样多,第二个向量被复制的行数为有v。然后我们在这两个数组之间做一个eq/equals 运算符。实际上,这个扩展矩阵的第一列全为 1,第二列全为 2,直到n。通过在这两个矩阵之间执行eq,您实际上可以确定v 中的哪些值等于相应的列索引。
这里是每个功能的详细时间测试和细分。我将每个实现放入一个单独的函数中,并且我还让n=max(v) 让 Luis 的第一个代码能够工作。我使用timeit 为每个函数计时:
function timing_binary
n = 10000;
v = randi(1000,n,1);
m = numel(v);
function luis_func()
M1 = full(sparse(1:m,v,1));
end
function luis_func2()
%m = numel(v);
%n = 3; %// or compute n automatically as n = max(v);
M2 = zeros(m, n);
M2((1:m).' + (v-1)*m) = 1;
end
function ray_func()
M3 = bsxfun(@eq, v, 1:n);
end
function op_func()
M4= ones(1,m)'*[1:n] == v * ones(1,n);
end
t1 = timeit(@luis_func);
t2 = timeit(@luis_func2);
t3 = timeit(@ray_func);
t4 = timeit(@op_func);
fprintf('Luis Mendo - Sparse: %f\n', t1);
fprintf('Luis Mendo - Indexing: %f\n', t2);
fprintf('rayryeng - bsxfun: %f\n', t3);
fprintf('OP: %f\n', t4);
end
此测试假设 n = 10000 和向量 v 是一个 10000 x 1 的向量,包含从 1 到 1000 的随机分布的整数。顺便说一句,我不得不修改 Luis 的第二个函数,以便索引能够按照添加的要求工作兼容维度的向量。
运行这段代码,我们得到:
>> timing_binary
Luis Mendo - Sparse: 0.015086
Luis Mendo - Indexing: 0.327993
rayryeng - bsxfun: 0.040672
OP: 0.841827
Luis Mendo 的 sparse 代码获胜(如我所料),然后是 bsxfun,然后是索引,然后是您提出的使用矩阵运算的方法。时间以秒为单位。