简体   繁体   中英

Finding whether the rows of a matrix in Matlab “fall” within the rows of another matrix

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?

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

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:

  1. reshape(Ksets.', N, [], G) reshapes Ksets into an N × l × G 3D-array so that each subrow is now separated from the others.
  2. 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 .
  3. all(..., 1) tests if all the elements of each subrow (ie first dimension) match. any(...,2) tests if this happens for any subrow of one of the original rows (ie second dimension).
  4. 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 ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM