Matlab , matrix operations - matlab

I have for example this matrix
A=[
11 15 19 13
12 16 0 114
13 17 111 115
14 18 112 116
];
I want to find nonzero elements of two matrix of indices:
i1=[1 3];
i2=[2 4];
The result:
B=A(i2,i1);
B=[12 0
14 112];
index of matrix in A.
index=[2 4 12];
So, How to obtain the indices without loop?
Thanks.

There is a one-liner which is not quite readable of course:
index = find(diag(ismember(1:size(A,1), i2))*A*diag(ismember(1:size(A,2), i1)));
or alternatively
index=find(sparse(i2,i2,1,size(A,1),size(A,1))*A*sparse(i1,i1,1,size(A,2),size(A,2)));
and there is more elaborate and readable one:
z=zeros(size(A));
z(i2,i1) = A(i2,i1);
index=find(z);
Note that the first one-liner fails if the matrix contains Inf or NaN values because those values will be multiplied by zero, the second and third methods are more robust in that sense.

This is one solution:
% sub2ind does not work, use this hack instead
z = zeros(size(A));
z(i2,i1) = 1
ind = find(z) % get linear indices
%only keep the ones for which A is nonzero
ind = ind(A(ind) ~= 0)
Result:
z =
0 0 0 0
1 0 1 0
0 0 0 0
1 0 1 0
ind =
2
4
10
12
ind =
2
4
12

Slightly more compact than Bas Swinckels answer:
I=reshape(1:numel(A),size(A));
J=I(i2,i1);
J(~~B)

Related

How to find minimum of each column in MATLAB and sum op all elements of that column?

I have a 300x178 matrix and I want to find the minimum of each column of that matrix, i.e. resulting in a 1x178 array. Then I want to store the sum of all elements but the minimum in each column in the 300x178 matrix on the location/pixel of the minimum value, leaving all other elements zero. How can I do this using MATLAB?
Example:
1 4 6 3
2 6 7 4
5 1 5 7
becomes:
1 0 0 1
0 0 0 0
0 1 1 0
and eventually:
8 0 0 14
0 0 0 0
0 11 18 0
Your example and title do not correspond to the question text. Your example sums all values in a column and stores them at the location of the minimum, which the title also asks. You can do this by making smart use of sub2ind:
A = [1 4 6 3
2 6 7 4
5 1 5 7];
C = zeros(size(A));
[tmp, idx] = min(A); % find the locations of minima
% one liner to store the sum of columns
C(sub2ind(size(A), idx, 1:size(A,2))) = sum(A,1);
C =
8 0 0 14
0 0 0 0
0 11 18 0
If, on the other hand, you're after what your question text asks about, subsequently subtract A on the minimum locations using the same sub2ind trick:
C(sub2ind(size(A), idx, 1:size(A,2))) = C(sub2ind(size(A), idx, 1:size(A,2))) - A(sub2ind(size(A), idx, 1:size(A,2)))
C =
7 0 0 11
0 0 0 0
0 10 13 0
This way you get the sum of all elements but the minimum.
For an in-depth explanation what sub2ind does, read this fantastic Q/A by Luis Mendo keeping in mind that in A(2,3) the 2 and 3 are called subscripts, which, in case of a 3-by-4 matrix, translates to linear index 8.
I cannot test this on my R2007b, but according to the documentation on min you could use [M, I] = min(A, [], 1, 'linear') to get the linear indices into I directly, without going through sub2ind:
C = zeros(size(A));
[tmp, idx] = min(A, [], 1, 'linear');
C(idx) = sum(A, 1);
% Optional, to sum all but the minimum
C(idx) = C(idx) - A(idx);
Small note from the documentation on the occurrence of multiple same-valued minima in your original matrix:
If the smallest element occurs more than once, then I contains the index to the first occurrence of the value.

Find last true element of columns

I'd like to extract one value per column of a matrix using a condition. Multiple values on each column match that condition, but only the last one should be selected. It is safe to assume that each row contains at least one such value.
So given an NxM matrix and an equally-sized boolean, extract M values for which the boolean is true and it is the last true value in a column. For example:
m = magic(4);
i = (m > 10);
% m =
% 16 2 3 13
% 5 11 10 8
% 9 7 6 12
% 4 14 15 1
% i =
% 1 0 0 1
% 0 1 0 0
% 0 0 0 1
% 0 1 1 0
And the expected output:
% i_ =
% 1 0 0 0
% 0 0 0 0
% 0 0 0 1
% 0 1 1 0
% x = [16, 14, 15, 12]
I know this could be easily achieved by looping through the columns and using find, but in my experience there often are better ways of formulating these problems.
This would do it
m(max(i.*reshape([1:numel(m)],size(m))))
Explanation
So we are generating an array of indices
reshape([1:numel(m)],size(m))
ans =
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
That represents the indices for each value. The we multiply that with I to get the values we are interested in
i.*reshape([1:numel(m)],size(m))
ans =
1 0 0 13
0 6 0 0
0 0 0 15
0 8 12 0
Then we do a max on that since max works on columns. This will give us the last index in each column.
max(i.*reshape([1:numel(m)],size(m)))
ans =
1 8 12 15
Then apply those indices on m to get the values
m(max(i.*reshape([1:numel(m)],size(m))))
ans =
16 14 15 12
You can use the second output of max to find the last true element of each column. Before that the logical matrx should be multiplied by an increasing column vector.
[~, idx] = max((1:size(i, 1)).' .* i, [], 1, 'linear') ;
x = m(idx) ;
Here's another way, using accumarray:
[~, col] = find(i); % column indices
lin = find(i); % linear indices
x = accumarray(col, m(lin), [], #(x) x(end));

How to find the indices of nonzero rows in a matrix?

How to find the indices of nonzero rows in a matrix?
Example:
A = [
14 0 6 9 8 17
85 14 1 3 0 99
0 0 0 0 0 0
29 4 5 8 7 46
0 0 0 0 0 0
17 0 5 0 0 49
]
the desired result :
V =[1 2 4 6]
You can use
ix = any(x,2);
any check whether there is any element that is not a zero. The second argument stands for "per-row" computation.
If you want to get the numeric index, you can use find function:
numIx = find(ix);
Another method:
ix = sum(abs(x),2)~=0;
Use
[i,~] = ind2sub(size(A),find(A));
v = unique(i);
Result for the matrix given above:
v = unique(i')
v =
1 2 4 6
Here's one that ab(uses) the fast matrix multiplication in MATLAB -
idx = find(abs(A)*ones(size(A,2),1))

Matlab: How I can make this transformation on the matrix A?

I have a matrix A 4x10000, I want to use it to find another matrix C.
I'll simplify my problem with a simple example:
from a matrix A
20 4 4 74 20 20
36 1 1 11 36 36
77 1 1 15 77 77
3 4 2 6 7 8
I want, first, to find an intermediate entity B:
2 3 4 6 7 8
[20 36 77] 0 1 0 0 1 1 3
[4 1 1] 1 0 1 0 0 0 2
[74 11 15] 0 0 0 1 0 0 1
we put 1 if the corresponding value of the first line and the vector on the left, made ​​a column in the matrix A.
the last column of the entity B is the sum of 1 of each line.
at the end I want a matrix C, consisting of vectors which are left in the entity B, but only if the sum of 1 is greater than or equal to 2.
for my example:
20 4
C = 36 1
77 1
N.B: for my problem, I use a matrix A 4x10000
See if this works for you -
%// We need to replace this as its not available in your old version of MATLAB:
%// [unqcols,~,col_match] = unique(A(1:end-1,:).','rows','stable') %//'
A1 = A(1:end-1,:).'; %//'
[unqmat_notinorder,row_ind,labels] = unique(A1,'rows');
[tmp_sortedval,ordered_ind] = sort(row_ind);
unqcols = unqmat_notinorder(ordered_ind,:);
[tmp_matches,col_match] = ismember(labels,ordered_ind);
%// OR use - "[tmp2,col_match] = ismember(A1,out,'rows');"
C = unqcols(sum(bsxfun(#eq,col_match,1:max(col_match)),1)>=2,:).'; %//'
%// OR use - "C = out(accumarray(col_match,ones(1,numel(col_match)))>=2,:).'"
This should work:
[a,~,c] = unique(A(1:end-1,:).', 'rows', 'stable');
C=a(histc(c,unique(c))>=2, :).';
Edit: For older versions of MATLAB:
D=A(1:end-1,:);
C=unique(D(:,squeeze(sum(all(bsxfun(#eq, D, permute(D, [1 3 2])))))>=2).', 'rows').':

MATLAB: extract submatrix with logical indexing

I'm looking for an elegant solution to this very simple problem in MATLAB. Suppose I have a matrix
>> M = magic(5)
M =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
and a logical variable of the form
I =
0 0 0 0 0
0 1 1 0 0
0 1 1 0 0
0 0 0 0 0
0 0 0 0 0
If I try to retrieve the elements of M associated to 1 values in I, I get a column vector
>> M(I)
ans =
5
6
7
13
What would be the simplest way to obtain the matrix [5 7 ; 6 13] from this logical indexing?
If I know the shape of the non-zero elements of I, I can use a reshape after the indexing, but that's not a general case.
Also, I'm aware that the default behavior for this type of indexing in MATLAB enforces consistency with respect to the case in which non-zero values in I do not form a matrix, but I wonder if there is a simple solution for this particular case.
This is a one way to do this. It is assumed that all rows of I have same number of ones. It is also assumed that all columns of I have same number have ones, because Submatrix must be rectangular.
%# Define the example data.
M = magic(5);
I = zeros(5);
I(2:3, 2:3) = 1;
%# Create the Submatrix.
Submatrix = reshape(M(find(I)), max(sum(I)), max(sum(I')));
Here is a very simple solution:
T = I(any(I'),any(I));
T(:) = M(I);
M = magic(5);
I = [ ... ];
ind = find(I); %# find indices of ones in I
[y1, x1] = ind2sub(size(M), ind(1)); %# get top-left position
[y2, x2] = ind2sub(size(M), ind(end)); %# get bottom-right position
O = M(y1:y2, x1:x2); %# copy submatrix