我遇到以下问题:我有一个20 x 1000
的矩阵,我想把它分成四个大小为20 x 250
的子矩阵。
之后,我想对每个子矩阵进行操作,假设我有一个长度等于子矩阵数的向量P
,4。
P= [ 3 4 5 6]
我打算为每个子矩阵(A)做的事情如下:
对于第一个子矩阵:A(:,1:P(1))=1
和第二个子矩阵一样:A(:,1:P(2))=1
依旧等等。
如果没有循环我怎么能这样做?
答案 0 :(得分:0)
一种矢量化方法可以使用cumsum
和bsxfun
的组合,但这可能会占用大量内存 -
blocksize = 250;
valid_idx = bsxfun(@le,[1:max(P)],P');
idx_mat = bsxfun(@plus,cumsum(valid_idx,2),[0:numel(P)-1]'*blocksize);
A(:,idx_mat(valid_idx)) = 1; %// You can replace this with "A(:,unique(idx_mat))=1;"
另一种稍微不同的方法 -
blocksize = 250;
maxP = max(P);
valid_idx = bsxfun(@le,[1:maxP],P');
idx_mat = bsxfun(@plus,[0:numel(P)-1]'*blocksize,1:maxP);
A(:,idx_mat(valid_idx))=1;
请注意,要真正了解矢量化解决方案的好处,您需要在原始循环代码进行大量迭代时使用它。否则,与设置矢量化方法的准备工作相关的开销将是浪费。因此,我假设您的实际案例涉及的不仅仅是4个子矩阵。
另一种基于cumsum
的方法,这个方法必须有趣才能尝试,甚至可能证明是最好的 -
blocksize = 250;
%//Get monotonically increasing labels within each group, defined by limits from idx
array1 = zeros(1,sum(P));
grp_starts = cumsum(P(1:end-1))+1;
array1(grp_starts) = P(1:end-1);
grp_labels = [1:numel(array1)] - cumsum(array1);
%// Get offsetted indices
array2 = zeros(1,sum(P));
array2(grp_starts) = blocksize;
offsetted_grp_labels = grp_labels + cumsum(array2);
A(:,offsetted_grp_labels)=1; %// perform the operation(s)