I have a 3d matrix in matlab and I need to extract each row to create new matricies - matlab

I have a 3d matrix in the following form,
AA = [1,1;2,2];
BB = [1,1;2,2];
CC = [1,1;2,2];
ZZ = cat(3,AA,BB,CC)
NEW_CODE = [1 1; 1 1; 1 1; 2 2; 2 2; 2 2;]
Basically the code that I have creates a matrix in the form NEW_CODE, I need to transfer this back to ZZ.
To be clear, from
NEW_CODE =
1 1
1 1
1 1
2 2
2 2
2 2
To,
ZZ(:,:,1) =
1 1
2 2
ZZ(:,:,2) =
1 1
2 2
ZZ(:,:,3) =
1 1
2 2
I have tried this with no success,
attempt=NEW_CODE(:,1:3+1:end);

You could use reshape to split the top and bottom "halves" of the NEW_DATA matrix, then shiftdim to rearrange the result as desired
ZZ2 = shiftdim( reshape( NEW_CODE, [], 2, 2 ), 1 );
You can check this is correct using isequal(ZZ,ZZ2), which returns true.

I don't have a copy of Matlab to play with right now, so you're going to need to double check this
permute( reshape( NEW_CODE' , 2 , 3 , 2 ) , [ 1 3 2 ] )

Related

How to create all permutations of a 2-column cell-array?

I created a cell array of shape m x 2, each element of which is a matrix of shape d x d.
For example like this:
A = cell(8, 2);
for row = 1:8
for col = 1:2
A{row, col} = rand(3, 3);
end
end
More generally, I can represent A as follows:
where each A_{ij} is a matrix.
Now, I need to randomly pick a matrix from each row of A, because A has m rows in total, so eventually I will pick out m matrices, which we call a combination.
Obviously, since there are only two picks for each row, there are a total of 2^m possible combinations.
My question is, how to get these 2^m combinations quickly?
It can be seen that the above problem is actually finding the Cartesian product of the following sets:
2^m is actually a binary number, so we can use those to create linear indices. You'll get an array containing 1s and 0s, something like [1 1 0 0 1 0 1 0 1], which we can treat as column "indices", using a 0 to indicate the first column and a 1 to indicate the second.
m = size(A, 1);
% Build all binary numbers and create a logical matrix
bin_idx = dec2bin(0:(2^m -1)) == '1';
row = 3; % Loop here over size(bin_idx,1) for all possible permutations
linear_idx = [find(~bin_idx(row,:)) find(bin_idx(row,:))+m];
A{linear_idx} % the combination as specified by the permutation in out(row)
On my R2007b version this runs virtually instant for m = 20.
NB: this will take m * 2^m bytes of memory to store bin_idx. Where that's just 20 MB for m = 20, that's already 30 GB for m = 30, i.e. you'll be running out of memory fairly quickly, and that's for just storing permutations as booleans! If m is large in your case, you can't store all of your possibilities anyway, so I'd just select a random one:
bin_idx = rand(m, 1); % Generate m random numbers
bin_idx(bin_idx > 0.5) = 1; % Set half to 1
bin_idx(bin_idx < 0.5) = 0; % and half to 0
Old, slow answer for large m
perms()1 gives you all possible permutations of a given set. However, it does not take duplicate entries into account, so you'll need to call unique() to get the unique rows.
unique(perms([1,1,2,2]), 'rows')
ans =
1 1 2 2
1 2 1 2
1 2 2 1
2 1 1 2
2 1 2 1
2 2 1 1
The only thing left now is to somehow do this over all possible amounts of 1s and 2s. I suggest using a simple loop:
m = 5;
out = [];
for ii = 1:m
my_tmp = ones(m,1);
my_tmp(ii:end) = 2;
out = [out; unique(perms(my_tmp),'rows')];
end
out = [out; ones(1,m)]; % Tack on the missing all-ones row
out =
2 2 2 2 2
1 2 2 2 2
2 1 2 2 2
2 2 1 2 2
2 2 2 1 2
2 2 2 2 1
1 1 2 2 2
1 2 1 2 2
1 2 2 1 2
1 2 2 2 1
2 1 1 2 2
2 1 2 1 2
2 1 2 2 1
2 2 1 1 2
2 2 1 2 1
2 2 2 1 1
1 1 1 2 2
1 1 2 1 2
1 1 2 2 1
1 2 1 1 2
1 2 1 2 1
1 2 2 1 1
2 1 1 1 2
2 1 1 2 1
2 1 2 1 1
2 2 1 1 1
1 1 1 1 2
1 1 1 2 1
1 1 2 1 1
1 2 1 1 1
2 1 1 1 1
1 1 1 1 1
NB: I've not initialised out, which will be slow especially for large m. Of course out = zeros(2^m, m) will be its final size, but you'll need to juggle the indices within the for loop to account for the changing sizes of the unique permutations.
You can create linear indices from out using find()
linear_idx = [find(out(row,:)==1);find(out(row,:)==2)+size(A,1)];
A{linear_idx} % the combination as specified by the permutation in out(row)
Linear indices are row-major in MATLAB, thus whenever you need the matrix in column 1, simply use its row number and whenever you need the second column, use the row number + size(A,1), i.e. the total number of rows.
Combining everything together:
A = cell(8, 2);
for row = 1:8
for col = 1:2
A{row, col} = rand(3, 3);
end
end
m = size(A,1);
out = [];
for ii = 1:m
my_tmp = ones(m,1);
my_tmp(ii:end) = 2;
out = [out; unique(perms(my_tmp),'rows')];
end
out = [out; ones(1,m)];
row = 3; % Loop here over size(out,1) for all possible permutations
linear_idx = [find(out(row,:)==1).';find(out(row,:)==2).'+m];
A{linear_idx} % the combination as specified by the permutation in out(row)
1 There's a note in the documentation:
perms(v) is practical when length(v) is less than about 10.

value in new column if two values if two columns match two others Matlab

So i have two very long matrices. A sample is given below:
First_Matrix:
A = [...
1 1 1;
1 1 2;
1 1 3;
1 2 1;
1 2 2;
1 2 3;
1 3 1;
1 3 2;
1 3 3];
Second Matrix
B = [...
1 1 916;
1 2 653;
1 3 114];
And I would like a thirds matrix that would combine the first matrix with the third column of the second matrix, based on the values in the first two column of the 2 matrices matching (being the same).
So Ouput_Matrix:
C = [...
1 1 1 916;
1 1 2 916;
1 1 3 916;
1 2 1 653;
1 2 2 653;
1 2 3 653;
1 3 1 114;
1 3 2 114;
1 3 3 11];
What would be the best way to do this?
Thanks in advance
Use the second output of ismember with the 'rows' option to get the indices of the matching, from which you can easily build the result:
[~, ind] = ismember(A(:, [1 2]), B(:, [1 2]), 'rows');
C = [A B(ind, 3)];
The for loop isn't pretty and might slow you down if B is very long. But I don't think it's possible to avoid (edit: it seems it is).
A = [1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
1 3 1
1 3 2
1 3 3];
B = [1 1 916
1 2 653
1 3 114];
C = [A zeros(size(A,1),1)];
for i = 1:size(B,1)
C(all(B(i,1:2)==A(:,1:2),2),4) = B(i,3);
end
C =
1 1 1 916
1 1 2 916
1 1 3 916
1 2 1 653
1 2 2 653
1 2 3 653
1 3 1 114
1 3 2 114
1 3 3 114
It is possible to achieve what you want without a for loop, but it may not be the most optimal implementation:
n = size(B, 1); % number of rows in B
B_(1, :, :) = B'; % convert to 3D matrix to be able to use elementwise comparision
x = squeeze(all(bsxfun(#eq, A(:, 1:2), B_(1, 1:2,:)), 2)); % x(i, j) == 1 if row A(i, :) matches B(j, :)
index = x * (1:n)'; % row B(index(i), :) corresponds with row A(i, :)
A(:, 4) = B(index, 3); % add data to A
An alternative formulation for x, without conversion to 3D, is:
x = bsxfun(#eq, A(:, 1), B(:,1)') & bsxfun(#eq, A(:, 2), B(:,2)');
The disadvantage of this method is that it less extendable to more matching columns.

How to efficiently sample a matrix in matlab, given a list of coordinates with repeatitions

I have a list of coordinates to a matrix, and I want to sample the matrix elements from it. The list of coordinates is with repetitions and actually is larger than the number of elements in the matrix.
e.g.
A = magic(3)
coords = [1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3];
I want to get back a vector of values (pseudo code): sample_from_matrix(A, coords);
You can try it that way:
A( sub2ind( size(A), coords(:,1), coords(:,2) ) )
If you want to remove coordinate duplicates first:
coords = unique( coords, 'rows' );
A( sub2ind( size(A), coords(:,1), coords(:,2) ) )

Create a multidimensional array following a pattern

I am making a 3 dimensional array, using matlab, that progresses according to a pattern. Athough I could write out the Array manually I am sure there is a quicker way to do it.
multiArray = cat(3,...
[1+randn(4,3); 1*randn(4,3)],...
[2+randn(4,3); 2*randn(4,3)],...
[3+randn(4,3); 3*randn(4,3)]);
If I want to make the above array to be 8x3x25 then the last line would be
[25+randn(4,3); 25*randn(4,3)]
But how can I make such an array without going through all the tedious intervening steps?
While mikkola basically got the solution, there is no need to shift dimensions at the end.
s=[4,3,25];
it=reshape(1:s(3),1,1,[]);
out = [bsxfun(#plus , it, randn(s));...
bsxfun(#times, it, randn(s))];
Here's a possible way using bsxfun.
%// 25 x 4 x 3 with elements for i + randn(4,3)
P = bsxfun(#plus, (1:25)', randn(25,4,3));
%// 25 x 4 x 3 with elements for i * randn(4,3)
T = bsxfun(#times, (1:25)', randn(25,4,3));
%// Concatenate and shift dimensions to get desired size output
multiArray = shiftdim([P T], 1);
If you don't mind taking things to 4D for efficiency purposes -
N = 25; %// Number of 3D slices
out = randn(4,2,3,N);
out(:,1,:,:) = bsxfun(#plus,permute(1:N,[1 4 3 2]),out(:,1,:,:));
out(:,2,:,:) = bsxfun(#times,permute(1:N,[1 4 3 2]),out(:,2,:,:));
out = reshape(out,8,3,N);
To legitimize the solution, let's start off with an input of A = randn(8,3,N) and initialize the output out with it. Also, let's take number of 3D slices as a small number, so say N = 3.
Thus,
>> N = 3;
A = randn(8,3,N);
out = reshape(A,[4 2 3 N]); %// This replaces "out = randn(4,2,3,N)"
Next up, we run the code that will change out -
>> out(:,1,:,:) = bsxfun(#plus,permute(1:N,[1 4 3 2]),out(:,1,:,:));
out(:,2,:,:) = bsxfun(#times,permute(1:N,[1 4 3 2]),out(:,2,:,:));
out = reshape(out,8,3,N);
Now, start validating per 3D slice -
>> out(1:4,:,1) - A(1:4,:,1)
ans =
1 1 1
1 1 1
1 1 1
1 1 1
>> out(1:4,:,2) - A(1:4,:,2)
ans =
2 2 2
2 2 2
2 2 2
2 2 2
>> out(1:4,:,3) - A(1:4,:,3)
ans =
3 3 3
3 3 3
3 3 3
3 3 3
>> out(5:end,:,1)./A(5:end,:,1)
ans =
1 1 1
1 1 1
1 1 1
1 1 1
>> out(5:end,:,2)./A(5:end,:,2)
ans =
2 2 2
2 2 2
2 2 2
2 2 2
>> out(5:end,:,3)./A(5:end,:,3)
ans =
3 3 3
3 3 3
3 3 3
3 3 3

matlab replace number

in a column, value 2 replace with 1 and value 1 & 3 replace with 2. The code i wrote below got problem:
S=[1 1 1 2 2 3 3 3 3];
S(S==2)=1; S(S==1)=2; S(S==3)=2;
result:
S=[2 2 2 2 2 2 2 2 2]
However, the result i wan to get is S=[2 2 2 1 1 2 2 2 2]. does anyone can help?
That is happening because when in the S(S==1)=2; step, you are affected by the modifications from the S(S==2)=1; step. Try this
S = [1 1 1 2 2 3 3 3 3];
S_copy = S;
S(S_copy == 2) = 1; S(S_copy == 1) = 2; S(S_copy == 3) = 2;
or you could also save the results of the tests into separate variables:
S = [1 1 1 2 2 3 3 3 3];
f1 = (S == 2);
f2 = (S == 1);
f3 = (S == 3);
S(f1) = 1; S(f2) = 2; S(f3) = 2;
Instead of manually replacing each value, you can use an extra matrix to define a "map" from input values in S to output values.
>> S = [1 1 1 2 2 3 3 3 3]; % input
>> M = [2 1 2]; % M[i] = j -> map value i to j
>> S = M(S) % compute output
S =
2 2 2 1 1 2 2 2 2
This operation should be really fast in Matlab.
Note that this methods works as long as the values in S can be interpreted as index values (that is, they are integers and not too large).
your are getting closer but the problem arises once you change all the 2's to one.
after this statement
S(S==2)=1;
the array looks like this
S=[1 1 1 1 1 3 3 3 3];
and after the other two statements S(S==1)=2; S(S==3)=2;
your array will obviously have all 2's.
Instead of
S(S==2)=1; S(S==1)=2; S(S==3)=2;
you can do like this:
S(S==2)=-1; S(S==1)=2; S(S==3)=2;S(S==-1)=1;
i.e. in the first step change all the 2's to some other value(e.g. -1 here) and then do the required conversion i.e. S(S==-1)=1;