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

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

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

How to find value from matrix

Let say I have a matrix
A=[0.8 0.9 0.7 0.5 0.3 0.8 0.2 0.1]; % 8 points
where A come from logical 1 from B
B=[1 0 1 0 0 1 0 1 0 1 1 0 1 1];
As I want to find location C that satisfies
C=find(A<0.6 & A>0.35)
where the ans is C=4. My question is how to get the true location in B=8?
Unless you do not have the indices stored away somewhere, I cannot see that you have much of a choice here.
tmp = find(B);
idx = tmp(C);
In case you actually want to use this mapping more than once, I would suggest that you store the indices instead of a binary vector. This will also be more memory efficient in case the binary vector is sparse (or not a boolean vector), since you will need less entries.
In case you also need the binary vector, you should store both in case memory allows. When I have done this kind of mapping in Matlab I have actually used both a binary vector (a mask) and an index vector. This have saved me from first mapping the mask to index and then index to filtered position (so to say, skipping the tmp = find(B); idx = tmp(C); part every time and go directly to idx = allIdx(C)).
This will get you the index in B
A=[0.8 0.9 0.7 0.5 0.3 0.8 0.2 0.1];
B=[1 0 1 0 0 1 0 1 0 1 1 0 1 1];
C=find(A<0.6 & A>0.35);
temp=0;
for i=1:size(B,2)
temp=temp+B(i);
if(temp==C)
break;
end
end
locationB=i;
locationB

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

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.

How to count non zero elements in a vector and replace this values based the number of occurences [duplicate]

This question already has answers here:
Finding islands of zeros in a sequence
(6 answers)
Closed 7 years ago.
I'm a new matlab user and in my case i have a vector let say:
v = [0 0 0 0.1 0.2 0.3 0.4 0.5 0 0 0 0 0 0 0.1 0.2]
I want to count consecutive non zero values i.e in my vector have first five nonzero values [0.1 0.2 0.3 0.4 0.5] and two last nozeros values [0.1 0.2]
what I want is:
count the consecutive non zero values and put a condition i.e. if the length of nonzeros is greater then 3 (count>3) then the respective values of vector V(i) remain v(i) if the length consecutive values is less than three (count<3) then respective values of v(i) = 0
I want to get a new vector let say v1 derivated from vector v where:
v1 = [0 0 0 0.1 0.2 0.3 0.4 0.5 0 0 0 0 0 0 0 0]
Any help would be appreciated.
If you have the MATLAB Image Processing Toolbox, you can use the power of morphological operations. The morphological opening (imopen) removes objects which are smaller than the structuring element from an image. We can use this in 2D and use [1,1,1] as structuring element to remove objects, i.e. sequences of nonzero elements, which are shorter than 3:
First we make the sequence binary: zero or nonzero.
w = v~=0;
Then we zero-pad the sequence, so short nonzero sequences at the borders get eliminated. As we use [1,1,1] as structuring element, zero-padding by 1 is sufficient:
w = [0,w,0];
Now we do the opening to remove all small nonzero sequences
w1 = imopen(w, [1,1,1]);
The vector w1 now contains 0 if the corresponding element in v is or should be set to 0 and 1 if the value should be kept. To get the result v1, we can ignore the first and last entry (those are the elements from the zero-padding), and multiply that by the input, as e.g. 1 * 0.1 = 0.1:
v1 = w1(2:end-1) .* v;
Which gives the correct result without any for loop, if statement or such stuff! Only 4 simple operations: morphology and a bit of multiplication and zero-padding.
buffer=0 %Buffer to remember non zero values
v=[0 0 0 0.1 0.2 0.3 0.4 0.5 0 0 0 0 0 0 0.1 0.2];
v1=[];
for i=1:length(v)
if v(i)~=0
buffer=buffer+1;
v1(i)=v(i);
end
if v(i)==0
switch buffer
case 1 % case 1 corresponds to only 1 non zero value in a single sequence
v1(i-1)=0;
buffer=0;
case 2 % case 2 corresponds to only 2 non zero value in a single sequence
v1(i-1)=0;
v1(i-2)=0;
buffer=0;
otherwise
buffer=0;
end
end
end
switch buffer % Test for the last two values
case 1
v1(length(v))=0;
case 2
v1(length(v))=0;
v1(length(v)-1)=0;
end
This should do the trick.

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.