一个非常简单的调用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 S英格尔顿EX平移函数。这样做的作用是,您提供两个任意大小的数组/矩阵,只要它们是可广播的。这意味着它们需要能够扩大尺寸,以使它们的尺寸相等。在这种情况下,v
是您感兴趣的向量,并且是第一个参数 - 请注意它是转置的。第二个参数是一个从 1 到n
。现在会发生的是列向量v
gets 复制的 / expands对于尽可能多的值n
并且第二个向量被复制了尽可能多的行v
。然后我们做一个eq
这两个数组之间的 / 等于运算符。该扩展矩阵实际上第一列中全为 1,第二列中全为 2,直到n
。通过做一个eq
在这两个矩阵之间,您实际上确定了哪些值v
等于相应的列索引。
以下是详细的时间测试和每个功能的细分。我将每个实现放入一个单独的函数中,并且还让n=max(v)
这样路易斯的第一个代码就能工作。我用了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
是一个由从 1 到 1000 的随机分布整数组成的 10000 x 1 向量。顺便说一句,我必须修改 Luis 的第二个函数,以便索引能够工作,因为加法需要兼容维度的向量。
运行这段代码,我们得到:
>> timing_binary
Luis Mendo - Sparse: 0.015086
Luis Mendo - Indexing: 0.327993
rayryeng - bsxfun: 0.040672
OP: 0.841827
路易斯·门多的sparse
代码获胜(如我所料),然后是bsxfun
,然后是索引,然后是您建议的使用矩阵运算的方法。时间以秒为单位。