How to save indices and values from Matrix in Matlab? - matlab

I have a 3x3 Matrix and want to save the indices and values into a new 9x3 matrix. For example A = [1 2 3 ; 4 5 6 ; 7 8 9] so that I will get a matrix x = [1 1 1; 1 2 2; 1 3 3; 2 1 4; 2 2 5; ...] With my code I only be able to store the last values x = [3 3 9].
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x=[];
for i = 1:size(A)
for j = 1:size(A)
x =[i j A(i,j)]
end
end
Thanks for your help

Vectorized approach
Here's one way to do it that avoids loops:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
[ii, jj] = ndgrid(1:size(A,1), 1:size(A,2)); % row and column indices
vv = A.'; % values. Transpose because column changes first in the result, then row
x = [jj(:) ii(:) vv(:)]; % result
Using your code
You're only missing concatenation with previous x:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x = [];
for i = 1:size(A)
for j = 1:size(A)
x = [x; i j A(i,j)]; % concatenate new row to previous x
end
end
Two additional suggestions:
Don't use i and j as variable names, because that shadows the imaginary unit.
Preallocate x instead of having it grow in each iteration, to increase speed.
The modified code is:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x = NaN(numel(A),3); % preallocate
n = 0;
for ii = 1:size(A)
for jj = 1:size(A)
n = n + 1; % update row counter
x(n,:) = [ii jj A(ii,jj)]; % fill row n
end
end

I developed a solution that works much faster. Here is the code:
% Generate subscripts from linear index
[i, j] = ind2sub(size(A),1:numel(A));
% Just concatenate subscripts and values
x = [i' j' A(:)];
Try it out and let me know ;)

Related

Reordering rows of several arrays in Matlab

Consider three matrices X1, X2, X3 in Matlab of dimension Nx(N-1) listing some integers among 0,1,...,10.
I want to reorder the elements in each row of X1, X2, X3 wrto X1, then X2 (if some elements of X1 are equal), then X3 (if some elements of X2 are equal) in ascending order.
Example 1
N=3;
X1=[3 8;
7 7;
2 1];
X2=[10 1;
10 9;
4 4];
X3=[1 1;
1 0;
1 0];
%I want to obtain
X1new=[3 8;
7 7;
1 2];
X2new=[10 1;
9 10;
4 4];
X3new=[1 1;
0 1;
0 1];
Example 2
N=4;
X1=[3 8 9;
7 6 6;
2 1 4;
4 4 4];
X2=[10 1 2;
9 10 10;
4 4 5;
5 5 2];
X3=[1 1 1;
0 0 1;
1 0 0;
0 0 0];
%I want to obtain
X1new=[3 8 9;
6 6 7;
1 2 4;
4 4 4];
X2new=[10 1 2;
10 10 9;
4 4 5;
2 5 5];
X3new=[1 1 1;
0 1 0;
0 1 0;
0 0 0];
This code does what I want. Could you suggest more efficient alternatives (if any) for cases in which size(Y,1) is large?
% 1) Create a 3d matrix Y of dimension Nx(N-1)x3
Y=NaN(N,N-1,3);
Y(:,:,1)=X1;
Y(:,:,2)=X2;
Y(:,:,3)=X3;
% 2) Reorder elements in each row (independently)
%wrto Y(:,:,1), then Y(:,:,2), then Y(:,:,3) in ascending order.
%Store everything in Ynew of dimension Nx(N-1)x3
Ynew = NaN(N,N-1,3);
for h = 1:size(Y,1),
Ynew (h,:,:) = sortrows(squeeze(Y(h,:,:)), [1 2 3]);
end
% 3) Create X1new, X2new, X3new
X1new=Ynew(:,:,1);
X2new=Ynew(:,:,2);
X3new=Ynew(:,:,3);
Since the numbers are between 0 and 10, you can easily combine the three matrices into one for the purposes of sorting (step 1); sort each row of the combined matrix and get the indices of that sorting (step 2); and from that build a linear index (step 3) which you can use into the original matrices (step 4):
M = 11; % Strict upper bound on possible values
Y = X1 + X2/M + X3/M^2; % STEP 1: combined matrix
[~, cols] = sort(Y, 2); % STEP 2: sort each row and get indices of sorting
ind = bsxfun(#plus, (1:size(X1,1)).', (cols-1)*size(X1,1)); % STEP 3: linear index
X1new = X1(ind); % STEP 4: result
X2new = X2(ind);
X3new = X3(ind);
sort(X,2) will do this. The 2 is to do it row-wise.
It can be done simply by using
'sort' command in Matlab
X1new = sort(X1,2);
X2new = sort(X2,2);
X3new = sort(X3,2);

Matrix Basis expansion

MATLAB:
I am trying to do basis expansion of a huge matrix(1000x15).
For example,
X =
x1 x2
1 4
2 5
3 6
I want to build a new matrix.
Y =
x1 x2 x1*x1 x1*x2 x2*x2
1 4 1 4 16
2 5 4 10 25
3 6 9 18 36
Could any one please suggest a easier way to do this
% your input
A = [1 4; 2 5; 3 6];
% generate pairs
[p,q] = meshgrid(1:size(A,2), 1:size(A,2));
% only retain unique pairs
ii = tril(p) > 0;
% perform element wise multiplication
res = [A A(:,p(ii)) .* A(:,q(ii))];
Using the one-liner from this answer to get the 2-combinations of the indices, you can generate the matrix without the interleaved ordering with
function Y = columnCombo(Y)
comb = nchoosek(1:size(Y,2),2);
Y = [Y , Y.^2 , Y(:,comb(:,1)).*Y(:,comb(:,2))];
end
For the interleaved ordering, I came up with this, possibly sub-optimal, solution:
function Y = columnCombo(Y)
[m,n] = size(Y);
comb = nchoosek(1:n,2);
Y = [Y,zeros(m,n + size(comb,1))];
col = n+1;
for k = 1:n-1
Y(:,col) = Y(:,k).*Y(:,k) ;
ms = comb(comb(:,1)==k,:) ;
ncol = size(ms,1) ;
Y(:,col+(1:ncol)) = Y(:,ms(:,1)).*Y(:,ms(:,2)) ;
col = col + ncol + 1 ;
end
Y(:,end) = Y(:,n).^2;
end

Design a simple matrix to group values from matrices

This problem is a succession of my previous problem:
1) Extract submatrices, 2) vectorize and then 3) put back
Now, I have two patients, named Ann and Ben.
Indeed the matrices A and B are data for Ann and the matrix C is data for Ben:
Now, I need to design a matrix M such that y = M*x where
y = [a11, a21, a12, a22, b11, b21, b12, b22]' which is a vector, resulting from concatenation of the top-left sub-matrices, Ann and Ben;
x = [2, 5, 4, 6, 7, 9, 6, 2, 9, 3, 4, 2]' which is a vector, resulting from concatenation of sub-matrices A, B and C.
Here, the M is a 8 by 12 matrix that
a11 = 2 + 7, a21 = 5 + 9, .., a22 = 6 + 2 and b11 = 9, ..b22 = 2.
I design the M manually by:
M=zeros(8,12)
M(1,1)=1; M(1,5)=1; % compute a11
M(2,2)=1; M(2,6)=1; % compute a21
M(3,3)=1; M(3,7)=1; % compute a12
M(4,4)=1; M(4,8)=1; % compute a22
M(5,9)=1; % for setting b11 = 9, C(1,1)
M(6,10)=1; % for setting b21 = 3, C(2,1)
M(7,11)=1; % for setting b12 = 4, C(1,2)
M(8,12)=1 % for setting b22 = 2, C(2,2)
Obviously, in general for M(i,j), i means the 8 linear-index position of vector y and j means linear-index position of vector x.
However, I largely simplified my original problem that I want to construct this M automatically.
Thanks in advance for giving me a hand.
Here you have my solution. I have essentially build the matrix M automatically (from the proper indexes) as you suggested.
A = [2 4 8;
5 6 3;
10 3 6];
B = [7 6 3;
9 2 9;
10 2 3];
C = [9 4 7;
3 2 5;
10 3 4];
% All matrices in the same array
concat = cat(3, A, B, C);
concat_sub = concat(1:2,1:2,:);
x = concat_sub(:);
n = numel(x)/3; %Number of elements in each subset
M2 = zeros(12,8); %Transpose of the M matrix (it could be implemented directly over M but that was my first approach)
% The indexes you need
idx1 = 1:13:12*n; % Indeces for A
idx2 = 5:13:12*2*n; % Indices for B and C
M2([idx1 idx2]) = 1;
M = M2';
y = M*x
I have taken advantage of the shape that the matrix M shold take:
You can index into things and extract what you want without multiplication. For your example:
A = [2 4 8; 5 6 3; 10 3 6];
B = [7 6 3; 9 2 9; 10 2 3];
C = [9 4 7;3 2 5; 10 3 4];
idx = logical([1 1 0;1 1 0; 0 0 0]);
Ai = A(idx);
Bi = B(idx);
Ci = C(idx);
output = [Ai; Bi; Ci];
y = [Ai + Bi; Ci]; % desired y vector
This shows each step individually but they can be done in 2 lines. Define the index and then apply it.
idx = logical([1 1 0;1 1 0;0 0 0]);
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Also you can use linear indexing with idx = [1 2 4 5]' This will produce the same subvector for each of A B C. Either way works.
idx = [1 2 4 5]';
or alternatively
idx = [1;2;4;5];
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Either way works. Check out doc sub2ind for some examples of indexing from MathWorks.

shifting versions of a matrix

I have a m-by-n matrix and I want to shift each row elements k no. of times (" one resultant matrix for each one shift so a total of k matrices corresponding to each row shifts ")(k can be different for different rows and 0<=k<=n) and want to index all the resultant matrices corresponding to each individual shift.
Eg: I have the matrix: [1 2 3 4; 5 6 7 8; 2 3 4 5]. Now, say, I want to shift row1 by 2 times (i.e. k=2 for row1) and row2 by 3times (i.e. k=3 for row2) and want to index all the shifted versions of matrices (It is similar to combinatorics of rows but with limited and diffeent no. of shifts to each row).
Can someone help to write up the code? (please help to write the general code but not for the example I mentioned here)
I found the following question useful to some extent, but it won't solve my problem as my problem looks like a special case of this problem:
Matlab: How to get all the possible different matrices by shifting it's rows (Update: each row has a different step)
See if this works for you -
%// Input m-by-n matrix
A = rand(2,5) %// Edit this to your data
%// Initialize shifts, k for each row. The number of elements would be m.
sr = [2 3]; %// Edit this to your data
[m,n] = size(A); %// Get size
%// Get all the shits in one go
sr_ind = arrayfun(#(x) 0:x,sr,'un',0); %//'
shifts = allcomb(sr_ind{:},'matlab')'; %//'
for k1 = 1:size(shifts,2)
%// Get shift to be used for each row for each iteration
shift1 = shifts(:,k1);
%// Get circularly shifted column indices
t2 = mod(bsxfun(#minus,1:n,shift1),n);
t2(t2==0) = n;
%// Get the linear indices and use them to index into input to get the output
ind = bsxfun(#plus,[1:m]',(t2-1)*m); %//'
all_matrices = A(ind) %// outputs
end
Please note that this code uses MATLAB file-exchange code allcomb.
If your problem in reality is not more complex than what you showed us, it can be done by a double loop. However, i don't like my solution, because you would need another nested loop for each row you want to shift. Also it generates all shift-combinations from your given k-numbers, so it has alot of overhead. But this can be a start:
% input
m = [1 2 3 4; 5 6 7 8; 2 3 4 5];
shift_times = {0:2, 0:3}; % 2 times for row 1, 3 times for row 2
% desird results
desired_matrices{1} = [4 1 2 3; 5 6 7 8; 2 3 4 5];
desired_matrices{2} = [3 4 1 2; 5 6 7 8; 2 3 4 5];
desired_matrices{3} = [1 2 3 4; 8 5 6 7; 2 3 4 5];
desired_matrices{4} = [4 1 2 3; 8 5 6 7; 2 3 4 5];
desired_matrices{5} = [3 4 1 2; 8 5 6 7; 2 3 4 5];
% info needed:
[rows, cols] = size(m);
count = 0;
% make all shift combinations
for shift1 = shift_times{1}
% shift row 1
m_shifted = m;
idx_shifted = [circshift([1:cols]',shift1)]';
m_shifted(1, :) = m_shifted(1, idx_shifted);
for shift2 = shift_times{2}
% shift row 2
idx_shifted = [circshift([1:cols]',shift2)]';
m_shifted(2, :) = m_shifted(r_s, idx_shifted);
% store them
store{shift1+1, shift2+1} = m_shifted;
end
end
% store{i+1, j+1} stores row 1 shifted by i and row 2 shifted by j
% example
all(all(store{2,1} == desired_matrices{1})) % row1: 1, row2: 0
all(all(store{2,2} == desired_matrices{4})) % row1: 1, row2: 1
all(all(store{3,2} == desired_matrices{5})) % row1: 2, row2: 1

Extracting a specific element from each cell within cell array

I have a cell array A of size 10x10 (say). Each cell in turn contains a 5x20 matrix. I want to select (i,j) element from each cell, where (i,j) are indices within a loop. I can run 4 for loops and easily get the answer. It may even be faster as it has been discussed many times that loops could be faster than cellfun, structfun etc.
Still, is there any solution using cellfun which I can use in a loop over (i,j) and extract (i,j) element in each cell? I tried writing a function which will act as handle to cellfun but I couldn't access two-leves down i.e. A{eachCellRow,eachCellCol}(i,j).
Example:
If A={[1 2;5 6], [3 4; 6 7]; [3 4; 6 7], [9 8; 5 6]};
Then for i=1, j=1 and i=2, j=1 output should be:
B=[1 3; 3 9] and B=[5 6; 6 5]
CELL2MAT gets all the data from a cell array that consists of numeric data only, into a numeric array. So, that helped us here. For your original problem, try this -
celldim_i = 10;
celldim_j = 10;
block_size_i = 5;
block_size_j = 20;
search_i = i; %// Edit to your i
search_j = j; %// Edit to your j
A_mat = cell2mat(A);
out = A_mat(search_i+block_size_i*(0:celldim_i-1),search_j+block_size_j*(0:celldim_j-1))
The easy to use cellfun one-liner would be:
ii = 2;
jj = 1;
A = {[1 2;5 6], [3 4; 6 7]; [3 4; 6 7], [9 8; 5 6]};
B = cell2mat( cellfun( #(x) x(ii,jj), A, 'uni', 0) )
gives:
B =
5 6
6 5
Advantage over Divakar's Solution: it works also for inconsistent matrix sizes in A.
And if you want to avoid also the outer loop, another fancy two-liner:
dim = [2 2];
[II, JJ] = meshgrid( 1:dim(1), 1:dim(2) );
C = cellfun( #(y) ...
{ cell2mat( cellfun( #(x) x( real(y), imag(y) ), A, 'uni', 0) ) },...
num2cell( II(:)+1i*JJ(:) ))
gives:
>> celldisp(C)
C{1} = % ii = 1 , jj = 1
1 3
3 9
C{2} = % ii = 1 , jj = 2
2 4
4 8
C{3} = % ii = 2 , jj = 1
5 6
6 5
C{4} = % ii = 2 , jj = 2
6 7
7 6
If memory is not an issue, you can concat all matrices along a third dim; and then indexing is very easy:
%// Example data
A = {[1 2;5 6], [3 4; 6 7]; [3 4; 6 7], [9 8; 5 6]};
ii = 2;
jj = 1;
%// Compute the result B
A2 = cat(3,A{:}); %// concat along third dim
B = reshape(A2(ii,jj,:),size(A{1})); %// index A2 and reshape