Reputation: 2299
I have a matrix Ksets
in Matlab with size Gx(l*N)
and a matrix A
with size MxN
.
Each row of Ksets
can be decomposed into l
sub-rows with size 1xN
.
Let me explain better with an example.
clear
N=3;
l=4;
G=2;
M=5;
Ksets=[1 2 3 5 6 7 9 10 11 0 0 0;
13 14 15 1 2 3 21 22 23 1 1 1]; %Gx(l*N)
A=[1 2 3;
5 6 7;
21 22 23;
1 2 3;
0 0 0]; %MxN
In the example:
row 1
of Ksets
is composed of l
sub-rows with size 1xN
: [1 2 3]
, [5 6 7]
, [9 10 11]
, [0 0 0]
;
row 2
of Ksets
is composed of l
sub-rows with size 1xN
: [13 14 15]
, [1 2 3]
, [21 22 23]
, [1 1 1]
.
I assume that each row of Ksets
does not contain equal sub-rows.
I would like your help to construct a matrix Response
with size GxM
with Response(g,m)=1
if the row A(m,:)
is equal to one of the l
sub-rows of Ksets(g,:)
and zero otherwise.
Continuing the example above
Response= [1 1 0 1 1;
1 0 1 1 0]; %GxM
This code does what I want:
Responsecorrectmy=zeros(G, M);
for x=1:G
for c=1:l
Responsecorrectmy(x,:)=Responsecorrectmy(x,:)+...
ismember(A,Ksets(x,(c-1)*N+1:c*N), 'rows').';
end
end
My code consists of 2 loops which is undesirable because in my real algorithm G,l
are big. Do you have suggestions without loops?
Upvotes: 1
Views: 61
Reputation: 104555
It's quite hard to do this vectorized, especially if the subsets you're trying to compare to are embedded in each row. What can be done for efficiency is to change the Ksets
into a 3D matrix where each slice contains those subsets formatted into a 2D matrix where each subset is on a per-row basis. You can then use ismember
combined with using just one loop on each row individually and populate your results.
Ksets2 = permute(reshape(Ksets.', [N l G]), [2 1 3]);
Response = false(G, M);
for i = 1 : G
Response(i, :) = ismember(A, Ksets2(:,:,i), 'rows')';
end
The first statement reshapes your data so that it becomes a 3D matrix, but because of MATLAB's column major processing, and because your subsets are in row major, we have to transpose the data prior to reshaping. However, this results in each column being in a subset, so we have to transpose each slice independently with the permute
operation.
Once that's done, we allocate a matrix of the desired size, then loop through each row in Ksets
(now transformed into rows of subsets) to produce the desired result.
We get:
>> Response
Response =
2×5 logical array
1 1 0 1 1
1 0 1 1 0
Upvotes: 1
Reputation: 112769
It can be done with a little reshaping and dimension-permuting:
Response = permute(any(all(bsxfun(@eq, reshape(Ksets.', N, [], G), permute(A, [2 3 4 1])), 1), 2), [3 4 1 2]);
This works as follows:
reshape(Ksets.', N, [], G)
reshapes Ksets
into an N
×l
×G
3D-array so that each subrow is now separated from the others.bsxfun(@eq, ..., permute(A, [2 3 4 1]))
creates an N
×l
×G
×M
4D-array with the result of comparing each element of the 3D-array from step 1 with each value in A
.all(..., 1)
tests if all the elements of each subrow (i.e. first dimension) match. any(...,2)
tests if this happens for any subrow of one of the original rows (i.e. second dimension).permute(..., [3 4 1 2])
removes the first two dimensions (which became singleton in step 3), giving the desired G
×M
result. (It would not be safe to use squeeze
for this because it would incorrectly remove the third dimension if G=1
).Upvotes: 1