I am trying to index (not get) the diagonals of a matrix in matlab.
Say I have a matrix "M", that is n by n. Then I want to obtain all indeces of all possible diagonals in the matrix "M".
I know that the center diagonal is indexed by
M(1:(n+1):end)
and all the following diagonals above it are indexed as:
M((1+1*n):(n+1):end)
M((1+2*n):(n+1):end)...
M((1+n*n):(n+1):end)
Now I also want to get the diagonals below. I cannot for the life of me figure out how to however.
Reproducible example:
rng(1); % set seed
n = 4;
M = rand(n);
yielding
M =
0.562408 0.947364 0.655088 0.181702
0.960604 0.268834 0.469042 0.089167
0.578719 0.657845 0.516215 0.419000
0.226410 0.601666 0.169212 0.378740
where I would like to index the lower diagonals, e.g. the subdiagonal:
0.960604 0.657845 0.169212
That is, I don't need to get the diagonal by e.g. the diags function, but access the index (since I ultimately want to replace the matrix entries diagonal by diagonal).
As you already noted, you can use the diag function to get the main diagonal and other diagonals above or below the main diagonals,
M = magic(4) % Test data
M =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
diag(M, -1)
ans =
5
7
15
but you can not assign values to the diagonal with the diag function:
diag(M, -1) = [3; 2; 1]
Index in position 2 is invalid. Array indices must be positive integers or logical values.
Instead, we can use logical indexing by indexing the array M with a logical matrix of the same size. We can easily create this matrix using the diag function, by creating a diagonal matrix with ones on the specified diagonal:
diag(ones(1, 3), -1)
ans =
0 0 0 0
1 0 0 0
0 1 0 0
0 0 1 0
To use this matrix for logical indexing, we need to convert it from double to logical with the logical function.
M(logical(diag(ones(1, 3), -1)))
ans =
5
7
15
or assign new values to it with
M(logical(diag(ones(1, 3), -1))) = [99, 98, 97]
M =
16 2 3 13
99 11 10 8
9 98 6 12
4 14 97 1
There is a slightly more performant way of using diag to get indices to a diagonal:
n = 5; % matrix size
M = reshape(1:n*n,n,n); % matrix with linear indices
indices = diag(M, ii); % indices to diagonal ii
However, it is much easier to just compute the right indices directly. As discovered by OP, the upper diagonal elements are given by:
indices = (1+ii*n):(n+1):(n*n);
(Note that the parenthesis are not necessary, as the colon operator has the lowest precedence.)
The lower diagonal elements are given by:
indices = (1+ii):(n+1):((n-ii)*n);
Both series are identical for the main diagonal, where ii=0.
We can verify correctness of these calculations by using the first method:
n = 5; % matrix size
M = reshape(1:n*n,n,n); % matrix with linear indices
for ii=1:n-1
indices = (1+ii*n):(n+1):(n*n);
assert(isequal(indices, diag(M, ii).'))
indices = (1+ii):(n+1):((n-ii)*n);
assert(isequal(indices, diag(M, -ii).'))
end
Related
I have a matrix M[1,98] and a matrix N[1,x], let's assume in this case x =16.
What I want is to multiply N by M , make the sum by element, and increment the matrix M. With the finality of getting an output of [1,98].
It's a bit confusing. An example:
M=[2 3 4 5 6 7]
N=[1 2 3]
it1=(2*1)+(3*2)+(4*3)+(5*0)+...=20
it2=(3*1)+(4*2)+(5*3)+(6*0)+...=26
it3=..
Output=[20 26 ... ... ... ...]
Like that until the end but considering the size of the matrix N variable. M has always the same size.
That's a convolution:
result = conv(M, N(end:-1:1), 'valid');
To achieve the result you want you need to flip the second vector and keep only the "valid" part of the convolution (no border effects).
In your example:
>> M = [2 3 4 5 6 7];
>> N = [1 2 3];
>> result = conv(M, N(end:-1:1), 'valid')
result =
20 26 32 38
How to select a submatrix (not in any pattern) in Matlab? For example, for a matrix of size 10 by 10, how to select the submatrix consisting of intersection of the 1st 2nd and 9th rows and the 4th and 6th columns?
Thanks for any helpful answers!
TLDR: Short Answer
As for your question, suppose you have an arbitrary 10-by-10 matrix A. The simplest way to extract the desired sub-matrix would be with an index vector:
B = A([1 2 9], [4 6]);
Indexing in MATLAB
There's an interesting article in the official documentation that comprehensively explains indexing in MATLAB.
Basically, there are several ways to extract a subset of values, I'll summarize them for you:
1. Indexing Vectors
Indexing vectors indicate the indices of the element to be extracted. They can either contain a single index or several, like so:
A = [10 20 30 40 50 60 70 80 90]
%# Extracts the third and the ninth element
B = A([3 9]) %# B = [30 90]
Indexing vectors can be specified for each dimension separately, for instance:
A = [10 20 30; 40 50 60; 70 80 90];
%# Extract the first and third rows, and the first and second columns
B = A([1 3], [1 2]) %# B = [10 30; 40 60]
There are also two special subscripts: end and the colon (:):
end simply indicates the last index in that dimension.
The colon is just a short-hand notation for "1:end".
For example, instead of writing A([1 2 3], [2 3]), you can write A(:, 2:end). This is especially useful for large matrices.
2. Linear Indexing
Linear indexing treats any matrix as if it were a column vector by concatenating the columns into one column vector and assigning indices to the elements respectively. For instance, we have:
A = [10 20 30; 40 50 60; 70 80 90];
and we want to compute b = A(2). The equivalent column vector is:
A = [10;
40;
70;
20;
50;
80;
30;
60;
90]
and thus b equals 40.
The special colon and end subscripts are also allowed, of course. For that reason, A(:) converts any matrix A into a column vector.
Linear indexing with matrix subscripts:
It is also possible to use another matrix for linear indexing. The subscript matrix is simply converted into a column vector, and used for linear indexing. The resulting matrix is, however always of the same dimensions as the subscript matrix.
For instance, if I = [1 3; 1 2], then A(I) is the same as writing reshape(A(I(:)), size(I)).
Converting from matrix subscripts to linear indices and vice versa:
For that you have sub2ind and ind2sub, respectively. For example, if you want to convert the subscripts [1, 3] in matrix A (corresponding to element 30) into a linear index, you can write sub2ind(size(A), 1, 3) (the result in this case should be 7, of course).
3. Logical Indexing
In logical indexing the subscripts are binary, where a logical 1 indicates that the corresponding element is selected, and 0 means it is not. The subscript vector must be either of the same dimensions as the original matrix or a vector with the same number of elements. For instance, if we have:
A = [10 20 30; 40 50 60; 70 80 90];
and we want to extract A([1 3], [1 2]) using logical indexing, we can do either this:
Ir = logical([1 1 0]);
Ic = logical([1 0 1]);
B = A(Ir, Ic)
or this:
I = logical([1 0 1; 1 0 1; 0 0 0]);
B = A(I)
or this:
I = logical([1 1 0 0 0 0 1 1 0]);
B = A(I)
Note that in the latter two cases is a one-dimensional vector, and should be reshaped back into a matrix if necessary (for example, using reshape).
Let me explain with an example:
Let's define a 6x6 matrix
A = magic(6)
A =
35 1 6 26 19 24
3 32 7 21 23 25
31 9 2 22 27 20
8 28 33 17 10 15
30 5 34 12 14 16
4 36 29 13 18 11
From this matrix you want the elements in rows 1, 2 and 5, and in the columns 4 and 6
B = A([1 2 5],[4 6])
B =
26 24
21 25
12 16
Hope this helps.
function f = sub(A,i,j)
[m,n] = size(A);
row = 1:m;
col = 1:n;
x = row;
x(i) = [];
y=col;
y(j) = [];
f= A(x,y);
Returns the matrix A, with the ith row and jth column removed.
I am super new to matlab. I want to implement the KNN algorithm. I tried to read the fitcknn classifier but I can't get it.
I have matrix x that has 4 input vectors (each vector has 3 features)
1 2 3
5 19 20
1 2 4
8 19 21
I want to get out an output matrix Y that gives me the nearest neighbors (in order) for each vector of the input matrix.
For example: y in this case will be
3 2 4
4 3 1
1 2 4
2 3 1
Explanation: the first row of matrix Y shows that the closest vectors to vector 1 are: vector 3 then vector 2 then vector 4.
Is there a library to do this classification (using the cosine distance as a similarity function)?
Thanks.
n = size(x,1);
dist = squareform(pdist(x,'cosine')); %// distance matrix
dist(1:n+1:end) = inf; %// self-distance doesn't count
[~, y] = sort(dist,2);
y = y(:,1:n-1);
To save memory, you can work in chunks using pdist2 instead of pdist:
n = size(x,1);
m = 100; %// chunk size. As large as memory allows. Divisor of n
y = NaN(n,n-1); %// pre-allocate results
for ii = 0:m:size(x,1)-1
ind = ii+(1:m); %// current chunk: these rows
dist_chunk = pdist2(x(ind,:),x,'cosine'); %// results for this chunk
[~, y_chunk] = sort(dist_chunk,2);
y(ind,:) = y_chunk(:,2:end); %// fill results, except self-distance
end
I need to access several indices around a certain point in 3D.
For example, for point (x1,y1,z1) I need to get all the indices of its 3x3x3 neighborhood such that (x1,y1,z1) is centered. For neighborhood of size 3, I do it with
[x,y,z] = meshgrid(-1:1,-1:1,-1:1);
x_neighbors = bsxfun(#plus,x,x1);
y_neighbors = bsxfun(#plus,y,y1);
z_neighbors = bsxfun(#plus,z,z1);
Here, I center x1,y1,z1 to (0,0,0) by adding the distances from (x1,y1,z1) to any point in the 3x3x3 box.
that gives me the coordinates of (x1,y1,z1) 3x3x3 neighborhood. I then need to turn them into linear indices so I can access them:
lin_ind = sub2ind(size(volume),y_neighbors,x_neighbors,z_neighbors);
that is costly in what I do.
My question is, how to avoid sub2ind. If inx is the linear index of (x1,y1,z1),
inx = sub2ind(size(volume),y1,x1,z1);
how can I find the 3x3x3 neighborhood of the linear index by adding or subtracting or any other simple operation of inx?
As long as you know the dimensions of your 3D array, you can compute the linear offsets of all the elements of the 3x3x3 neighborhood. To illustrate this, consider a 2D example of a 4x5 matrix. The linear indices look like this:
1 5 9 13 17
2 6 10 14 18
3 7 11 15 19
4 8 12 16 20
The 3x3 neighborhood of 10 is [5 6 7 9 10 11 13 14 15]. The 3x3 neighborhood of 15 is [10 11 12 14 15 16 18 19 20]. If we subtract off the index of the central element, in both cases we get [-5 -4 -3 -1 0 1 3 4 5]. More generally, for MxN matrix we will have [-M-1 -M -M+1 -1 0 1 M-1 M M+1], or [(-M+[-1 0 1]) -1 0 1 (M+[-1 0 1])].
Generalizing to three dimensions, if the array is MxNxP, the linear index offsets from the central element will be [(-M*N+[-M-1 -M -M+1 -1 0 1 M-1 M M+1]) [-M-1 -M -M+1 -1 0 1 M-1 M M+1] (M*N+[-M-1 -M -M+1 -1 0 1 M-1 M M+1])]. You can reshape this to 3x3x3 if you wish.
Note that this sort of indexing doesn't deal well with edges; if you want to find the neighbors of an element on the edge of the array you should probably pad the array on all sides first (thereby changing M, N, and P).
Just adding the (generalized) code to #nhowe answer:
This is an example for neighborhood of size 5X5X5, therefore r (the radius) is 2:
ns = 5;
r = 2;
[M,N,D] = size(vol);
rs = (1:ns)-(r+1);
% 2d generic coordinates:
neigh2d = bsxfun(#plus, M*rs,rs');
% 3d generic coordinates:
pages = (M*N)*rs;
pages = reshape(pages,1,1,length(pages));
neigh3d = bsxfun(#plus,neigh2d,pages);
to get any neighborhood of any linear index of vol, just add the linear index to neigh3d:
new_neigh = bxsfun(#plus,neigh3d, lin_index);
How to select a submatrix (not in any pattern) in Matlab? For example, for a matrix of size 10 by 10, how to select the submatrix consisting of intersection of the 1st 2nd and 9th rows and the 4th and 6th columns?
Thanks for any helpful answers!
TLDR: Short Answer
As for your question, suppose you have an arbitrary 10-by-10 matrix A. The simplest way to extract the desired sub-matrix would be with an index vector:
B = A([1 2 9], [4 6]);
Indexing in MATLAB
There's an interesting article in the official documentation that comprehensively explains indexing in MATLAB.
Basically, there are several ways to extract a subset of values, I'll summarize them for you:
1. Indexing Vectors
Indexing vectors indicate the indices of the element to be extracted. They can either contain a single index or several, like so:
A = [10 20 30 40 50 60 70 80 90]
%# Extracts the third and the ninth element
B = A([3 9]) %# B = [30 90]
Indexing vectors can be specified for each dimension separately, for instance:
A = [10 20 30; 40 50 60; 70 80 90];
%# Extract the first and third rows, and the first and second columns
B = A([1 3], [1 2]) %# B = [10 30; 40 60]
There are also two special subscripts: end and the colon (:):
end simply indicates the last index in that dimension.
The colon is just a short-hand notation for "1:end".
For example, instead of writing A([1 2 3], [2 3]), you can write A(:, 2:end). This is especially useful for large matrices.
2. Linear Indexing
Linear indexing treats any matrix as if it were a column vector by concatenating the columns into one column vector and assigning indices to the elements respectively. For instance, we have:
A = [10 20 30; 40 50 60; 70 80 90];
and we want to compute b = A(2). The equivalent column vector is:
A = [10;
40;
70;
20;
50;
80;
30;
60;
90]
and thus b equals 40.
The special colon and end subscripts are also allowed, of course. For that reason, A(:) converts any matrix A into a column vector.
Linear indexing with matrix subscripts:
It is also possible to use another matrix for linear indexing. The subscript matrix is simply converted into a column vector, and used for linear indexing. The resulting matrix is, however always of the same dimensions as the subscript matrix.
For instance, if I = [1 3; 1 2], then A(I) is the same as writing reshape(A(I(:)), size(I)).
Converting from matrix subscripts to linear indices and vice versa:
For that you have sub2ind and ind2sub, respectively. For example, if you want to convert the subscripts [1, 3] in matrix A (corresponding to element 30) into a linear index, you can write sub2ind(size(A), 1, 3) (the result in this case should be 7, of course).
3. Logical Indexing
In logical indexing the subscripts are binary, where a logical 1 indicates that the corresponding element is selected, and 0 means it is not. The subscript vector must be either of the same dimensions as the original matrix or a vector with the same number of elements. For instance, if we have:
A = [10 20 30; 40 50 60; 70 80 90];
and we want to extract A([1 3], [1 2]) using logical indexing, we can do either this:
Ir = logical([1 1 0]);
Ic = logical([1 0 1]);
B = A(Ir, Ic)
or this:
I = logical([1 0 1; 1 0 1; 0 0 0]);
B = A(I)
or this:
I = logical([1 1 0 0 0 0 1 1 0]);
B = A(I)
Note that in the latter two cases is a one-dimensional vector, and should be reshaped back into a matrix if necessary (for example, using reshape).
Let me explain with an example:
Let's define a 6x6 matrix
A = magic(6)
A =
35 1 6 26 19 24
3 32 7 21 23 25
31 9 2 22 27 20
8 28 33 17 10 15
30 5 34 12 14 16
4 36 29 13 18 11
From this matrix you want the elements in rows 1, 2 and 5, and in the columns 4 and 6
B = A([1 2 5],[4 6])
B =
26 24
21 25
12 16
Hope this helps.
function f = sub(A,i,j)
[m,n] = size(A);
row = 1:m;
col = 1:n;
x = row;
x(i) = [];
y=col;
y(j) = [];
f= A(x,y);
Returns the matrix A, with the ith row and jth column removed.