Finding elements who meet a specific condition - matlab

I've a matrix A and I'd like to find elements of first row which have 1 in the second row. i.e. for following matrix
A=
2 5 6 1
1 0 0 1
I'd like to have output as hits = [2 1] without using loops. and then finds the maximum items in the answer. i.e. (2>1) so my final answer is 2. The response is probably using arrayfun but I've problems and get errors using it. What is the correct syntax?
Thanks

Try this:
out = max(A(1,A(2,:) == 1))
Example:
>> A
A =
2 5 6 1
1 0 0 1
>> out
out =
2
Explanation: (if you need)
%// create a mask of which column you want
mask = A(2,:) == 1 %// by checking all values of 2nd row with 1
%// get only the values of row one, meeting 'the' condition
hits = A(1,mask)
%// Find the maximum from that
maxHits = max(hits)
For Cell Array using cellfun
A = {[2 5 6 1; 1 0 0 1], [2 3 2 5 4; 1 1 3 1 2]} %// eg input
A =
[2x4 double] [2x5 double]
out = cellfun(#(x) max(x(1,x(2,:) == 1)),A)
out =
2 5

Related

Remove single elements from a vector

I have a vector M containing single elements and repeats. I want to delete all the single elements. Turning something like [1 1 2 3 4 5 4 4 5] to [1 1 4 5 4 4 5].
I thought I'd try to get the count of each element then use the index to delete what I don't need, something like this:
uniq = unique(M);
list = [uniq histc(M,uniq)];
Though I'm stuck here and not sure how to go forward. Can anyone help?
Here is a solution using unique, histcounts and ismember:
tmp=unique(M) ; %finding unique elements of M
%Now keeping only those elements in tmp which appear only once in M
tmp = tmp(histcounts(M,[tmp tmp(end)])==1); %Thanks to rahnema for his insight on this
[~,ind] = ismember(tmp,M); %finding the indexes of these elements in M
M(ind)=[];
histcounts was introduced in R2014b. For earlier versions, hist can be used by replacing that line with this:
tmp=tmp(hist(M,tmp)==1);
You can get the result with the following code:
A = [a.', ones(length(a),1)];
[C,~,ic] = unique(A(:,1));
result = [C, accumarray(ic,A(:,2))];
a = A(~ismember(A(:,1),result(result(:,2) == 1))).';
The idea is, add ones to the second column of a', then accumarray base on the first column (elements of a). After that, found the elements in first column which have accum sum in the second column. Therefore, these elements repeated once in a. Finally, removing them from the first column of A.
Here is a cheaper alternative:
[s ii] = sort(a);
x = [false s(2:end)==s(1:end-1)]
y = [x(2:end)|x(1:end-1) x(end)]
z(ii) = y;
result = a(z);
Assuming the input is
a =
1 1 8 8 3 1 4 5 4 6 4 5
we sort the list s and get index of the sorted list ii
s=
1 1 1 3 4 4 4 5 5 6 8 8
we can find index of repeated elements and for it we check if an element is equal to the previous element
x =
0 1 1 0 0 1 1 0 1 0 0 1
however in x the first elements of each block is omitted to find it we can apply [or] between each element with the previous element
y =
1 1 1 0 1 1 1 1 1 0 1 1
we now have sorted logical index of repeated elements. It should be reordered to its original order. For it we use index of sorted elements ii :
z =
1 1 1 1 0 1 1 1 1 0 1 1
finally use z to extract only the repeated elements.
result =
1 1 8 8 1 4 5 4 4 5
Here is a result of a test in Octave* for the following input:
a = randi([1 100000],1,10000000);
-------HIST--------
Elapsed time is 5.38654 seconds.
----ACCUMARRAY------
Elapsed time is 2.62602 seconds.
-------SORT--------
Elapsed time is 1.83391 seconds.
-------LOOP--------
Doesn't complete in 15 seconds.
*Since in Octave histcounts hasn't been implemented so instead of histcounts I used hist.
You can test it Online
X = [1 1 2 3 4 5 4 4 5];
Y = X;
A = unique(X);
for i = 1:length(A)
idx = find(X==A(i));
if length(idx) == 1
Y(idx) = NaN;
end
end
Y(isnan(Y)) = [];
Then, Y would be [1 1 4 5 4 4 5]. It detects all single elements, and makes them as NaN, and then remove all NaN elements from the vector.

Position of integers in vector

I think the question is pretty basic, but still keeps me busy since some time.
Lets assume we have a vector containing 4 integers randomly repetetive, like:
v = [ 1 3 3 3 4 2 1 2 3 4 3 2 1 4 3 3 4 2 2]
I am searching for the vector of all positions of each integer, e.g. for 1 it should be a vector like:
position_one = [1 7 13]
Since I want to search every row of a 100x10000 matrix I was not able to deal with linear indeces.
Thanks in advance!
Rows and columns
Since your output for every integer changes, a cell array will fit the whole task. For the whole matrix, you can do something like:
A = randi(4,10,30); % some data
Row = repmat((1:size(A,1)).',1,size(A,2)); % index of the row
Col = repmat((1:size(A,2)),size(A,1),1); % index of the column
pos = #(n) [Row(A==n) Col(A==n)]; % Anonymous function to find the indices of 'n'
than for every n you can write:
>> pos(3)
ans =
1 1
2 1
5 1
6 1
9 1
8 2
3 3
. .
. .
. .
where the first column is the row, and the second is the column for every instance of n in A.
And for all ns you can use an arrayfun:
positions = arrayfun(pos,1:max(A(:)),'UniformOutput',false) % a loop that goes over all n's
or a simple for loop (faster):
positions = cell(1,max(A(:)));
for n = 1:max(A(:))
positions(n) = {pos(n)};
end
The output in both cases would be a cell array:
positions =
[70x2 double] [78x2 double] [76x2 double] [76x2 double]
and for every n you can write positions{n}, to get for example:
>> positions{1}
ans =
10 1
2 3
5 3
3 4
5 4
1 5
4 5
. .
. .
. .
Only rows
If all you want in the column index per a given row and n, you can write this:
A = randi(4,10,30);
row_pos = #(k,n) A(k,:)==n;
positions = false(size(A,1),max(A(:)),size(A,2));
for n = 1:max(A(:))
positions(:,n,:) = row_pos(1:size(A,1),n);
end
now, positions is a logical 3-D array, that every row corresponds to a row in A, every column corresponds to a value of n, and the third dimension is the presence vector for the combination of row and n. this way, we can define R to be the column index:
R = 1:size(A,2);
and then find the relevant positions for a given row and n. For instance, the column indices of n=3 in row 9 is:
>> R(positions(9,3,:))
ans =
2 6 18 19 23 24 26 27
this would be just like calling find(A(9,:)==3), but if you need to perform this many times, the finding all indices and store them in positions (which is logical so it is not so big) would be faster.
Find linear indexes in a matrix: I = find(A == 1).
Find two dimensional indexes in matrix A: [row, col] = find(A == 1).
%Create sample matrix, with elements equal one:
A = zeros(5, 4);
A([2 10 14]) = 1
A =
0 0 0 0
1 0 0 0
0 0 0 0
0 0 1 0
0 1 0 0
Find ones as linear indexes in A:
find(A == 1)
ans =
2
10
14
%This is the same as reshaping A to a vector and find ones in the vector:
B = A(:);
find(B == 1);
B' =
0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0
Find two dimensional indexes:
[row, col] = find(A == 1)
row =
2
5
4
col =
1
2
3
You can do that with accumarray using an anonymous function as follows:
positions = accumarray(v(:), 1:numel(v), [], #(x) {sort(x.')});
For
v = [ 1 3 3 3 4 2 1 2 3 4 3 2 1 4 3 3 4 2 2];
this gives
positions{1} =
1 7 13
positions{2} =
6 8 12 18 19
positions{3} =
2 3 4 9 11 15 16
positions{4} =
5 10 14 17

Create Non Zero elements of Matrix in vector form in Matlab

I have a Matrix of size M by N in which each row has some zero entries. I want to create M row vectors such that each of the vector contains the non zero elements of each row. For example if I have the following Matrix
A=[0 0 0 5;0 0 4 6;0 1 2 3;9 10 2 3]
I want four different row vectors of the following form
[5]
[4 6]
[1 2 3]
[9 10 2 3]
This can be done with accumarray using an anonymous function as fourth input argument. To make sure that the results are in the same order as in A, the grouping values used as first input should be sorted. This requires using (a linearized version of) A transposed as second input.
ind = repmat((1:size(A,2)).',1,size(A,2)).';
B = A.';
result = accumarray(ind(:), B(:), [], #(x){nonzeros(x).'});
With A = [0 0 0 5; 0 0 4 6; 0 1 2 3; 9 10 2 3]; this gives
result{1} =
5
result{2} =
4 6
result{3} =
1 2 3
result{4} =
9 10 2 3
Since Matlab doesn't support non-rectangular double arrays, you'll want to settle on a cell array. One quick way to get the desired output is to combine arrayfun with logical indexing:
nonZeroVectors = arrayfun(#(k) A(k,A(k,:)~=0),1:size(A,1),'UniformOutput',false);
I used the ('UniformOutput',false) name-value pair for the reasons indicated in the documentation (I'll note that the pair ('uni',0) also works, but I prefer verbosity). This input produces a cell array with the entries
>> nonZerosVectors{:}
ans =
5
ans =
4 6
ans =
1 2 3
ans =
9 10 2 3

Delete rows with 0 for specific columns in Matlab

So I want to delete rows of a matrix that contain zero, but only for specific columns. For example:
A = [[0 0 0 0; 1 2 0 4; 2 0 1 1; 0 0 0 0; 1 2 3 4; 0 1 2 3];
I want for matrix A to check if the second and/or 4th columns contain zero's. If this is true: then delete the whole row. So the result should be:
A = [1 2 0 4; 1 2 3 4; 0 1 2 3];
I used this function:
new_a = A(all(A,2),:)
But I deleted all the rows containing zeros.
You can write
>>> secondColIsNonzero = A(:, 2) ~= 0;
>>> fourthColIsNonzero = A(:, 4) ~= 0;
>>> keep = secondColIsNonzero & fourthColIsNonzero;
>>> newA = A(keep, :)
newA =
1 2 0 4
1 2 3 4
0 1 2 3
to keep (i.e., not delete) columns where neither the 2nd or 4th column is zero.
For a less verbose solution, consider indexing both columns at the same time and using all with a dimension argument:
keep = all(A(:, [2 4]) ~= 0, 2)
This is easily solved using the find() function:
B = A(find(A(:,2)~=0),:)
find() by default returns rows, so calling it in this case returns the index of the rows where the value on the second column is not 0.

Row-by-row comparison in MATLAB

I want to compare every row of a matrix with its every other row, element by element wise, using MATLAB. If two of the entries match, the result will be stored as 1, and if they don't match, it will be 0. This will give a symmetric matrix consisting of 0s and 1s.
For example, let A = [4 6 7 9 5; 2 6 9 9 1]
Then, the result expected is [1 1 1 1 1; 0 1 0 1 0; 0 1 0 1 0; 1 1 1 1 1]
The code I am using is (for a 1000*1000 random matrix):
A = randi(50,1000,1000);
B = zeros(1000000,1000);
D = zeros(1000000,1);
c=0;
for i=1:1000
for k=1:1000
for j=1:1000
if A(i,j)==A(k,j)
B(k+c,j)=1;
else
B(k+c,j)=0;
end
end
end
c=c+1000;
end
for l=1:1000000
D(l)=0;
for m=1:1000
D(l)=D(l)+(B(l,m)/(1000));
end
end
E=reshape(D,1000,1000);
This goes out of memory. Could anyone please suggest a solution or a more efficient code?
you can try row by row comparison directly as taking a complete row array and comparing with the other row array.
For example,
let
A = [4 6 7 9 5; 2 6 9 9 1];
nA = length(A(:,1));
finalMat = [];
for i = 1:nA
matRow = ones(nA,1)*A(i,:); % create a matrix size of A consists of same row elements
finalMat = [finalMat;matRow == A];
end
see if it is okay for you application.
You can use permute to align dimensions apprpriately and then bsxfun for the comparisons:
reshape(bsxfun(#eq, permute(A, [1 3 2]), permute(A, [3 1 2])), [], size(A,2))