How to find one value from a matrix - matlab

0I have on matrix-
A=[1 2 2 3 5 5;
1 5 5 8 8 7;
2 9 9 3 3 5];
From matrix i need to count now many nonzero elements ,how any 1,how many 2 and how many 3 in each row of given matrix"A".For these i have written one code like:
[Ar Ac]=size(A);
for j=1:Ar
for k=1:Ac
count(:,j)=nnz(A(j,:));
d(:,j)=sum(A(j,:)== 1);
e(:,j)=sum(A(j,:)==2);
f(:,j)=sum(A(j,:)==3);
end
end
but i need to write these using on loop i.e. here i manually use sum(A(j,:)== 1),sum(A(j,:)== 2) and sum(A(j,:)== 3) but is there any option where i can only write sum(A(j,:)== 1:3) and store all the values in the different row i.e, the result will be like-
b=[1 2 1;
1 0 0;
0 1 2];
Matlab experts need your valuable suggestions

Sounds like you're looking for a histogram count:
U = unique(A);
counts = histc(A', U)';
b = counts(:, ismember(U, [1 2 3]));
Example
%// Input matrix and vector of values to count
A = [1 2 2 3 5 5; 1 5 5 8 8 7; 2 9 9 3 3 5];
vals = [1 2 3];
%// Count values
U = unique(A);
counts = histc(A', U)';
b = counts(:, ismember(U, vals));
The result is:
b =
1 2 1
1 0 0
0 1 2

Generalizing the sought values, as required by asker:
values = [ 1 2 3 ]; % or whichever values are sought
B = squeeze(sum(bsxfun(#(x,y) sum(x==y,2), A, shiftdim(values,-1)),2));

Here is a simple and general way. Just change n to however high you want to count. n=max(A(:)) is probably a good general value.
result = [];
n = 3;
for col= 1:n
result = [result, sum(A==col, 2)];
end
result
e.g. for n = 10
result =
1 2 1 0 2 0 0 0 0 0
1 0 0 0 2 0 1 2 0 0
0 1 2 0 1 0 0 0 2 0

Why not use this?
B=[];
for x=1:size(A,1)
B=[B;sum(A(x,:)==1),sum(A(x,:)==2),sum(A(x,:)==3)];
end

I'd do this way:
B = [arrayfun(#(i) find(A(i,:) == 1) , 1:3 , 'UniformOutput', false)',arrayfun(#(i) find(A(i,:) == 2) , 1:3 , 'UniformOutput', false)',arrayfun(#(i) find(A(i,:) == 3) , 1:3 , 'UniformOutput', false)'];
res = cellfun(#numel, B);

Here is a compact one:
sum(bsxfun(#eq, permute(A, [1 3 2]), 1:3),3)
You can replace 1:3 with any array.
you can make an anonymous function for it
rowcnt = #(M, R) sum(bsxfun(#eq, permute(M, [1 3 2]), R),3);
then running it on your data returns
>> rowcnt(A,1:3)
ans =
1 2 1
1 0 0
0 1 2
and for more generalized case
>> rowcnt(A,[1 2 5 8])
ans =
1 2 2 0
1 0 2 2
0 1 1 0

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.

Replace specific matrix position with array value without using for loop in MATLAB

can I know how can I replace values in specific matrix position without using for loop in MATLAB? I initialize matrix a that I would like to replace its value on specified row and column for each no. This has to be done a few time within num for loop. The num for loop is important here because I would want the update the value in the original code.
The real code is more complicated, I am simplifying the code for this question.
I have the code as follow:
a = zeros(2,10,15);
for num = 1:10
b = [2 2 1 1 2 2 2 1 2 2 2 2 1 2 2];
c = [8.0268 5.5218 2.9893 5.7105 7.5969 7.5825 7.0740 4.6471 ...
6.3481 14.7424 13.5594 10.6562 7.3160 -4.4648 30.6280];
d = [1 1 1 2 1 1 1 1 1 1 3 1 6 1 1];
for no = 1:15
a(b(no),d(no),no) = c(1,no,:)
end
end
A sample output for, say no 13 is as follows:
a(:,:,13) =
Columns 1 through 8
0 0 0 0 0 7.3160 0 0
0 0 0 0 0 0 0 0
Columns 9 through 10
0 0
0 0
Thank you so much for any help I could get.
It can be done using sub2ind, which casts the subs to a linear index.
Following your vague variable names, it would look like this (omitting the useless loop over num):
a = zeros(2,10,15);
b = [2 2 1 1 2 2 2 1 2 2 2 2 1 2 2];
d = [1 1 1 2 1 1 1 1 1 1 3 1 6 1 1];
c = [8.0268 5.5218 2.9893 5.7105 7.5969 7.5825 7.0740 4.6471 ...
6.3481 14.7424 13.5594 10.6562 7.3160 -4.4648 30.6280];
% // we vectorize the loop over no:
no = 1:15;
a(sub2ind(size(a), b, d, no)) = c;
Apart from the sub2ind based approach as suggested in Nras's solution, you can use a "raw version" of sub2ind to reduce a function call if performance is very critical. The related benchmarks comparing sub2ind and it's raw version is listed in another solution. Here's the implementation to solve your case -
no = 1:15
a = zeros(2,10,15);
[m,n,r] = size(a)
a((no-1)*m*n + (d-1)*m + b) = c
Also for pre-allocation, you can use a much faster approach as listed in Undocumented MATLAB blog post on Preallocation performance with -
a(2,10,15) = 0;
The function sub2ind is your friend here:
a = zeros(2,10,15);
x = [2 2 1 1 2 2 2 1 2 2 2 2 1 2 2];
y = [1 1 1 2 1 1 1 1 1 1 3 1 6 1 1];
z = 1:15;
dat = [8.0268 5.5218 2.9893 5.7105 7.5969 7.5825 7.0740 4.6471 ...
6.3481 14.7424 13.5594 10.6562 7.3160 -4.4648 30.6280];
inds = sub2ind(size(a), x, y, z);
a(inds) = dat;
Matlab provides a function 'sub2ind' may do what you expected.
with variable as the same you posted:
idx = sub2ind(size(a),b,d,[1:15]); % return the index of row a column b and page [1:15]
a(idx) = c;

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.

If same value in two matrices, keep the value in the first matrix

how can I achieve the matrix C with following conditions:
A(i,j) is any B(k) , then A(i,j) = B(k)
else A(i,j) = 0
example:
A = [1 0 3 6 3 4; 2 0 3 1 8 2];
B = [1;2;3];
C = [1 0 3 0 3 0; 2 0 3 1 0 2]
Thank you!
A.*ismember(A,B)
Well not much to explain, ismember fits exactly your condition. Thus ismember(A,B) is 1 for all values you want to copy.
If your concern is to avoid products, you may try:
A(~ismember(A,B))=0;
depending on what you're looking for, from the matlab documentation
[LIA,LOCB] = ismember(A,B) also returns an array LOCB containing the
highest absolute index in B for each element in A which is a member of
B and 0 if there is no such index.
a = [9 9 8 8 7 7 7 6 6 6 5 5 4 4 2 1 1 1]
b = [1 1 1 3 3 3 3 3 4 4 4 4 4 9 9 9]
[lia1,locb1] = ismember(a,b)
% returns
lia1 = [1 1 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1]
locb1 = [16 16 0 0 0 0 0 0 0 0 0 0 13 13 0 3 3 3]
Another possibility, without ismember:
A .* any(bsxfun(#eq, A, permute(B,[3 2 1])),3)
Thank you guys!
I followed your advise and extended the code for my task. I guess my question was unclear formulated:
Following your advice, the Matrix C will give only 1 or 0.
I need the actual value of A in it.
In my following solution the code just rewrites A in the end. I gues there are many smarter solutions, but it works.
A = [1 0 3 6 3 4; 2 0 3 1 8 2];
B = [1;2;3];
[N M] = size (A);
C = ismember(A,B);
for i = 1:N
for j = 1:M
if C(i,j) == 0;
A(i,j) = 0;
end
end
end

finding matching rows in matrix

Suppose I have an (m x n) matrix Q, and a row vector r, e.g.
Q = [ 1 2 3 ; 4 2 3 ; 5 6 7 ; 1 2 3 ; 1 2 3 ; 1 2 5 ];
r = [ 1 2 3 ];
What is the easiest way to obtain a logical vector (of length m) that indicates which of the rows in Q are identical (for all elements) to the specified row r?
In the sample case above, that should be
[ 1 0 0 1 1 0 ];
You can use ismember and do it in a single line:
>> ismember(Q,r,'rows')'
ans =
1 0 0 1 1 0
all(bsxfun(#eq, r, Q),2)'
bsxfun(#eq, r, Q) compares each row and returns a matrix with same size as Q:
>> bsxfun(#eq, r, Q)
ans =
1 1 1
0 1 1
0 0 0
1 1 1
1 1 1
1 1 0
the all function computes if the result of bsxfun is all true along each row separately. Thus it returns:
>> all(ans,2)'
ans =
1 0 0 1 1 0
and yeah, there is also a transpose operator ' to match your desired row output
a = [1 1 1; 2 2 2; 3 3 3];
b = a(1:2,;);
[temp locb] = ismember(a,b,'rows');
b(locb(locb~=0),:)
ans =
1 1 1
2 2 2
Easier way with repmat:
a = [1 2 3; 4 5 6; 7 8 9];
t = [4 5 6];
[x,y] = size(a);
r = all(a==repmat(t,y,1), 2)'