0

私は次の問題を抱えています: 私は である行列を持っており、20 x 1000それを size の 4 つの部分行列に分割したいと考えています20 x 250

その後、P部分行列の数 4 に等しい長さのベクトルがあると仮定して、各部分行列の操作を行いたいと思います。

P= [ 3 4 5 6] 

各サブマトリックス(A)に対して私が目指していることは次のとおりです。

最初の部分行列の場合: A(:,1:P(1))=1

2 番目のサブマトリックスと同様に、次のように続きA(:,1:P(2))=1ます。

ループなしでこれを行うにはどうすればよいですか?

4

1 に答える 1

0

cumsumベクトル化されたアプローチの 1 つは、との組み合わせを使用する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)
于 2014-10-22T03:22:24.213 に答える