I'm trying to compare two cell arrays that contain both characters and numbers. I would like to compare two specific columns and then return the values in another related column.
For example, I have two cell arrays of the forms:
One= Two=
[A 2 10 [A 1 2 76
B 2 11 B 1 2 78
A 5 22 C 1 2 80
B 5 23 D 1 4 98
A 6 28 E 1 4 99
B 6 28 F 1 4 100
C 6 28] G 1 6 110]
And I want to be able to find everywhere column 2 of 'One' equals column 3 of 'Two' and return the specific value in column 4 of 'Two.' So for this example, I would obtain a result that is:
Three=
[76
78
80
110]
Any help would be appreciated.
Option 1: convert to numeric array first
X = cell2mat(One(:,2:end));
Y = cell2mat(Two(:,2:end));
result = Y(X(:,1)==Y(:,2),3)
Option 2: convert to numeric array at various points
result = cell2mat(Two(cell2mat(One(:,2))==cell2mat(Two(:,3)),4))
Option 3: convert cell to table first
T1 = cell2table(One);
T2 = cell2table(Two);
result = T2.Two4(T1.One2==T2.Two3)
Option 4: abuse how Matlab cell arrays and numeric arrays work
result = [Two{([One{:,2}]==[Two{:,3}])',4}]'
Related
I have 3 datasets in one 40×7 double data set and I want to multiply these and plot the result over a time period. My question is how to do that.
My attempt has been to divide the datasets into 3 individual cells of data and call them A, B and C (each with 40×3) by using the operator a=[{A}] and so on.
Next, I multiplied them with each other by using .*a.*b.*c and with the time t=[0:40] (which is the x-axis).
I get the following error and I don't know what to do.
Index exceeds matrix dimensions
Anyone that can help me?
Code as provided by OP in a comment:
a = ans(:,1:3);
b = ans(:,4:6);
c = ans(:,7:9);
A[{xyz}];
B=[{a}];
C=[{c}];
t=[0:41];
D=(A.*B.*C);
plot(D,t);
One way to do this is to combine reshape and permute, and take the product along the third dimension.
Assume the following is your data. This will be 40x9 in your case.
rows = 4; cols = 6; N = 2;
x = ceil(10*rand(rows,cols))
x =
9 6 1 6 5 8
6 9 9 5 10 6
10 9 7 9 6 3
7 10 10 3 9 7
r = permute(reshape(x, rows, N, []), [3,1,2])
result = prod(r,3).'
result =
54 6 40
54 45 60
90 63 18
70 30 63
So looking at your code, it seems unnecessary to create a cell from it:
you can for example:
ans=rand(40,9);
a = ans(:,1:3); b = ans(:,4:6); c = ans(:,7:9);
D=a.*b.*c;
t=[1:40];
plot(D,t)
or
ans=rand(40,9);
a = ans(:,1:3); b = ans(:,4:6); c = ans(:,7:9);
D=a.*b.*c;
t=[0:39];
plot(D,t)
Your t vector has to have the same length as your inital matrix - your matrix has 40 rows but the vector you create by t=[0:40] is 41 entries long so you either do t=[1:40] or t=[0:39]
and if t is your x-axis you should plot it in the right order so plot(t,D) instead of plot(D,t)
I'm trying to compare two cell arrays that contain both characters and numbers. I would like to compare specific columns and then return the values in another related column.
For example, I have two cell arrays of the forms:
One= Two=
[A X 2 10 [A 1 X 2 76
B Y 2 11 B 1 Y 2 78
A X 5 22 C 1 Z 2 80
B Y 5 23 D 1 X 4 98
A X 6 28 E 1 Y 4 99
B Y 6 28 F 1 Z 4 100
C Z 6 28] G 1 X 6 110
H 1 Y 6 120]
And I want to be able to find everywhere column 2 and 3 of 'One' equals column 3 and 4 of 'Two' and return the specific value in column 5 of 'Two' (and ideally also the value in column 3). In this example, 'One' has an X 2, Y 2, X 6, and Y 6 in common with 'Two' so I would obtain a result that is:
Three=
[X 76
Y 78
X 110
Y 120]
The cell arrays I currently have are also of different sizes. Any help would be appreciated.
You can declare One and Two as cell array
Also Create one empty cell named Third. You can compare and get output as
[m n]=size(One)
Three = {};
for i=1:m
if ((One{i,2} == Two{i,3}) && (One{i,3} == Two{i,4}) )
Three=[Three; {One{i,2},Two{i,5}}];
end
end
How do I sort a column based on the values in another column in MATLAB?
Column A shows position data (it is neither ascending or descending in order) Column B contains another column of position data. Finally column C contains numerical values. Is it possible to link the first position value in B with its numerical value in the first cell of C? Then after this I want to sort B such that it is in the same order as column A with the C values following their B counterparts?The length of my columns would be 1558 values.
Before case;
A B C
1 4 10
4 1 20
3 5 30
5 2 40
2 3 50
After Case;
A B C
1 1 20
4 4 10
3 3 50
5 5 30
2 2 40
Basically A and B became the same and Column C followed B.
Since you don't want things necessarily in ascending or descending order, I don't think any built-in sorting functions like sortrows() will help here. Instead you are matching elements in one column with elements in another column.
Using [~,idx]=ismember(A,B) will tell you where each element of B is in A. You can use that to sort the desired columns.
M=[1 4 10
4 1 20
3 5 30
5 2 40
2 3 50];
A=M(:,1); B=M(:,2); C=M(:,3);
[~,idx]=ismember(A,B);
sorted_matrix = [A B(idx) C(idx)]
Powerful combo of bsxfun and matrix-multiplication solves it and good for code-golfing too! Here's the implementation, assuming M as the input matrix -
[M(:,1) bsxfun(#eq,M(:,1),M(:,2).')*M(:,2:3)]
Sample run -
>> M
M =
1 4 10
4 1 20
3 5 30
5 2 40
2 3 50
>> [M(:,1) bsxfun(#eq,M(:,1),M(:,2).')*M(:,2:3)]
ans =
1 1 20
4 4 10
3 3 50
5 5 30
2 2 40
Given M = [A B C]:
M =
1 4 10
4 1 20
3 5 30
5 2 40
2 3 50
You need to sort the rows of the matrix excluding the first column:
s = sortrows(M(:,2:3));
s =
1 20
2 40
3 50
4 10
5 30
Then use the first column as the indices to reorder the resulting submatrix:
s(M(:,1),:);
ans =
1 20
4 10
3 50
5 30
2 40
This would be used to build the output matrix:
N = [M(:,1) s(M(:,1),:)];
N =
1 1 20
4 4 10
3 3 50
5 5 30
2 2 40
The previous technique will obviously only work if A and B are permutations of the values (1..m). If this is not the case, then we need to find the ranking of each value in the array. Let's start with new values for our arrays:
A B C
1 5 60
6 1 80
9 6 60
-4 9 40
5 -4 30
We construct s as before:
s = sortrows([B C]);
s =
-4 30
1 80
5 60
6 60
9 40
We can generate the rankings one of two ways. If the elements of A (and B) are unique, we can use the third output of unique as in this answer:
[~, ~, r] = unique(A);
r =
2
4
5
1
3
If the values of A are not unique, we can use the second return value of sort, the indices in the original array of the elements in sorted order, to generate the rank of each element:
[~, r] = sort(A);
r =
4
1
5
2
3
[~, r] = sort(r);
r =
2
4
5
1
3
As you can see, the resulting r is the same, it just takes 2 calls to sort rather than 1 to unique. We then use r as the list of indices for s above:
M = [A s(r, :)];
M =
1 1 80
6 6 60
9 9 40
-4 -4 30
5 5 60
If you must retain the order of A then use something like this
matrix = [1 4 10; 4 1 20; 3 5 30; 5 2 40; 2 3 50];
idx = arrayfun(#(x) find(matrix(:,2) == x), matrix(:,1));
sorted = [matrix(:,1), matrix(idx,2:3)];
N.B: This question is more complex than my previous question: Matlab: How I can make this transformation on the matrix A?
I have a matrix A 4x10000, I want to use it to find another matrix C, based on a predefined vector U.
I'll simplify my problem with a simple example:
from a matrix A
20 4 4 74 20 20 4
36 1 1 11 36 36 1
77 1 1 15 77 77 1
3 4 2 6 7 8 15
and
U=[2 3 4 6 7 8 2&4&15 7&8 4|6].
& : AND
| : OR
I want, first, to find an intermediate entity B:
2 3 4 6 7 8 2&4&15 7&8 4|6
[20 36 77] 0 1 0 0 1 1 0 1 0 4
[4 1 1] 1 0 1 0 0 0 1 0 1 4
[74 11 15] 0 0 0 1 0 0 0 0 1 2
we put 1 if the corresponding value of the first line and the vector on the left, made a column in the matrix A.
the last column of the entity B is the sum of 1 of each line.
at the end I want a matrix C, consisting of vectors which are left in the entity B, but only if the sum of 1 is greater than or equal to 3.
for my example:
20 4
C = 36 1
77 1
This was a complex one indeed and because of the many restrictions and labeling processes involved, it won't be as efficient as the solution to the previous problem. Here's the code to solve the posted problem -
find_labels1 = 2:8; %// Labels to be detected - main block
find_labels2 = {[2 4 15],[7 8],[4 6]}; %// ... side block
A1 = A(1:end-1,:); %// all of A except the last row
A2 = A(end,:); %// last row of A
%// Find unique columns and their labels for all of A execpt the last row
[unqmat_notinorder,row_ind,inv_labels] = unique(A1.','rows'); %//'
[tmp_sortedval,ordered_ind] = sort(row_ind);
unqcols = unqmat_notinorder(ordered_ind,:);
[tmp_matches,labels] = ismember(inv_labels,ordered_ind);
%// Assign labels to each group
ctl = numel(unique(labels));
labelgrp = arrayfun(#(x) find(labels==x),1:ctl,'un',0);
%// Work for the main comparisons
matches = bsxfun(#eq,A2,find_labels1'); %//'
maincols = zeros(ctl,numel(find_labels1));
for k = 1:ctl
maincols(k,:) = any(matches(:,labelgrp{k}),2);
end
%// Work for the extra comparisons added that made this problem extra-complex
lens = cellfun('length',find_labels2);
lens(end) = 1;
extcols = nan(ctl,numel(find_labels2));
for k = 1:numel(find_labels2)
idx = find(ismember(A2,find_labels2{k}));
extcols(:,k)=arrayfun(#(n) sum(ismember(labelgrp{n},idx))>=lens(k),1:ctl).'; %//'
end
C = unqcols(sum([maincols extcols],2)>=3,:).' %//'# Finally the output
I will give you a partial answer. I think you can take from here. Idea is to concatenate first 3 rows of A with each element of U replicated as last column. After you get the 3D matrix, replicate your original A and then just compare the rows. The rows which are equal, that is equivalent to putting one in your table.
B=(A(1:3,:).';
B1=repmat(B,[1 1 length(U)]);
C=permute(U,[3 1 2]);
D=repmat(C,[size(B1,1),1,1]);
E=[B1 D];
F=repmat(A',[1 1 size(E,3)]);
Now compare F and E, row-wise. If the rows are equal, then you put 1 in your table. For replicating & and |, you can form some kind of indicator vector.
Say,
indU=[1 2 3 4 5 6 7 7 7 8 8 -9 -9];
Same positive value indicates &, same negative value indicates |. Different value indicate different entries.
I hope you can take from here.
I have matrix F of dimension 5 X 3. For example:
F= [1 12 13;
2 23 24;
3 34 35;
4 45 46;
5 56 57]
and I have a label cell of size 1X1 with entry 'v' i.e.
>> label
label =
'v'
and size of F is given by :
>> [m n]=size(F)
m=
5
n =
3
I want my output to look like:
>> F
F =
1 12 13 v
2 23 24 v
3 34 35 v
4 45 46 v
5 56 57 v
How can I concatenate the cell with the matrix to get this output?
To create an array that contains both numeric and non-numeric data, you need to put everything into a cell array (replace label by {label} in case it isn't a cell array):
Fcell = [ num2cell(F), repmat(label,size(F,1),1)]
You can then access individual numbers/letters using the curly brackets:
Fcell{2,2}
ans =
23
As #Jonas described, converting it to cells is the way to go when you want to access the data for further use.
However, if you are solely interested in seeing the data on the screen and don't like the brackets this is also an option:
Fcell = [num2str(F) repmat([' ' label{1}],size(F,1),1)]
If your label is actually a char it should work like this:
Fcell = [num2str(F) repmat([' ' label],size(F,1),1)]