我需要在 MATLAB 中创建具有以下要求的矩阵。v
例如,给定一个向量,[1,2,2,1,3,5,1]
我需要形成一个矩阵:
[1 0 0 1 0 0 1;
0 1 1 0 0 0 0;
0 0 0 0 1 0 0;
0 0 0 0 0 0 0;
0 0 0 0 0 1 0]
即矩阵的第 th 列在 rowi
仅包含一个非零元素(单个) 。如何避免循环并以有效的方式做到这一点?1
v[i]
其他人指出循环在这里很好。我会指出稀疏的要好得多。您的矩阵非常稀疏,因此请使用稀疏的能力来解决问题,并在矩阵很大的情况下节省大量存储空间。
N = 3000;
v = ceil(rand(1,3000)*3000);
tic
A = zeros(N,N);
for i = 1:N
A(v(i),i) = 1;
end
toc
Elapsed time is 0.069082 seconds.
tic
B = sparse(v,1:N,1,N,N);
toc
Elapsed time is 0.001308 seconds.
因此,如果矩阵很大,则在时间上存在巨大差异。
空间呢?
whos A B
Name Size Bytes Class Attributes
A 3000x3000 72000000 double
B 3000x3000 72008 double sparse
其他方面的矩阵是相同的。
sum(sum(abs(A - B)))
ans =
0
稀疏矩阵占用的空间很小,您可以像使用任何其他矩阵一样使用它。
使用 MATLAB 的功能。
首先,我必须给出我的标准免责声明,尽管普遍认为在 MATLAB 中通常应该避免循环,但在 MATLAB 的现代版本中,循环实际上变得更加高效,这在很大程度上要归功于 JIT 加速器。因此,当然,对您的代码进行基准测试以确定循环是否真的是瓶颈。
也就是说,我对如何在没有循环的情况下解决这个问题的第一个想法是索引一个单位矩阵(如下所示)。
identityMatrix = eye(max(v(:)));
result = identityMatrix(:,v);
我认为这是一个不错的、干净的解决方案;但是,我不一定知道它比使用循环更有效。作为比较,我使用循环实现了以下解决方案:
numRows = max(v(:));
numCols = length(v);
result = zeros(numRows,numCols);
for i=1:numCols
result(v(i),i) = 1;
end
根据我的测试运行,对于那些v
不是很长的情况,顶级(无循环)解决方案通常更快。但是,当v
包含许多元素(例如 >100)时,我实际上看到了循环解决方案击败替代方案的平均时间。
>> v = [1,2,2,1,3,5,1];
>> a = zeros(max(v), length(v));
>> a((0 : size(a, 1) : numel(a) - 1) + v) = 1
a =
1 0 0 1 0 0 1
0 1 1 0 0 0 0
0 0 0 0 1 0 0
0 0 0 0 0 0 0
0 0 0 0 0 1 0
m = max(v);
n = length(v);
M = zeros(m, n);
M([0:(n-1)]*m + v) = 1;
这与在神经网络分配中创建目标向量所需的步骤非常相似(第 5 周 - 来自 Andrew NG ML 课程的手写数字识别)。我们必须为单个训练输出创建一个 10 X 1 大小的向量,例如输出 y。如果 y 中的第 i 个训练输出为 2,则向量化后的第 i 个输出为 [0 1 0 0 0 0 0 0 0 0]'。因此,对于 5000 个训练示例,我们需要 5000 个向量。
事不宜迟,代码是:
>> v = [1,2,2,1,3,5,1];
>> v_vec = (1:5)==v';
>> v_vec
v_vec =
1 0 0 0 0
0 1 0 0 0
0 1 0 0 0
1 0 0 0 0
0 0 1 0 0
0 0 0 0 1
1 0 0 0 0
>> v_vec'
ans =
1 0 0 1 0 0 1
0 1 1 0 0 0 0
0 0 0 0 1 0 0
0 0 0 0 0 0 0
0 0 0 0 0 1 0
v_vec' 是所需的输出。一个有用的链接:https ://www.ee.columbia.edu/~marios/matlab/Matlab%20Tricks.pdf