How can using the existing fields, the value of another field achieved? - matlab

I have a Table as follows:
cl c2 c3 .....
r1 x A 4
r2 y B 5
r3 z C 2
.
.
.
r(1,2,3) are label of rows and c(1,2,3) are label of columns. I have a field of c1,c2 and I want c3. For example I have y and B, so I want achieve to '5';
I read 'Find , sub2ind' Functions but I do not know how can I use them For this case.

You can use simple logical indexing to accomplish this. You want the third column when the value of the first column is 'y' and the value of the second column is 'B'
t = table({'x'; 'y'; 'z'}, {'A'; 'B'; 'C'}, [4; 5; 2], 'VariableNames', {'c1', 'c2', 'c3'});
value = t.c3(ismember(t.c1, 'y') & ismember(t.c2, 'B'))
% 5

Related

Group data in a cell array

I have the following data:
Names={A1 A2 B1 B2 C1 C2 C3}
Doserate=(2.2 3.4 6.4 3.4 2.3 4.5 7.5)
Time=(5 7.8 9 3.5 10.2 5.6 7.8)
The order of Doserate and Time is such they correspond to Names. I would like to make groups starting with the same letter so that I can perform calculations using Doserate and Time corresponding to that group. Names can vary to even more letters (A-Z) or more numbers like (A1-A30).
How can I group these entries?
Names={'A1' 'A2' 'B1' 'B2' 'C1' 'C2' 'C3'};
first_letter = blanks(numel(Names));
for ii = 1:numel(Names)
first_letter(ii) = Names{ii}(1); % Grab the first letter
end
[a, b, c] = unique(first_letter)
a =
ABC
b =
2 4 7
c =
1 1 2 2 3 3 3
You can use a loop to extract the first character in each cell entry (you can probably use cellfun() as well) and then a call to unique() to extract the unique characters. Its third output, named c in my example, will be your groups. Thus Doserate(c(c==2)) will return all Doserate entries where Names start with B.
To extract one or more letters from the start of your names, you can use regex:
Names = {'A1' 'A2' 'B1' 'B2' 'C1' 'C2' 'C3'};
N = regexp( Names, '^[a-zA-Z]+', 'match', 'once' )
% >> N = {'A', 'A', 'B', 'B', 'C', 'C', 'C'};
Then you can use findgroups to group them
[gidx,gnames] = findgroups(N)
gidx =
1 1 2 2 3 3 3
gnames =
{'A', 'B', 'C'}
i.e. now anything where gidx == 2 matches the group 'B' (2nd element in gnames).

Collapsing and averaging redundant entries in MATLAB table

I have the following MATLAB table
item_a item_b score
a b 1
a b 1
b c 3
d e 2
d e 1
d e 0
I want to average the redundant rows. The desired result is as follows:
item_a item_b score
a b (1+1)/2
b c 3
d e (2+1+0)/3
This is a classic scenario for the findgroups, split-apply workflow.
Given your table named t:
% Find mean values.
G = findgroups(t.item_a);
meanValues = splitapply(#mean,t.score,G);
% Create new table.
[~,i] = unique(G);
newTable = t(i,:);
newTable.score = meanValues
newTable contains the desired table.
See this documentation page for more examples.
This is what I got. You can tweak with the final results. There is a similar example on MATLAB documentation. Here are two key functions, accumarray and unique. Note that this solution works only for array inputs not cell data types. By manipulating data types, you can also find the solution for table and cell data types. Otherwise, I think for loop will be necessary.
items = ['a' 'b'
'a' 'b'
'b' 'c'
'd' 'e'
'd' 'e'
'd' 'e' ];
scores = [1 1 3 2 1 0]';
[items_unique,ia,ic] = unique(items,'rows');
score_mean = accumarray(ic,scores, [], #mean);
result = {items_unique score_mean};

How to copy one table column to another respecting row names?

In the following toy example, tables t1 and t2 have shapes (3 x 0) and (3 x 1), respectively. Furthermore, both tables have the same row names.
>> t1 = table('RowNames', {'a', 'b', 'c'});
>> t2 = table([3 ; 2 ; 1], ...
'RowNames', {'c', 'a', 'b'}, 'VariableNames', {'x'});
Then a copy of t2's single column is added to t1 as a new column, with the same variable name.
>> t1.('x') = t2.('x');
The resulting table t1, however, differs from t2 in the association between row names and the values in the x-column:
>> t1({'a', 'b', 'c'}, :)
ans =
x
_
a 3
b 2
c 1
>> t2({'a', 'b', 'c'}, :)
ans =
x
_
a 2
b 1
c 3
What's the simplest way to assign t2.('x') to t1.('x') "respecting rownames"? By this last condition I mean that the final t1 should look just like t2; e.g.:
>> t1({'a', 'b', 'c'}, :)
ans =
x
_
a 2
b 1
c 3
You can index the table using row names so if you extract the list of rownames from t1 you can use that as the ordering for t2:
order = t1.Properties.RowNames % cell array
intermediate = t2(order, :);
or just do it all in one go:
t2(t1.Properties.RowNames, :);
Since t1 doesn't have the x column you can concatenate t1 with column x of t2
>> t1=[t1, t2(:,'x')]
t1 =
x
_
a 2
b 1
c 3
It will automatically take care of matching rows.
OK, this is the OP here.
I found a (potential) answer to my question: instead of
t1.('x') = t2.('x');
use
t1.('x') = t2{t1.Properties.RowNames, 'x'};
I say that this is a "potential" answer because with MATLAB I never know when something that works for a particular type, or under particular circumstances, will generalize. E.g., at this point I don't know if the above will work if column x holds non-numeric values.
If someone knows of a better way, or can point to documentation in support of my lucky guess here, please post it. I'll be glad to accept it as the answer.

Reshape Matlab table

I have the following table
name = ['A' 'A' 'A' 'B' 'B' 'C' 'C' 'C' 'C' 'D' 'D' 'E' 'E' 'E']';
value = randn(14, 1);
T = table(name, value);
i,e.
T =
name value
____ _________
A 0.0015678
A -0.76226
A 0.98404
B -1.0942
B 0.71249
C 1.688
C 1.4001
C -0.9278
C -1.3725
D 0.11563
D 0.076776
E 1.0568
E 1.1972
E 0.29037
I want to transform it in the following way: take the first two cells in value corresponding to different values in name and put it in the 5x2 matrix. This matrix would have rows corresponding to different names A,B,C,D,E and columns corresponding to values, e.g. the first two rows are
0.0015678 -0.76226
-1.0942 0.71249
This can be done with accumarray using a custom function. The first step is to convert the name column of T into a numeric vector; and then accumarray can be applied.
This approach requires T being sorted according to column 1, because only in this case is accumarray guaranteed to preserve order (as indicated in its documentation). So if T may not be sorted (although it is in your example), sort it first using sortrows.
T = sortrows(T, 1); %// you can remove this line if T is guaranteed to be sorted
[~, ~, names] = unique(T(:,1)); %// names as a numeric vector
result = cell2mat(accumarray(names, T.value, [], #(x) {x([1 2]).'}));
First figure out where each name has values located in the table, then cycle through each name and place the first two values encountered for each name into individual cell arrays. Once you're done, reshape the matrix to 5 x 2 as you have said. As such, do something like this:
names = unique(T.name); %// 1
ind = arrayfun(#(x) find(T.name == x), names, 'uni', 0); %// 2
vals = cellfun(#(x) T.value(x(1:2)), ind, 'uni', 0); %// 3
m = [vals{:}].'; %// 4
Let's go through each line of code slowly.
Line #1
The first line finds all unique names through unique and we store them into names.
Line #2
The next line goes through all of the unique names and finds those locations / rows in the table that share that particular name. I use arrayfun and go through each name in names, find those rows that share the same name as one we are looking for, and place those row locations into individual cells; these are stored into ind. To find the locations of each valid name in our table, I use find and the locations are placed into a column vector. As such, we will have five column vectors where each column vector is placed into an individual cell. These column vectors will tell us which rows match a particular name located in your table.
Line #3
The next line uses cellfun to go through each of the cells in ind and extracts the first two row locations that share a particular name, indexes into the value field for your table to pull those two values, and these are placed as two-element vectors into individual cells for each name.
Line #4
The last line of code simply unrolls each two-element vector. The first two elements of each name get stored into columns. To get them into rows, I simply transpose the unrolling. The output matrix is stored into m.
If you want to see what the output looks like, this is what I get when I run the above code with your example table:
m =
0.0016 -0.7623
-1.0942 0.7125
1.6880 1.4001
0.1156 0.0768
1.0568 1.1972
Be advised that I only showed the first 5 digits of precision so there is some round-off at the end. However, this is only for display purposes and so what I got is equivalent to what your expect for the output.
Hope this helps!
If you want use the tables, you could try something like this:
count = 1;
U = unique(table2array(T(:,1)));
for ii = 1:size(U,1)
A = find(table2array(T(:,1)) == U(ii));
A = A(1:2);
B(count,1:2) = table2array(T(A,2));
count = count + 1;
end
Personally, I would find this simpler to do with your name and value arrays and forget about the table. If it is a requirement then I understand, however I will provide my solution still. It may provide some insight either way.
count = 1;
U = unique(name);
for ii = 1:size(U,1)
A = find(name == U(ii));
A = A(1:2);
B(count,1:2) = value(A);
count = count + 1;
end
Quick and dirty, but hopefully it's good enough. Good luck.
Another solution that is more manageable and easily scalable exists. Since MATLAB R2013b you can use a specialized function for pivoting a table (which is what you want to do): unstack.
In order to get exactly what you wanted, you need to add an extra variable to your table that will indicate replications:
name = ['A' 'A' 'A' 'B' 'B' 'C' 'C' 'C' 'C' 'D' 'D' 'E' 'E' 'E']';
value = randn(14, 1);
rep = [1, 2, 3, 1, 2, 1, 2, 3, 4, 1, 2, 1, 2, 3];
T = table(name, value, rep);
T =
name value rep
____ _________ ___
A 0.53767 1
A 1.8339 2
A -2.2588 3
B 0.86217 1
B 0.31877 2
C -1.3077 1
C -0.43359 2
C 0.34262 3
C 3.5784 4
D 2.7694 1
D -1.3499 2
E 3.0349 1
E 0.7254 2
E -0.063055 3
Then you just use unstack like this:
pivotTable = unstack(T, 'value','name')
pivotTable =
rep A B C D E
___ _______ _______ ________ _______ _________
1 0.53767 0.86217 -1.3077 2.7694 3.0349
2 1.8339 0.31877 -0.43359 -1.3499 0.7254
3 -2.2588 NaN 0.34262 NaN -0.063055
4 NaN NaN 3.5784 NaN NaN
Afterwards, it's a matter of re-arranging the table if you still want to.
The easiest way is to first convert the table into a matrix form and then reshape it by using the "reshape" function in Matlab.
matrix = t{:,:};% t-- your table variable
reshape_matrix = reshape(matrix ,[2,3]) % [2,3]--> the size of the matrix you desire
These two steps can be done by one line of code
reshape_matrix = reshape(t{:,:},[2,3]);

bsxfun rows subtraction in loop

I have a text file D with 98 rows and 2 columns. looks like this:
10 0.261344
11 0.456167
12 0.668595
2 0.481754
... etc
I have another excel file M with 17 rows and 2 col.
I want to subtract all rows values from the 1st row, then from 2, etc.so i get something like this:
10-11 -0.194823
10-12 -0.407251
... etc
in other words difference between 1st row and all rest, 2nd row and all rest ..excluding those rows of which 1st column has same values as in 2nd M excel file 1st column. which makes in total difference compare to 81 rows.
i have been trying to use this:
M = xlsread('...');
FSumID=fopen(D);
MatrixSub = loadD);
m = textscan(FSumID,'%d %f');
horzcat(m{:})
NewData = M(:,1)
D_size=size(D);
for i=1:D_size
if (ptvBodyDist(:,1)~=NewData(i))
%for calculating
DVec = bsxfun(#minus, ((m{i,2})), (m{i,2}));
%when i check this it gives only one loop all zeros(98,1)while i need (((98-17)^2,1). I need to change,last part of expression to get what i want but I'm stuck with bsxfun. i dont know how to make correct expression to subtract all rows.
I'm newbie in Matlab any help would be much appreciated. also if you could suggest some manuals or tutorials,apart from mathworks help. Many thanks.
Let D be n by 2 matrix (data from text file).
Let M by m by 2 matrix (data from excel file).
The first stage is to find the relevant n-m rows of D: rows that their first value does not appear in M, using setdiff.
[~, idx] = setdiff( D( :, 1 ), M( :, 1 ), 'stable' );
Now we can compute the all-vs-all diff using bsxfun
d = bsxfun( #minus, permute( D( idx, : ), [1 3 2] ), ...
permute( D( idx, : ), [3 1 2] ) );
Now d is |idx|x|idx|x2 array where
d( ii, jj, : ) = D( idx(ii), :) - D( idx(jj), : )