Extracting multiple matrix from a single matrix in MATLAB [duplicate] - matlab

This question already has answers here:
split a matrix according to a column with matlab.
(3 answers)
Closed 4 years ago.
I have a matrix(type double) similar to the following example:
X = [ 23 3 5 1;
21 45 8 1;
65 56 7 1;
71 42 4 2;
45 91 5 2;
34 6 1 3;
87 37 8 3;
23 3 5 3]
Based on the element of the fourth column I want to get 3 matrix from the above matrix like the following example;
A=[ 23 3 5 1;
21 45 8 1;
65 56 7 1; ]
B =[ 71 42 4 2;
45 91 5 2; ]
C =[ 34 6 1 3;
87 37 8 3;
23 3 5 3;]
Basically I want to seprate all the 1s,2s and 3s of the fourth column into another matrix. How can I do it in the Matlab!

A = X(:,X(:,4)==1);
B = X(:,X(:,4)==2);
C = X(:,X(:,4)==3);

Related

How to loop over 3 elements of an array?

I am trying to create a loop that selects 3 rows from an array at a time and does some calculation later.
For example:
array = [2 3 4; 4 5 6; 7 8 9; 10 11 23; 23 56 78; 67 55 89; 90 87 32]
So in the first loop it should select [2 3 4; 4 5 6; 7 8 9]
and in the second loop [10 11 23; 23 56 78; 67 55 89].
I am struggling to make this possible.
Hope the code Help:
clear, clc
% Array
Arr = [2 3 4; 4 5 6; 7 8 9; 10 11 23; 23 56 78; 67 55 89; 90 87 32];
% Define The Length to Prevent the Error of Iteration in For Loop
if mod(size(Arr,1),3) ==0
LenArr = size(Arr,1); % Length Examined
else
LenArr = size(Arr,1) - mod(size(Arr,1),3);
end
Counter = 1;
for i = 1:3: LenArr
Iter = Arr(i:i+2, :); % Here the Answer of the Question
% Disply Results ----------
fprintf('Iteration %d = \n',Counter)
disp(Iter)
Counter = Counter+1;
%--------------------------
end
Results:
Iteration 1 =
2 3 4
4 5 6
7 8 9
Iteration 2 =
10 11 23
23 56 78
67 55 89
you can do this like below code
your algorithms can be applied to selectBlockLocations variable.
array = [2 3 4; 4 5 6; 7 8 9; 10 11 23; 23 56 78; 67 55 89; 90 87 32];
number_of_loop = floor(length(array)/3);
for i=0:number_of_loop-1
selectBlockLocations = array(i*3+1:i*3+3, 1:end);
disp(selectBlockLocations)
end
result:
2 3 4
4 5 6
7 8 9
10 11 23
23 56 78
67 55 89
Have a good time!

Matlab: how I can transform this algorithm associated with matrices manipulation?

(For my problem, I use a matrix A 4x500000. And the values of A(4,k) varies between 1 and 200).
I give here an example for a case A 4x16 and A(4,k) varies between 1 and 10.
I want first to match a name to the value from 1 to 5 (=10/2):
1 = XXY;
2 = ABC;
3 = EFG;
4 = TXG;
5 = ZPF;
My goal is to find,for a vector X, a matrix M from the matrix A:
A = [20 52 70 20 52 20 52 20 20 10 52 20 11 1 52 20
32 24 91 44 60 32 24 32 32 12 11 32 2 5 24 32
40 37 24 30 11 40 37 40 40 5 10 40 40 3 37 40
2 4 1 3 4 5 2 1 3 3 8 6 7 9 6 10]
A(4,k) takes all values between 1 and 10. These values can be repeated and they all appear on the 4th line.
20
X= 32 =A(1:3,1)=A(1:3,6)=A(1:3,8)=A(1:3,9)=A(1:3,12)=A(1:3,16)
40
A(4,1) = 2;
A(4,6) = 5;
A(4,8) = 1;
A(4,9) = 3;
A(4,12) = 6;
A(4,16) = 10;
for A(4,k) corresponding to X, I associate 2 if A(4,k)<= 5, and 1 if A(4,k)> 5. For the rest of the value of A(4,k) which do not correspond to X, I associate 0:
[ 1 2 3 4 5 %% value of the fourth line of A between 1 and 5
2 2 2 0 2
ZX = 6 7 8 9 10 %% value of the fourth line of A between 6 and 10
1 0 0 0 1
2 2 2 0 2 ] %% = max(ZX(2,k),ZX(4,k))
the ultimate goal is to find the matrix M:
M = [ 1 2 3 4 5
XXY ABC EFG TXG ZPF
2 2 2 0 2 ] %% M(3,:)=ZX(5,:)
Code -
%// Assuming A, X and names to be given to the solution
A = [20 52 70 20 52 20 52 20 20 10 52 20 11 1 52 20
32 24 91 44 60 32 24 32 32 12 11 32 2 5 24 32
40 37 24 30 11 40 37 40 40 5 10 40 40 3 37 40
2 4 1 3 4 5 2 1 3 3 8 6 7 9 6 10];
X = [20 ; 32 ; 40];
names = {'XXY','ABC','EFG','TXG','ZPF'};
limit = 10; %// The maximum limit of A(4,:). Edit this to 200 for your actual case
%// Find matching 4th row elements
matches = A(4,ismember(A(1:3,:)',X','rows'));
%// Matches are compared against all possible numbers between 1 and limit
matches_pos = ismember(1:limit,matches);
%// Finally get the line 3 results of M
vals = max(2*matches_pos(1:limit/2),matches_pos( (limit/2)+1:end ));
Output -
vals =
2 2 2 0 2
For a better way to present the results, you can use a struct -
M_struct = cell2struct(num2cell(vals),names,2)
Output -
M_struct =
XXY: 2
ABC: 2
EFG: 2
TXG: 0
ZPF: 2
For writing the results to a text file -
output_file = 'results.txt'; %// Edit if needed to be saved to a different path
fid = fopen(output_file, 'w+');
for ii=1:numel(names)
fprintf(fid, '%d %s %d\n',ii, names{ii},vals(ii));
end
fclose(fid);
Text contents of the text file would be -
1 XXY 2
2 ABC 2
3 EFG 2
4 TXG 0
5 ZPF 2
A bsxfun() based approach.
Suppose your inputs are (where N can be set to 200):
A = [20 52 70 20 52 20 52 20 20 10 52 20 11 1 52 20
32 24 91 44 60 32 24 32 32 12 11 32 2 5 24 32
40 37 24 30 11 40 37 40 40 5 10 40 40 3 37 40
2 4 1 3 4 5 2 1 3 3 8 6 7 9 6 10]
X = [20; 32; 40]
N = 10;
% Match first 3 rows and return 4th
idxA = all(bsxfun(#eq, X, A(1:3,:)));
Amatch = A(4,idxA);
% Match [1:5; 5:10] to 4th row
idxZX = ismember([1:N/2; N/2+1:N], Amatch)
idxZX =
1 1 1 0 1
1 0 0 0 1
% Return M3
M3 = max(bsxfun(#times, idxZX, [2;1]))
M3 =
2 2 2 0 2

How to use rank index number to sort other set of data using loops?

I am quite new to Matlab, and am tasked to use Matlab to manage a finance/econs database.
To cut straight to the problem. Just imagine I have two sets of data, one is A and another one is B (see below). My objective is to rank the 3 columns according to value size, and then I would like to use the rank index for A (sorted_index) to position the values in B accordingly.
Below is the working but non-looping solution to obtain my answer:
A = [5 17 8; 11 2 9; 55 70 3; 11 8 33; 9 71 35; 9 2 3; 21 5 43; 5 2 9; 41 5 23; 61 72 91];
B = [1 2 3; 11 12 13; 21 22 23; 31 32 33; 1 2 3; 11 12 13; 21 22 23; 31 32 33; 41 42 43; 51 52 53];
[A_sorted sorted_index] = sort (A);
[B_sorted sorted_indexB] = sort (B);
B_sorted (:,1) = B(sorted_index(:,1),1);
B_sorted (:,2) = B(sorted_index(:,2),2);
B_sorted (:,3) = B(sorted_index(:,3),3);
The outcome of B (sorted according to the rank position of A):
1 12 23
31 12 13
1 32 3
11 22 13
11 42 33
31 32 43
21 2 33
41 22 3
21 2 23
51 52 53
The problem is, what if I have 2000 columns instead of just 3, how can i loop successfully?
I tried this
for ii= size(B,2); jj= size(B,2) ; kk= size(B,2);
temp = 0*B;
temp(:,ii) = B(sorted_index(:,jj),kk);
B_sortedTest= temp;
end
But it only turns out to give me the correct sorted result for the last column, the first two columns are overwritten (become all zeros). Can you help me to solve the problem?
Thank you very very much!
Here is my method without any loops:
A = [5 17 8; 11 2 9; 55 70 3; 11 8 33; 9 71 35; 9 2 3; 21 5 43; 5 2 9; 41 5 23; 61 72 91];
B = [1 2 3; 11 12 13; 21 22 23; 31 32 33; 1 2 3; 11 12 13; 21 22 23; 31 32 33; 41 42 43; 51 52 53];
[A_sorted sorted_index] = sort (A);
% converting sorted_index into a vectorized form and having linear indices instead of subscripts i.e.
% (row 2,column 3) in your sorted_index will be represented as 23=2*number of rows + 3=2*10+3.
linearSortedIndex=sub2ind(size(sorted_index),sorted_index(:),reshape(repmat((1:size(sorted_index,2),size(sorted_index,1),1).*ones(size(sorted_index)),[],1));
B_sorted1=reshape(B(linearSortedIndex),[],size(B,2));
%test that the result is correct
for i=1:size(B,2)
B_sorted2(:,i) = B(sorted_index(:,i),i);
end
isequal(B_sorted1,B_sorted2) %If it prints 1, then this method is correct.
Try this:
A = [5 17 8; 11 2 9; 55 70 3; 11 8 33; 9 71 35; 9 2 3; 21 5 43; 5 2 9; 41 5 23; 61 72 91];
B = [1 2 3; 11 12 13; 21 22 23; 31 32 33; 1 2 3; 11 12 13; 21 22 23; 31 32 33; 41 42 43; 51 52 53];
[A_sorted sorted_index] = sort (A);
[B_sorted sorted_indexB] = sort (B);
for i=1:size(B,2)
B_sorted (:,i) = B(sorted_index(:,i),i);
end

corresponding indices from two different matrices in matlab

In an algorithm, in each level, I have two corresponding matrices in a way one of them has 4 times more element than the other. like children and parent, but i need to have the corresponding elements. consider the two following indices as an example for a level
1 5 9 13
2 6 10 14 and 1 3
3 7 11 15 2 4
4 8 12 16
so for example, I want to receive the element by the index of 1 from the second matrix when i have each of 1,2,5,6 element indices from the first matrix or 2 when i have 3,4,7,8 or 3 for 9,10,16,14 and so on. how can i do that?
as an another example for another level:
1 9 17 25 33 41 49 57
2 10 18 26 34 42 50 58
3 11 19 27 35 43 51 59 and 1 5 9 13
4 12 20 28 36 44 52 60 2 6 10 14
5 13 21 29 37 45 53 61 3 7 11 15
6 14 22 30 38 46 54 62 4 8 12 16
7 15 23 31 39 47 55 63
8 16 24 32 40 48 56 64
Here is one way of doing that:
% Size of matrix A (8x8)
sizeA = 8;
% Size of matrix B (4x4)
sizeB = 4;
% Index of element on matrix A
idxA = 43;
% That is how you can get the corresponding index on matrix B
[r, c] = ind2sub([sizeA sizeA], idxA);
idxB = sub2ind([sizeB sizeB], ceil(r / 2), ceil(c / 2))
It will give you idxB = 10.
It is possible that reshape could be helpful for you.
Consider
A = [1 5 9 13;
2 6 10 14;
3 7 11 15;
4 8 12 16];
B = reshape(permute(reshape(A, [2 2 2 2]), [2 4 1 3]), [4 4]);
B
1 2 5 6
3 4 7 8
9 10 13 14
11 12 15 16
Now you have a nice mapping of the indices from one level to the next.
B(1,:) corresponds to all the indices that map to element 1 in your second array, etc.
When the matrix gets larger (2n x 2n), the operation becomes
B = reshape(permute(reshape(A, [2 n 2 n]), [2 4 1 3]), [n*n 4]);
If you know the 2D indices for the first matrix, then you just divide each by 2 to get the second pair indices:
r = 3;
c = 2;
% Then A(r,c) corresponds to B(floor(r/2), floor(c/2))
If you DON'T know the indices, but instead have the element value itself, you have to find the 2D index first:
val = 7; % test value
[r c] = find(A==val);
other_val = B(floor(r/2), floor(c/2));

Matrix division & permutation to achieve Baker map

I'm trying to implement the Baker map.
Is there a function that would allow one to divide a 8 x 8 matrix by providing, for example, a sequence of divisors 2, 4, 2 and rearranging pixels in the order as shown in the matrices below?
X = reshape(1:64,8,8);
After applying divisors 2,4,2 to the matrix X one should get a matrix like A shown below.
A=[31 23 15 7 32 24 16 8;
63 55 47 39 64 56 48 40;
11 3 12 4 13 5 14 6;
27 19 28 20 29 21 30 22;
43 35 44 36 45 37 46 38;
59 51 60 52 61 53 62 54;
25 17 9 1 26 18 10 2;
57 49 41 33 58 50 42 34]
The link to the document which I am working on is:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.39.5132&rep=rep1&type=pdf
This is what I want to achieve:
Edit: a little more generic solution:
%function Z = bakermap(X,divisors)
function Z = bakermap()
X = reshape(1:64,8,8)'
divisors = [ 2 4 2 ];
[x,y] = size(X);
offsets = sum(divisors)-fliplr(cumsum(fliplr(divisors)));
if any(mod(y,divisors)) && ~(sum(divisors) == y)
disp('invalid divisor vector')
return
end
blocks = #(div) cell2mat( cellfun(#mtimes, repmat({ones(x/div,div)},div,1),...
num2cell(1:div)',...
'UniformOutput',false) );
%create index matrix
I = [];
for ii = 1:numel(divisors);
I = [I, blocks(divisors(ii))+offsets(ii)];
end
%create Baker map
Y = flipud(X);
Z = [];
for jj=1:I(end)
Z = [Z; Y(I==jj)'];
end
Z = flipud(Z);
end
returns:
index matrix:
I =
1 1 3 3 3 3 7 7
1 1 3 3 3 3 7 7
1 1 4 4 4 4 7 7
1 1 4 4 4 4 7 7
2 2 5 5 5 5 8 8
2 2 5 5 5 5 8 8
2 2 6 6 6 6 8 8
2 2 6 6 6 6 8 8
Baker map:
Z =
31 23 15 7 32 24 16 8
63 55 47 39 64 56 48 40
11 3 12 4 13 5 14 6
27 19 28 20 29 21 30 22
43 35 44 36 45 37 46 38
59 51 60 52 61 53 62 54
25 17 9 1 26 18 10 2
57 49 41 33 58 50 42 34
But have a look at the if-condition, it's just possible for these cases. I don't know if that's enough. I also tried something like divisors = [ 1 4 1 2 ] - and it worked. As long as the sum of all divisors is equal the row-length and the modulus as well, there shouldn't be problems.
Explanation:
% definition of anonymous function with input parameter: div: divisor vector
blocks = #(div) cell2mat( ... % converts final result into matrix
cellfun(#mtimes, ... % multiplies the next two inputs A,B
repmat(... % A...
{ones(x/div,div)},... % cell with a matrix of ones in size
of one subblock, e.g. [1,1,1,1;1,1,1,1]
div,1),... % which is replicated div-times according
to actual by cellfun processed divisor
num2cell(1:div)',... % creates a vector [1,2,3,4...] according
to the number of divisors, so so finally
every Block A gets an increasing factor
'UniformOutput',false...% necessary additional property of cellfun
));
Have also a look at this revision to have a simpler insight in what is happening. You requested a generic solution, thats the one above, the one linked was with more manual inputs.