Matlab 矢量化代码的性能:从索引向量创建一个稀疏矩阵,每行1个
我有一个大的列向量Matlab 矢量化代码的性能:从索引向量创建一个稀疏矩阵,每行1个,matlab,for-loop,vectorization,sparse-matrix,Matlab,For Loop,Vectorization,Sparse Matrix,我有一个大的列向量y,包含从1到10的整数值。我想把它转换成一个矩阵,其中每一行都是0,除了在y的相应行的值所给出的索引处的1之外 这个例子应该更清楚: y = [3; 4; 1; 10; 9; 9; 4; 2; ...] % gets converted to: Y = [ 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 0 0 0 0 0 0 0 0 1; 0 0 0
y
,包含从1到10的整数值。我想把它转换成一个矩阵,其中每一行都是0,除了在y
的相应行的值所给出的索引处的1之外
这个例子应该更清楚:
y = [3; 4; 1; 10; 9; 9; 4; 2; ...]
% gets converted to:
Y = [
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 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 1 0;
0 0 0 1 0 0 0 0 0 0;
0 1 0 0 0 0 0 0 0 0;
...
]
我已经为此编写了以下代码(它可以工作):
我知道有很多方法可以删除代码中的for循环(矢量化)。包含以下内容,包括:
Y = full(sparse(1:length(y), y, ones(length(y),1)));
但是我必须将y
转换为double才能使用它,结果实际上比我的“for”方法慢3倍,使用10.000.000作为y
的长度
y
,进行这种矢量化是否可能会带来更好的性能?我已经读过很多次,矢量化计算可以带来更好的性能(不仅仅是在MATLAB中),但这种解决方案似乎可以带来更多的计算sparse
这样的事情对你不管用吗
tic;
N = 1e6;
y = randperm( N );
Y = spalloc( N, N, N );
inds = sub2ind( size(Y), y(:), (1:N)' );
Y = sparse( 1:N, y, 1, N, N, N );
toc
上述产出
运行时间为0.144683秒
似乎您正在寻找完整的数字矩阵
Y
作为输出。因此,您可以尝试这种方法-
m = numel(y);
Y1(m,10) = 0; %// Faster way to pre-allocate zeros than using function call `zeros`
%// Source - http://undocumentedmatlab.com/blog/preallocation-performance
linear_idx = (y-1)*m+(1:m)'; %//'# since y is mentioned as a column vector,
%// so directly y can be used instead of y(:)
Y1(linear_idx)=1; %// Y1 would be the desired output
标杆管理 使用并稍微增加数据量-
y = randi([1 10], [1.5e6 1], 'double');
最后使用Y(m,10)=0执行前面提到的更快的预分配方案代码>而不是Y=0(m,10)代码>,我在我的系统上得到了这些结果-
>> testIndicatorMatrix
ans =
0.1798
0.4651
0.1693
0.1457
这就是这里提到的矢量化方法
(基准测试套件中的最后一种)比for loop
代码(基准测试套件中的第一种)的性能提高了15%以上。因此,如果您使用大数据量并打算获得稀疏矩阵的完整版本,这种方法将是有意义的(在我个人看来)。下面是一个测试:
function [t,v] = testIndicatorMatrix()
y = randi([1 10], [1e6 1], 'double');
funcs = {
@() func1(y);
@() func2(y);
@() func3(y);
@() func4(y);
};
t = cellfun(@timeit, funcs, 'Uniform',true);
v = cellfun(@feval, funcs, 'Uniform',false);
assert(isequal(v{:}))
end
我得到:
>> testIndicatorMatrix
ans =
0.0388
0.1712
0.0490
0.0430
这样一个简单的for循环可以在运行时进行动态JIT编译,并且运行速度非常快(甚至比矢量化代码稍微快一点) 如果您将数组名称从y
和y
更改为不同的名称,如x
和y
,可能会有所帮助。有一次我用ECG
作为一个名字,它让我的代码运行得很慢,直到我意识到ECG
是一个MATLAB函数。这是一个很好的建议;)也许读者也有点困惑。现在我不能更改它,或者所有的问题都需要修改,但我下次会记住。很好的基准测试+1.你能用Y(m,10)=0
而不是最后两个funcs
,因为这必须加快它的速度;我怀疑创建指标矩阵的任务是代码中的瓶颈!对于一个包含数百万个元素的向量,它们都在几分之一秒内运行:)是的,但我想在这个问题的背景下,看看到目前为止提到的方法是如何公平的,我想这是公平的。该死,太多的“公平”用在那里:)对。我想我们应该提一提这个问题:事实上,最初的来源是这个,我想-我的意思是我首先在那里发现了这个。
function Y = func1(y)
m = numel(y);
Y = zeros(m, 10);
for i = 1:m
Y(i, y(i)) = 1;
end
end
function Y = func2(y)
m = numel(y);
Y = full(sparse(1:m, y, 1, m, 10, m));
end
function Y = func3(y)
m = numel(y);
Y = zeros(m,10);
Y(sub2ind([m,10], (1:m).', y)) = 1;
end
function Y = func4(y)
m = numel(y);
Y = zeros(m,10);
Y((y-1).*m + (1:m).') = 1;
end
>> testIndicatorMatrix
ans =
0.0388
0.1712
0.0490
0.0430