I have an m by n matrix in MATLAB, say M. I have an n-element row vector, i.e. a one by n column matrix, say X.
I know X is a row somewhere in M. How can I find the index in M?
EDIT:
gnovice's suggestion is even simpler than mine:
[~,indx]=ismember(X,M,'rows')
indx =
3
FIRST SOLUTION:
You can easily do it using find and ismember. Here's an example:
M=magic(4); %#your matrix
M =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
X=[9 7 6 12]; %#your row vector
find(ismember(M,X),1)
ans =
3
Before I learned of ismember, I used to do:
index = find(all(bsxfun(#eq, M, X), 2));
But using ismember(X, M, 'rows') is definitely preferable.
Another solution that returns a row index for each occurrence of X is
find(sum(abs(M-ones(rows(M),1)*X),2)==0)
Also, this solution can be easily adapted to find rows that are within threshold of X as follows (if numerical noise is an issue)
tolerance = 1e-16; %setting the desired tolerance
find(sum(abs(M-ones(rows(M),1)*X),2)<tolerance)
This is a non-loop version. It is only suitable, if M (your matrix) is not very large, ie. n and m are small. X is your row:
function ind = findRow(M,X)
tmp = M - repmat(X,size(M,1),1);
ind = find(tmp,1);
end
If M is too large, it might be faster, to iterate the rows of M and compare every row with your vector.
#Edit: renamed variables to match the names used in the question.
Related
I have a situation analogous to the following
z = magic(3) % Data matrix
y = [1 2 2]' % Column indices
So,
z =
8 1 6
3 5 7
4 9 2
y represents the column index I want for each row. It's saying I should take row 1 column 1, row 2 column 2, and row 3 column 2. The correct output is therefore 8 5 9.
I worked out I can get the correct output with the following
x = 1:3;
for i = 1:3
result(i) = z(x(i),y(i));
end
However, is it possible to do this without looping?
Two other possible ways I can suggest is to use sub2ind to find the linear indices that you can use to sample the matrix directly:
z = magic(3);
y = [1 2 2];
ind = sub2ind(size(z), 1:size(z,1), y);
result = z(ind);
We get:
>> result
result =
8 5 9
Another way is to use sparse to create a sparse matrix which you can turn into a logical matrix and then sample from the matrix with this logical matrix.
s = sparse(1:size(z,1), y, 1, size(z,1), size(z,2)) == 1; % Turn into logical
result = z(s);
We also get:
>> result
result =
8
5
9
Be advised that this only works provided that each row index linearly increases from 1 up to the end of the rows. This conveniently allows you to read the elements in the right order taking advantage of the column-major readout that MATLAB is based on. Also note that the output is also a column vector as opposed to a row vector.
The link posted by Adriaan is a great read for the next steps in accessing elements in a vectorized way: Linear indexing, logical indexing, and all that.
there are many ways to do this, one interesting way is to directly work out the indexes you want:
v = 0:size(y,2)-1; %generates a number from 0 to the size of your y vector -1
ind = y+v*size(z,2); %generates the indices you are looking for in each row
zinv = z';
zinv(ind)
>> ans =
8 5 9
We've got a columnvector m x 1 and a matrix m x n.
For the value in row i in the columnvector we want to multiply this value with each value in the same row i of the matrix, and then sum all of these up. This is to be repeated for every row i in the vector so that we end up with a columnvector.
Want to do this with a for-loop, have this so far (where M is the matrix and v is the initial columnvector we start out with) which returns an error that says "Subscripted assignment dimension mismatch.", so I guess I messed up with my indices somehow:
for i = 1:nv
for k = 1:mM
columnvectorendresult(i,) = columnvectorendresult(i,) + v(i,:)*M(i,:);
end
end
Don't know if I'm close with what I have so far, but not fully into this just yet. Any suggestions?
In case you want to sum after multiplication, the answer of knedlsepp using the distributive property of multiplication is the logical choice. If you want to use other operations than sums or differences, than the following answer can be applied more generically
Here we go:
%// columnvector m x 1
a = randi(5,3,1)
%// matrix m x n
B = randi(5,3,2)
%// multiplication
Ba = bsxfun(#times,B,a(:))
%// sum
BaSum = sum(Ba,2)
Example:
a =
3
4
4
B =
2 5
3 1
1 1
Ba =
6 15
12 4
4 4
BaSum =
21
16
8
Instead of multiplying each entry with the same factor and then doing the summation, you should sum the rows of the matrix first and then do the multiplication. ("Use the distributive property of multiplication.")
This is how you do this in MATLAB:
columnvectorendresult = v.*sum(M,2);
What I intend to do is very simple but yet I haven't found a proper way to do it. I have a function handle which depends on two variables, for example:
f = #(i,j) i+j
(mine is quite more complicated, though)
What I'd like to do is to create a matrix M such that
M(i,j) = f(i,j)
Of course I could use a nested loop but I'm trying to avoid those. I've already managed to do this in Maple in a quite simple way:
f:=(i,j)->i+j;
M:=Matrix(N,f);
(Where N is the dimension of the matrix) But I need to use MATLAB for this. For now I'm sticking to the nested loops but I'd really appreciate your help!
Use bsxfun:
>> [ii jj] = ndgrid(1:4 ,1:5); %// change i and j limits as needed
>> M = bsxfun(f, ii, jj)
M =
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
If your function f satisfies the following condition:
C = fun(A,B) accepts arrays A and B of arbitrary, but equal size and returns output of the same size. Each element in the output array C is the result of an operation on the corresponding elements of A and B only. fun must also support scalar expansion, such that if A or B is a scalar, C is the result of applying the scalar to every element in the other input array.
you can dispose of ndgrid. Just add a transpose (.') to the first (i) vector:
>> M = bsxfun(f, (1:4).', 1:5)
Function handles can accept matrices as inputs. Simply pass a square matrix of size N where the values corresponds to the row number for i, and a square matrix of size N where the values correspond to the column number for j.
N = 5;
f = #(i,j) i+j;
M = f(meshgrid(1:N+1), meshgrid(1:N+1)')
I have two vectors with the same elements but their order is not same. For eg
A
10
9
8
B
8
9
10
I want to find the mapping between the two
B2A
3
2
1
How can I do this in matlab efficiently?
I think the Matlab sort is efficient. So:
[~,I]=sort(A); %sort A; we want the indices, not the values
[~,J]=sort(B); %same with B
%I(1) and J(1) both point to the smallest value, and a similar statement is true
%for other pairs, even with repeated values.
%Now, find the index vector that sorts I
[~,K]=sort(I);
%if K(1) is k, then A(k) is the kth smallest entry in A, and the kth smallest
%entry in B is J(k)
%so B2A(1)=J(k)=J(K(1)), where BSA is the desired permutation vector
% A similar statement holds for the other entries
%so finally
B2A=J(K);
if the above were in script "findB2A" the following should be a check for it
N=1e4;
M=100;
A=floor(M*rand(1,N));
[~,I]=sort(rand(1,N));
B=A(I);
findB2A;
all(A==B(B2A))
There are a couple of ways of doing this. The most efficient in terms of lines of code is probably using ismember(). The return values are [Lia,Locb] = ismember(A,B), where Locb are the indices in B which correspond to the elements of A. You can do [~, B2A] = ismember(A, B) to get the result you want. If your version of MATLAB does not allow ~, supply a throwaway argument for the first output.
You must ensure that there is a 1-to-1 mapping to get meaningful results, otherwise the index will always point to the first matching element.
Here a solution :
arrayfun(#(x)find(x == B), A)
I tried with bigger arrays :
A = [ 7 5 2 9 1];
B = [ 1 9 7 5 2];
It gives the following result :
ans =
3 4 5 2 1
Edit
Because arrayfun is usually slower than the equivalent loop, here a solution with a loop:
T = length(A);
B2A = zeros(1, length(A));
for tt = 1:T
B2A(1, tt) = find(A(tt) == B);
end
I would go for Joe Serrano's answer using three chained sort's.
Another approach is to test all combinations for equality with bsxfun:
[~, B2A] = max(bsxfun(#eq, B(:), A(:).'));
This gives B2A such that B(B2A) equals A. If you want it the other way around (not clear from your example), simply reverse A and B within bsxfun.
In matlab, after meeting a specific criterion, I used to return back the pixel itself and store it in the vector pixels as follows:
pixels(index) = y(i,j);
Now, I would like to return the location of those pixels. Should I do the following?
pixels(index) = i,j;
EDIT
If I want to then set those indexes to the value 1, I do the following, right?
for i=1:m
for j=1:n
y(i,j)=1
end
end
Thanks.
It is extremely inefficient to do so in a nested loop in Matlab.
Using sub2ind can help you do so much faster:
y( sub2ind( size(y), i, j ) ) = 1;
EDIT - sub2ind
What sub2ind does?
Suppose you have a matrix M of size [4 6]:
M = [ 1 5 9 13 17 21
2 6 10 14 18 22
3 7 11 15 19 23
4 8 12 16 20 24 ];
You wish to access two elements: the one at the first row and second column, and another at the fourth row and the fifth column.
In that case you have the rows you wish to access r = [ 1 4 ] and the columns you wish to access c = [ 2 5 ]. However, if you try and access
>> M( r, c )
This is a 2x2 matrix
ans =
5 17
8 20
And not the two elements you were looking for (which are 5 and 20).
What sub2ind does is convert the row/column indices you have into linear indices
>> sub2ind( size(M), r, c )
ans =
5 20
which happens to be the linear indices of the requested entries.
You can think of linear indices as the single index required to access an element in a matrix in the case that the matrix was converted to a vector stacking its columns one after the other.
A few comments:
Matlab has a few ways of indexing matrices: by row / column indices (like i and j in your question). By linear indices (like index in your question). However, the more efficient way is to use logical indexing: that is, using a matrix of the same size as y with true for the entries you wish to set / get.
So, in your example, if you could get such a logical matrix instead of index or i and j it would have been better.
Matlab has many advantages over other programing languages. One of them is its ability to perform vector/matrix operations extremely efficient. Resorting to loops, or worse, nested loops, is something that should be avoided in Matlab.
It is not a good practice to use i and j as variables in Matlab.
If you want to find the occurrence of a value y(i,j) simply evaluate
idx = (pixels == y(i,j));
Depending on your variables you can then probably do
index(idx) = 1;