count match value two matrix using bsxfun - matlab

I use c=bsxfun(#eq,b,a) to compare value of two matrix. but I find it difficult to count un-match values. for example, I use this code
a = [1 2 3 4 7 6; ...
3 2 4 6 7 2 ];
b = [1 3 2 4 5 7; ...
3 4 5 6 7 2; ...
2 3 4 5 6 6];
for i = 1:size(a,1)
c= bsxfun(#eq,a(i,:),b)
match = sum(c')
end
and result
c =
1 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
match =
2 1 1
c =
0 0 0 0 0 0
1 0 0 1 1 1
0 0 1 0 0 0
match =
0 4 1
I want to save value first match matrix with second match. for example
total_match =
2 5 2
Do you have any suggestion ? thanks..

No need for loop
match = bsxfun( #eq, permute( a, [1 3 2]), permute( b, [3 1 2] ) ); % result in 2x3x6 boolean
match = sum( match, 3 ); % sum matches across rows of a--b
total_match = sum( match, 1 );
PS
It is best not to use i and j as variable names in Matlab.

Related

in matlab,how can i put all zeros in the end of the rows in a matrix? [duplicate]

I have a matrix in MATLAB with zeroes and I would like to get another matrix with the first N non-zero elements in each row. Let's say for example N = 3, and the matrix is
A = [ 0 0 2 0 6 7 9;
3 2 4 7 0 0 6;
0 1 0 3 4 8 6;
1 2 0 0 0 1 3]
I'd like the result to be:
B = [2 6 7;
3 2 4;
1 3 4;
1 2 1]
I have a huge matrix so I would like to do it without a loop, could you please help me? Thanks a lot!
Since MATLAB stores a matrix according to column-major order, I first transpose A, bubble up the non-zeros, and pick the first N lines, and transpose back:
N = 3;
A = [ 0 0 2 0 6 7 9;
3 2 4 7 0 0 6;
0 1 0 3 4 8 6;
1 2 0 0 0 1 3];
Transpose and preallocate output B
At = A';
B = zeros(size(At));
At =
0 3 0 1
0 2 1 2
2 4 0 0
0 7 3 0
6 0 4 0
7 0 8 1
9 6 6 3
Index zeros
idx = At == 0;
idx =
1 0 1 0
1 0 0 0
0 0 1 1
1 0 0 1
0 1 0 1
0 1 0 0
0 0 0 0
Bubble up the non-zeros
B(~sort(idx)) = At(~idx);
B =
2 3 1 1
6 2 3 2
7 4 4 1
9 7 8 3
0 6 6 0
0 0 0 0
0 0 0 0
Select first N rows and transpose back
B(1:N,:)'
You can do the bubbling in row-major order, but you would need to retrieve the row and column subscripts with find, and do some sorting and picking there. It becomes more tedious and less readable.
Using accumarray with no loops:
N = 3;
[ii,jj] = find(A); [ii,inds]=sort(ii); jj = jj(inds);
lininds = ii+size(A,1)*(jj-1);
C = accumarray(ii,lininds,[],#(x) {A(x(1:N)')}); %' cell array output
B = vertcat(C{:})
B =
2 6 7
3 2 4
1 3 4
1 2 1
Usually I don't go with a for loop solution, but this is fairly intuitive:
N = 3;
[ii,jj] = find(A);
B = zeros(size(A,1),N);
for iRow = 1:size(A,1),
nzcols = jj(ii==iRow);
B(iRow,:) = A(iRow,nzcols(1:N));
end
Since you are guaranteed to have more than N nonzeros per row of A, that should get the job done.
One-liner solution:
B = cell2mat(cellfun(#(c) c(1:N), arrayfun(#(k) nonzeros(A(k,:)), 1:size(A,1), 'uni', false), 'uni', false)).'
Not terribly elegant or efficient, but so much fun!
N = 3;
for ii=1:size(A,1);
B(ii,:) = A( ii,find(A(ii,:),N) );
end
Actually , you can do it like the code blow:
N=3
for n=1:size(A,1)
[a b]=find(A(n,:)>0,N);
B(n,:)=A(n,transpose(b));
end
Then I think this B matrix will be what you want.

Finding a critical point in matrix

I'm attempting to find a critical point in a matrix. The value at index (i,j) should be greater than or equal to all elements in its row, and less than or equal to all elements in its column.
Here is what I have (it's off but I'm close):
function C = critical(A)
[nrow ncol] = size(A);
C = [];
for i = 1:nrow
for j = 1:ncol
if (A(i,j) >= A(i,1:end)) && (A(i,j) <= A(1:end,j))
C = [C ; A(i,j)]
end
end
end
You can use logical indexing.
minI = min(A,[],1);
maxI = max(A,[],2);
[row,col] = find(((A.'==maxI.').' & A==minI) ==1)
Details
Remember that Matlab is column major. We therefore transpose A and maxI.
A = [
3 4 1 1 2
2 4 2 1 4
4 3 2 1 2
3 3 1 1 1
2 3 0 2 1];
A.'==maxI.'
ans =
0 0 1 1 0
1 1 0 1 1
0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
Then do the minimum
A==minI
ans =
0 0 0 1 0
1 0 0 1 0
0 1 0 1 0
0 1 0 1 1
1 1 1 0 1
And then multiply the two
((A.'==maxI.').' & A==minI)
ans =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
0 1 0 0 0
Then find the rows and cols
[row,col] = find(((A.'==maxI.').' & A==minI) ==1)
row =
4
5
col =
2
2
Try this vectorised solution using bsxfun
function [ r,c,criP ] = critical( A )
%// finding the min and max values of each col & row resptly
minI = min(A,[],1);
maxI = max(A,[],2);
%// matching all the values of min & max for each col and row resptly
%// getting the indexes of the elements satisfying both the conditions
idx = find(bsxfun(#eq,A,maxI) & bsxfun(#eq,A,minI));
%// getting the corresponding values from the indexes
criP = A(idx);
%// Also getting corresponding row and col sub
[r,c] = ind2sub(size(A),idx);
end
Sample Run:
r,c should be a vector of equal length which represents the row and column subs of each Critical point. While val is a vector of same length giving the value of the critical point itself
>> A
A =
3 4 1 1 2
2 4 2 1 4
4 3 2 1 2
3 3 1 1 1
2 3 0 2 1
>> [r,c,val] = critical(A)
r =
4
5
c =
2
2
val =
3
3
I think there is a simpler way with intersect:
>> [~, row, col] = intersect(max(A,[],2), min(A));
row =
4
col =
2
UPDATE:
With intersect, in case you have multiple critical points, it will only give you the first one. To have all the indicies, there is also another simple way:
>> B
B =
3 4 1 4 2 5
2 5 2 4 4 4
4 4 2 4 2 4
3 4 1 4 1 4
2 5 4 4 4 5
>> row = find(ismember(max(B,[],2),min(B)))
row =
3
4
>> col = find(ismember(min(B),max(B,[],2)))
col =
2 4 6
Note that the set of critical points now should be the combination of row and col, means you have total 6 critical points in this example: (3,2),(4,2),(3,4),(4,4),(3,6),(4,6).
Here you can find how to export such combination.

How to generate a matrix of vector combinations with zeros for excluded elements?

I want to create a matrix from all combinations of elements of one vector that fulfill a condition
For example, I have this vector
a = [1 2 3 4 5]
and want to create a matrix like
a = [1 0 0 0 0;
1 2 0 0 0;
1 2 3 0 0;
1 2 3 4 0;
1 2 3 4 5;
0 2 0 0 0;
0 2 3 0 0;
........;]
and then get the rows that fulfill the condition I can use the command:
b = sum(a')' > value
but I don't know how to generate the matrix
You can generate all possible binary combinations to determine the matrix you want:
a = [1 2 3];
n = size(a,2);
% generate bit combinations
c =(dec2bin(0:(2^n)-1)=='1');
% remove first line
c = c(2:end,:)
n_c = size(c,1);
a_rep = repmat(a,n_c,1);
result = c .* a_rep
Output:
c =
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
result =
0 0 3
0 2 0
0 2 3
1 0 0
1 0 3
1 2 0
1 2 3

Find the first N non-zero elements in each row of a matrix

I have a matrix in MATLAB with zeroes and I would like to get another matrix with the first N non-zero elements in each row. Let's say for example N = 3, and the matrix is
A = [ 0 0 2 0 6 7 9;
3 2 4 7 0 0 6;
0 1 0 3 4 8 6;
1 2 0 0 0 1 3]
I'd like the result to be:
B = [2 6 7;
3 2 4;
1 3 4;
1 2 1]
I have a huge matrix so I would like to do it without a loop, could you please help me? Thanks a lot!
Since MATLAB stores a matrix according to column-major order, I first transpose A, bubble up the non-zeros, and pick the first N lines, and transpose back:
N = 3;
A = [ 0 0 2 0 6 7 9;
3 2 4 7 0 0 6;
0 1 0 3 4 8 6;
1 2 0 0 0 1 3];
Transpose and preallocate output B
At = A';
B = zeros(size(At));
At =
0 3 0 1
0 2 1 2
2 4 0 0
0 7 3 0
6 0 4 0
7 0 8 1
9 6 6 3
Index zeros
idx = At == 0;
idx =
1 0 1 0
1 0 0 0
0 0 1 1
1 0 0 1
0 1 0 1
0 1 0 0
0 0 0 0
Bubble up the non-zeros
B(~sort(idx)) = At(~idx);
B =
2 3 1 1
6 2 3 2
7 4 4 1
9 7 8 3
0 6 6 0
0 0 0 0
0 0 0 0
Select first N rows and transpose back
B(1:N,:)'
You can do the bubbling in row-major order, but you would need to retrieve the row and column subscripts with find, and do some sorting and picking there. It becomes more tedious and less readable.
Using accumarray with no loops:
N = 3;
[ii,jj] = find(A); [ii,inds]=sort(ii); jj = jj(inds);
lininds = ii+size(A,1)*(jj-1);
C = accumarray(ii,lininds,[],#(x) {A(x(1:N)')}); %' cell array output
B = vertcat(C{:})
B =
2 6 7
3 2 4
1 3 4
1 2 1
Usually I don't go with a for loop solution, but this is fairly intuitive:
N = 3;
[ii,jj] = find(A);
B = zeros(size(A,1),N);
for iRow = 1:size(A,1),
nzcols = jj(ii==iRow);
B(iRow,:) = A(iRow,nzcols(1:N));
end
Since you are guaranteed to have more than N nonzeros per row of A, that should get the job done.
One-liner solution:
B = cell2mat(cellfun(#(c) c(1:N), arrayfun(#(k) nonzeros(A(k,:)), 1:size(A,1), 'uni', false), 'uni', false)).'
Not terribly elegant or efficient, but so much fun!
N = 3;
for ii=1:size(A,1);
B(ii,:) = A( ii,find(A(ii,:),N) );
end
Actually , you can do it like the code blow:
N=3
for n=1:size(A,1)
[a b]=find(A(n,:)>0,N);
B(n,:)=A(n,transpose(b));
end
Then I think this B matrix will be what you want.

Matrix creation Octave / Matlab, loopless solution request

I want to create a matrix like
A = [0 0 0 0 1;
0 0 0 1 1;
0 0 0 1 1;
0 0 0 1 1;
0 0 1 1 1;
0 1 1 1 1]
based on a vector indicating how many '0's should precede '1's on each row:
B = [4 3 3 3 2 1]
Is there a loopless way to do this ?
You don't mention in your question how the horizontal size of the array should be defined (the number of ones).
For predefined width you can use this code:
width = 5;
A = cell2mat(arrayfun(#(x) [ zeros(1,x), ones(1,width-x) ], B, 'UniformOutput', false)');
If you want that A has minimal width, but still at least one 1 in every row:
A = cell2mat(arrayfun(#(x) [ zeros(1,x), ones(1,max(B)+1-x) ], B, 'UniformOutput', false)');
A shorter “old-school” way to achieve this without a loop would be as follows:
A = repmat(B',1,max(B)+1)<repmat([1:max(B)+1],size(B,2),1)
If you want to have a minimum number of ones
min_ones=1; %or whatever
A = repmat(B',1,max(B)+min_ones)<repmat([1:max(B)+min_ones],size(B,2),1)
I don’t know how this compares speedwise to #nrz’s approach (I’ve only got Octave to hand right now), but to me it's more intuitive as it’s simply comparing a max(B) + min_ones * column tiling of B:
4 4 4 4 4
3 3 3 3 3
3 3 3 3 3
3 3 3 3 3
2 2 2 2 2
1 1 1 1 1
with a row tiling of [1 : max(B) + min_ones]
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
To generate:
A =
0 0 0 0 1
0 0 0 1 1
0 0 0 1 1
0 0 0 1 1
0 0 1 1 1
0 1 1 1 1
This requires only one line, and seems to be faster than previous solutions based on repmat or arrayfun:
%// Example data
ncols = 5;
B = [4 3 3 3 2 1];
%// Generate A
A = bsxfun(#gt, 1:ncols, B(:));