Create matrices from a given cell-array of strings with different lengths - matlab

I have 3 sequences in a cell-array:
Input_cell= {'ABCD','ACD', 'ABD'}
S1= 'ABCD' % which means A<B<C<D
S2= 'ACD' % which means A<C<D % missing B in the full string of 'ABCD'
S3= 'ABD' % which means A<B<D % missing C in the full string of 'ABCD'
I want to convert each of the strings in the Input_cell into a matrix M (i-by-j) which has to satisfy these conditions:
M(i,j) and M(j,i) are random
M(i,i) = 0.5
M(i,j) + M(j,i) = 1
M(i,j) < M(j,i) For example if A<B then M(A,B) < M(B,A)
For example if we have S1 = 'ABCD' (which means A<B<C<D), the M1 matrix will be expected as follows:
A B C D
A 0.5 0.3 0.2 0.1
B 0.7 0.5 0 0.4
C 0.8 1 0.5 0.1
D 0.9 0.6 0.9 0.5
If we have S2 = 'ACD' (which means A<C<D), missing B in the full string of 'ABCD', we will put the value 0.5 in every position of B in the matrix, the M2 matrix will be expected as follows:
A B C D
A 0.5 0.5 0.2 0.1
B 0.5 0.5 0.5 0.5
C 0.8 0.5 0.5 0.1
D 0.9 0.5 0.9 0.5
If we have S3 = 'ABD' (which means A<B<D), missing C in the full string of 'ABCD', we will put the value 0.5 in every position of C in the matrix, the M3 matrix will be expected as follows:
A B C D
A 0.5 0.4 0.5 0.1
B 0.6 0.5 0.5 0.3
C 0.5 0.5 0.5 0.5
D 0.9 0.7 0.5 0.5
How to create that kind of above matrices from a given cell-array of sequences?

Firstly you need to work out how to do this just for a single sequence:
Create a matrix of random numbers between 0.5 and 1:
M = 0.5*rand(4) + 0.5;
Set the main diagonal to equal 0.5
M(logical(eye(4))) = 0.5;
Set the upper triangle of M equal to 1 - the lower triangle:
M(triu(true(4))) = 1 - M(tril(true(4))); %// Note the main diagonal doesn't matter...
Work out which letter is missing and set the row and column equal to 0.5 accordingly:
fullSeq = 'abcd';
idx = find(fullSeq == setdiff(fullSeq, 'abd'));
%// at this point you'll need to check if idx is empty first...
M(:,idx) = 0.5;
M(idx,:) = 0.5;
And now that you can do it for one matrix, just loop over your cell array or else encapsulate this into a function and use cellfun.

Related

Copy element of matrix to a vector MATLAB

Assume we have a matrix A (2x5), with the first row containing the numbers:
1 2 3 5 7
and the second row:
0.4 0.1 0.2 0.1 0.2
Also, there is a 10 dimensional vector B with numbers 1,2,3...10.
How can I create a new 10 dimensional vector C that will only contain the values of A (second row) when A(1,:) == B, else 0.
So the new vector C should have the form:
0.4 0.1 0.2 0 0.1 0 0.2 0 0 0
(add zero for the cells of B that are not in A).
I tried this solution but I have a problem due to the difference in dimensions between A and B.
for i=1:53
if B(i) == A(1,i)
C{1,i} = A(2,i);
else
C{1,i}=0;
end
end
Index exceeds matrix dimensions.
It's not very clear what you're after, but this at least gives the desired output:
A = [1 2 3 5 7; 0.4 0.1 0.2 0.1 0.2];
B = 1:10;
[tf,loc] = ismember(A(1,:), B);
C = zeros(1,10);
C(loc(tf)) = A(2,tf)
[I'm assuming you mean 10 element vector, rather than 10 dimensional...]
If you just want to use the first row of A as indices and the second row as assigned values, then you don't need to use B at all and you can do something like this:
A = [1 2 3 5 7; 0.4 0.1 0.2 0.1 0.2];
C = zeros(1,10);
C(A(1,:)) = A(2,:)
How about removing the for loop and do it inline using ismember function:
A = [1 2 3 5 7; 0.4 0.1 0.2 0.1 0.2];
B = 1:10;
C = zeros(1,10);
C(B(ismember(B, A(1,:)))) = A(2,ismember(A(1,:),B));
Hint: Even if we happen to have a value in A(1,:) which B does not have, this solution will work.
Using ismember and a for loop:
clc; clear;
A=[
1 2 3 5 7;
0.4 0.1 0.2 0.1 0.2
];
B = 1:10;
C = zeros(1,10);
for j = 1:10
if ismember(j, A(1,:))
C(j) = A(2, A(1,:) == j);
else
C(j) = 0;
end
end
C

Create matrices from a given cell-array of strings with the same lengths [duplicate]

This question already has answers here:
Create matrices from a given cell-array of strings with different lengths
(1 answer)
Create a relation matrix from a sequence (Matlab)
(2 answers)
Closed 7 years ago.
The difference in this case from the previous cases is the length of each string the the Input-cell is the same. One of the previous questions is in different length, another case just transform from one string into a matrix
I have 3 sequences in a cell-array:
Input_cell= {'ABCD','ACDB', 'BCAD'}
S1= 'ABCD' % which means A<B<C<D
S2= 'ACDB' % which means A<C<D<B
S3= 'BCAD' % which means B<C<A<D
I want to convert each of the strings in the Input_cell into a matrix M (i-by-j) which has to satisfy these conditions:
M(i,j) and M(j,i) are random
M(i,i) = 0.5
M(i,j) + M(j,i) = 1
M(i,j) < M(j,i) For example if A<B then M(A,B) < M(B,A)
%For example if we have S1 = 'ABCD' (which means A<B<C<D), the M1 matrix will be expected as follows:
A B C D
A 0.5 0.3 0.2 0.1
B 0.7 0.5 0 0.4
C 0.8 1 0.5 0.1
D 0.9 0.6 0.9 0.5
%If we have S2 = 'ACDB' (which means A<C<D<B), the M2 matrix will be expected as follows:
A B C D
A 0.5 0.3 0.2 0.1
B 0.7 0.5 0.6 0.8
C 0.8 0.4 0.5 0.1
D 0.9 0.2 0.9 0.5
% If we have S3 = 'BCAD' (which means B<C<A<D), the M3 matrix will be expected as follows:
A B C D
A 0.5 0.6 0.7 0.1
B 0.4 0.5 0.2 0.3
C 0.3 0.8 0.5 0.1
D 0.9 0.7 0.9 0.5
How to create that kind of above matrices from a given cell-array of sequences?
I would do the following, even if it doesn't seem really optimized :
1) Fill your output matrix as if the order was the natural one (i.e. 'ABCD').
2) Apply a permutation to your matrix so that it satisfies your condition.
Codewise :
1)
Generate an upper diagonal matrix with 0.5 on the diagonal and sorted random generated values in [0,0.5] above the diagonal, for example :
A=diag([0.5 0.5 0.5 0.5])+sort(triu(0.5*rand(4),1),2);
Example of output :
A =
0.500000000000000 0.084125649245764 0.108781654711410 0.277868971359693
0 0.500000000000000 0.092216833878827 0.125520923007868
0 0 0.500000000000000 0.106015421266160
0 0 0 0.500000000000000
Fill the values of lower traingular block to match your constraint M(i,j)+M(j,i)=1 :
A=A+tril(1-transpose(A),-1);
output :
A =
0.500000000000000 0.084125649245764 0.108781654711410 0.277868971359693
0.915874350754236 0.500000000000000 0.092216833878827 0.125520923007868
0.891218345288590 0.907783166121173 0.500000000000000 0.106015421266160
0.722131028640307 0.874479076992132 0.893984578733840 0.500000000000000
2) Apply a permutation corresponding to the ordering of your input sequence.
NOTE : Characters are ordered alphabetically due to the way ASCII code is defined (see for example the outputs of 'A'<'B', or 'H'>'Z');
With that in mind, one can sort your input sequence in order to get the order it was in with the second output of MATLAB's sort function.
[Tmp,order]=sort(input);
Now one just has to calculate the input matrix you want :
A=A(order,order);
output, case input='ACDB' :
A =
0.500000000000000 0.277868971359693 0.084125649245764 0.108781654711410
0.722131028640307 0.500000000000000 0.874479076992132 0.893984578733840
0.915874350754236 0.125520923007868 0.500000000000000 0.092216833878827
0.891218345288590 0.106015421266160 0.907783166121173 0.500000000000000
output, case input='BCAD' :
A =
0.500000000000000 0.891218345288590 0.907783166121173 0.106015421266160
0.108781654711410 0.500000000000000 0.084125649245764 0.277868971359693
0.092216833878827 0.915874350754236 0.500000000000000 0.125520923007868
0.893984578733840 0.722131028640307 0.874479076992132 0.500000000000000

Calling text file

if i have text file that has three column say
1 2 1
3 1 1
2 3 1
and also have a matrix s =
[0.3 0.4 0.6
0.1 0.5 0.7
0.2 0.11 0.9]
firstly:
with respect to text file, i want to consider first column as i and second column as j then if the third column equal 1 then put its corresponding value in matrix s in new array say A else put remaining value in matrix s in new another array say B.
i.e i want this result
A=[0.4, 0.2, 0.7] B=[0.3, 0.6, 0.1, 0.5, 0.11, 0.9]
coordinates = [1 2 1
3 1 1
2 3 1];
s = [0.3 0.4 0.6
0.1 0.5 0.7
0.2 0.11 0.9];
linindices = sub2ind(size(s), coordinates(:, 1), coordinates(:, 2))';
A = s(linindices)
B = s(setdiff(1:numel(s), linindices))

Brute force in Matlab

this is my problem, for example i have an equation x + y =2, so using matlab i want to know how to determine all the possible combination of values of x and y when you add it, and will give sum of 2 (ex: x1 = 0.98, y1 =0.12; x2=0.94 y2=0.16, and etc)
i think i need to use for loop?
for x = 2-y
end
for y =2-x
end
Values of x and y
x y
0 2
0.1 1.9
0.2 1.8
0.3 1.7
0.4 1.6
0.5 1.5
0.6 1.4
0.7 1.3
0.8 1.2
0.9 1.1
1 1
so guys i need your help thanks
To get all possible combinations of x and y between 0 and 2 with a step size of 0.1 you don't even need a for loop. You can create a vector x which contains all possible x values and then calculate the corresponding y's:
x = 0:0.1:2; % Create a vector of values between 0 and 2 in steps 0f 0.1
y = 2 - x;
This will give you two (row) vectors containing all possible combinations which add up to 2.

changing multiple columns of a matrix with respect to sorted indices of its specific columns

Let's say I have a 2 by 9 matrix. I want to replace the 2 by 3 matrices inside this matrix with respect to descending sort of a(2,3), a(2,6), and a(2,9) elements. For example:
a =
0.4 0.4 0.5 0.6 0.2 0.2 0.6 0.2 0.6
0.5 0.8 0.9 0.9 0.6 0.6 0.1 0.2 0.8
[b i] = sort(a(2,3:3:end),2,'descend')
b =
0.9 0.8 0.6
i =
1 3 2
So, I want to have the following matrix:
a =
0.4 0.4 0.5 0.6 0.2 0.6 0.6 0.2 0.6
0.5 0.8 0.9 0.1 0.2 0.8 0.9 0.6 0.6
Try converting to a cell matrix first and then using your i to rearrange the cells
[b i] = sort(a(2,3:3:end),2,'descend')
A = mat2cell(a, 2, 3*ones(1,3));
cell2mat(A(i))
If for whatever reason you don't want to convert the whole of a into a cell matrix, you can do it by extending your indexing vector i to index all the columns. In your case you'd need:
I = [1,2,3,7,8,9,4,5,6]
which you could generate using a loop or else use bsxfun to get
[1 7 4
2 8 5
3 9 6]
and then "flatten" using reshape:
I = reshape(bsxfun(#plus, 3*s-2, (0:2)'), 1, [])
and then finally
a(:,I)
Typically, when a 2d matrix is separated into blocks, best practice ist to use more dimensions:
a=reshape(a,size(a,1),3,[]);
Now you can access each block via a(:,:,1)
To sort use:
[~,idx]=sort(a(2,3,:),'descend')
a=a(:,:,idx)
If you really need a 2d matrix, change back:
a=reshape(a,2,[])
sortrows-based approach:
n = 3; %// number of columns per block
m = size(a,1);
a = reshape(sortrows(reshape(a, m*n, []).', -m*n).', m, []);
This works by reshaping each block into a row, sorting rows according to last column, and reshaping back.