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

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.

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 select the average value from 3 matrices

I am new to MATLAB and I need help. I have 3 matrices (A, B, and C) and I want to create a new matrix average_ABC that contains average values.
A = [ 0.3 0.5 0.9
0.14 0.36 0.1
0.9 0.5 0.14]
B = [ 0.8 0.9 0.14
0.1 0.25 0.4
0.8 0.14 0.25]
C = [0.25 0.3 0.47
0.12 0.3 0.2
0.14 0.56 0.9]
The resulting matrix will be
average_matrix = [ 0.3 0.5 0.47
0.12 0.25 0.2
0.8 0.5 0.25]
Please, any suggestion, how can I do it?
You can first concatenate your matrices along the third dimension (using cat) and then compute whatever you want using the dim parameter that is available for most functions to specify that you want to perform that operation along the third dimension.
Also you've stated that you want the average (mean), but based on your example you actually want the median. Either way, we can compute them using this method.
data = cat(3, A, B, C);
% Compute the mean
mean(data, 3)
% 0.45 0.56667 0.50333
% 0.12 0.30333 0.23333
% 0.61333 0.4 0.43
% Compute the median (which seems to be what you actually want)
median(data, 3)
% 0.3 0.5 0.47
% 0.12 0.3 0.2
% 0.8 0.5 0.25
I hope this will work
average_matrix=(A+B+C)/3.;

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.

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))

reshape matrix in matlab

I don't see the bug anymore...maybe (very probably :-) ) there's even a much more easier and faster way of doing it...
I summarized the important columns of my huge data frame in a little expData (see below).
The problem is actually quite easy, but I'm just blind for the easy idea of solving it..
My objective is to reshape columns b,c,d into one column that expData afterwards looks like expData2.
I would be really happy, if someone could help me out.
My code so far:
a = [1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5]';
b = [0.3 0.3 0.3 0.3 0.3 0.4 0.4 0.4 0.4 0.4 0.5 0.5 0.5 0.5 0.5 0.8 0.8 0.8 0.8 0.8 0.9 0.9 0.9 0.9 0.9]';
c = [0.4 0.4 0.4 0.4 0.4 0.6 0.6 0.6 0.6 0.6 0.8 0.8 0.8 0.8 0.8 0.9 0.9 0.9 0.9 0.9 0.1 0.1 0.1 0.1 0.1]';
d = [0.5 0.5 0.5 0.5 0.5 0.1 0.1 0.1 0.1 0.1 0.7 0.7 0.7 0.7 0.7 0.2 0.2 0.2 0.2 0.2 0.3 0.3 0.3 0.3 0.3]';
e = rand(25,1);
f = rand(25,1);
a2 = [2 3 4 2 3 4 2 3 4 2 3 4 2 3 4]';
b2 = [0.3 0.4 0.5 0.4 0.6 0.1 0.5 0.8 0.7 0.8 0.9 0.2 0.9 0.1 0.3]';
c2 = rand(15,1);
d2 = rand(15,1);
expData = horzcat(a,b,c,d,e,f);
expData2 = horzcat(a2,b2,c2,d2); % for explanation of my objective
k = horzcat(expData(:,2),expData(:,3),expData(:,4))'; % How I wanted to do it
expData(:,2:4) = [];
k = reshape(k,[],1);
for index = 1:size(expData,1)
if expData(index,1) == 1
expData(index,:) = [];
end
if expData(index,1) == 5
expData(index,:) = [];
end
end
k = k(1:size(expData,1),:);
expData2 = [expData k];
Your current code throws an error, since the number of loop iterations gets determined at the beginning of the loop. As you are removing rows of expData, you run out of rows to index at some point.
The quick fix would be to start looping from the back, i.e. use for index = size(expData,1):-1:1. This way, you can safely remove rows without running into indexing problems.
The elegant fix is to use ismember to identify rows to remove:
rows2remove = ismember(expData(:,1),[1 5]);
expDate(rows2remove,:) = [];