how to select a submatrix from a matrix in Matlab [duplicate] - matlab

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.

Related

Indexing all diagonals of a matrix in MATLAB

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

Repeat row vector as matrix with different offsets in each row

I want to repeat a row vector to create a matrix, in which every row is a slightly modified version of the original vector.
For example, if I have a vector v = [10 20 30 40 50], I want every row of my matrix to be that vector, but with a random number added to every element of the vector to add some fluctuations.
My matrix should look like this:
M = [10+a 20+a 30+a 40+a 50+a;
10+b 20+b 30+b 40+b 50+b;
... ]
Where a, b, ... are random numbers between 0 and 2, for an arbitrary number of matrix rows.
Any ideas?
In Matlab, you can add a column vector to a matrix. This will add the vector elements to each of the row values accordingly.
Example:
>> M = [1 2 3; 4 5 6; 7 8 9];
>> v = [1; 2; 3];
>> v + M
ans =
2 3 4
6 7 8
10 11 12
Note that in your case v is a row vector, so you should transpose it first (using v.').
As Sardar Usama and Wolfie note, this method of adding is only possible since MATLAB version R2016b, for earlier versions you will need to use bsxfun:
>> % instead of `v + M`
>> bsxfun(#plus, v, M)
ans =
2 4 6
5 7 9
8 10 12
If you have a MATLAB version earlier than 2016b (when implicit expansion was introduced, as demonstrated in Daan's answer) then you should use bsxfun.
v = [10 20 30 40 50]; % initial row vector
offsets = rand(3,1); % random values, add one per row (this should be a column vector)
output = bsxfun(#plus,offsets,v);
Result:
>> output =
10.643 20.643 30.643 40.643 50.643
10.704 20.704 30.704 40.704 50.704
10.393 20.393 30.393 40.393 50.393
This can be more easily understood with less random inputs!
v = [10 20 30 40 50];
offsets = [1; 2; 3];
output = bsxfun(#plus,offsets,v);
>> output =
11 21 31 41 51
12 22 32 42 52
13 23 33 43 53
Side note: to get an nx1 vector of random numbers between 0 and 2, use
offsets = rand(n,1)*2

MATLAB: Use a single row vector to specify which row element of a multiple row matrix to select

Given an mxn matrix e.g.
M= [ 10 20 30 40; 11 12 13 14; 19 18 17 16];
and a 1xn 'selector'
S = [1 2 3 1];
where all elements of S are in the range 1..m, I want the output vector O with size 1xn s.t. O[1, i] = M[ S[i], i]. In this example
O = [10 12 17 40];
Clearly I can do this using a loop. Is there a way to vectorize it which is more cost effective than a loop assuming that m and n are in the hundreds ?
You are looking for sub2ind. So the desired output could be achieved with -
O = M(sub2ind(size(M),S,1:numel(S)))
Or for performance, you can use a raw version of sub2ind -
O = M([0:numel(S)-1]*size(M,1) + S)

How can I use values within a MATLAB matrix as indices to determine the location of data in a new matrix?

I have a matrix that looks like the following.
I want to take the column 3 values and put them in another matrix, according to the following rule.
The value in the Column 5 is the row index for the new matrix, and Column 6 is the column index. Therefore 20 (taken from 29,3) should be in Row 1 Column 57 of the new matrix, 30 (from 30,3) should in Row 1 column 4 of the new matrix, and so on.
If the value in column 3 is NaN then I want NaN to be copied over to the new matrix.
Example:
% matrix of values and row/column subscripts
A = [
20 1 57
30 1 4
25 1 16
nan 1 26
nan 1 28
25 1 36
nan 1 53
50 1 56
nan 2 1
nan 2 2
nan 2 3
80 2 5
];
% fill new matrix
B = zeros(5,60);
idx = sub2ind(size(B), A(:,2), A(:,3));
B(idx) = A(:,1);
There are a couple other ways to do this, but I think the above code is easy to understand. It is using linear indexing.
Assuming you don't have duplicate subscripts, you could also use:
B = full(sparse(A(:,2), A(:,3), A(:,1), m, n));
(where m and n are the output matrix size)
Another one:
B = accumarray(A(:,[2 3]), A(:,1), [m,n]);
I am not sure if I understood your question clearly but this might help:
(Assuming your main matrix is A)
nRows = max(A(:,5));
nColumns = max(A(:,6));
FinalMatrix = zeros(nRows,nColumns);
for i=1:size(A,1)
FinalMatrix(A(i,5),A(i,6))=A(i,3);
end
Note that above code sets the rest of the elements equal to zero.

How to select a submatrix (not in any particular pattern) in Matlab

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.