Matlab vactor table to normal table extraction - matlab

I have a table name output which contains the dimention like this:
cat values s1 s2 sub_cat
1 [1x2 double] 0.66584 3.1383 {2x1 cell}
values are such as:
cat values s1 s2 sub_cat
1 2.5 3.4 0.555 3.999 emozi-1
emozi-3
2 2.9 7.1 5.0 2 khazal-11
kha-9
How can i re-arrange this table like this(remove vector to normal):
cat values s1 s2 sub-cat
1 2.5 0.555 3.999 emozi-1
1 3.4 0.555 3.999 emozi-3
2 2.9 5.0 2 khazal-11
2 7.1 5.0 2 kha-9
Can anyone help to do this in matlab?

I think what you're after is a table stack operation. It's a bit tricky because I think you're trying to stack two table variables simultaneously (without getting all the combinations), so here's what I think you need:
%# Sample table data
t = table([1;2], [1, 2; 3, 4], [0.1; 0.2], {'a', 'b'; 'c', 'd'}, ...
'VariableNames', {'cat', 'values', 's1', 'sub_cat'});
%# Combine corresponding columns of 'values' and 'sub_cat' so
%# that we've got something we can stack
t2 = table(t.cat, [num2cell(t.values(:,1)), t.sub_cat(:,1)], ...
[num2cell(t.values(:,2)), t.sub_cat(:,2)], ...
t.s1, 'VariableNames', {'cat', 'vs1', 'vs2', 's1'});
%# Actually call 'stack'
t3 = stack(t2, {'vs1', 'vs2'});
%# Unpick the variables in 't3' into something more useful
t4 = table(t3.cat, t3.s1, cell2mat(t3.vs1_vs2(:,1)), ...
t3.vs1_vs2(:,2), 'VariableNames', ...
{'cat', 's1', 'values', 'sub_cat'})

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

Merging elements of different cells

Suppose, we have a cell array consisting of ids and one attribute, e.g.
A{1,1}=[1 2;2 4]
A{1,2}=[2 3 5;8 5 6]
Now, I'd like to have a final output consisting of unique ids of two cells (first row values) and corresponding columns have attribute value of each cell separately.
i.e.
C =
[1] [ 2]
[2] [1x2 double] % 4 in first cell and 8 in second cell
[3] [ 5]
[5] [ 6]
it seems that it's not possible to use something like C=[unique(A{1,:}(1,:)')]. Any help is greatly appreciated.
Assuming that each cell has two rows and a variable amount of columns where the first row is the ID and the second row is an attribute, I'd consolidate all of the cells into a single 2D matrix and use accumarray. accumarray is very suitable here because you want to group values that belong to the same ID together and apply a function to it. In our case, our function will simply place the values in a cell array and we'll make sure that the values are sorted because the values that are grouped by accumarray per ID come into the function in random order.
Use cell2mat to convert the cells into a 2D matrix, transpose it so that it's compatible for accumarray, and use it. One thing I'll need to note is that should any IDs be missing, accumarray will make this slot empty. What I meant by missing is that in your example, the ID 4 is missing as there is a gap between 3 and 5 and also the ID 6 between 5 and 7 (I added the example in your comment to me). Because the largest ID in your data is 7, accumarray works by assigning outputs from ID 1 up to ID 7 in increments of 1. The last thing we would need to tackle is to eliminate any empty cells from the output of accumarray to complete the grouping.
BTW, I'm going to assume that your cell array consists of a single row of cells like your example.... so:
%// Setup
A{1,1}=[1 2;2 4];
A{1,2}=[2 3 5;8 5 6];
A{1,3}=[7;8];
%// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray
B = cell2mat(A).';
%// Group IDs together and ensure they're sorted
out = accumarray(B(:,1), B(:,2), [], #(x) {sort(x)});
%// Add a column of IDs and concatenate with the previous output
IDs = num2cell((1:numel(out)).');
out = [IDs out];
%// Any cells from the grouping that are empty, eliminate
ind = cellfun(#isempty, out(:,2));
out(ind,:) = [];
We get:
out =
[1] [ 2]
[2] [2x1 double]
[3] [ 5]
[5] [ 6]
[7] [ 8]
>> celldisp(out(2,:))
ans{1} =
2
ans{2} =
4
8
If you'd like this done on a 2D cell array, where each row of this cell array represents a separate instance of the same problem, one suggestion I have is to perhaps loop over each row. Something like this, given your example in the comments:
%// Setup
A{1,1}=[1 2;2 4];
A{1,2}=[2 3 5;8 5 6];
A{1,3}=[7;8];
A{2,1}=[1 2;2 4];
A{2,2}=[1;7];
%// Make a cell array that will contain the output per row
out = cell(size(A,1),1);
for idx = 1 : size(A,1)
%// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray
B = cell2mat(A(idx,:)).';
%// Group IDs together and ensure they're sorted
out{idx} = accumarray(B(:,1), B(:,2), [], #(x) {sort(x)});
%// Add a column of IDs and concatenate with the previous output
IDs = num2cell((1:numel(out{idx})).');
out{idx} = [IDs out{idx}];
%// Any cells from the grouping that are empty, eliminate
ind = cellfun(#isempty, out{idx}(:,2));
out{idx}(ind,:) = [];
end
We get:
>> out{1}
ans =
[1] [ 2]
[2] [2x1 double]
[3] [ 5]
[5] [ 6]
[7] [ 8]
>> out{2}
ans =
[1] [2x1 double]
[2] [ 4]
>> celldisp(out{1}(2,:))
ans{1} =
2
ans{2} =
4
8
>> celldisp(out{2}(1,:))
ans{1} =
1
ans{2} =
2
7

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.

How can I group variables from a mat file by name and collect them in a structure?

I'm reading in a mat file which has variables with a counter e.g. a1, a2, a3, b, c1 and c2.
I want to put the data into a structure with field names "a", "b" and "c" where
a=[a1;a2;a3], b=b and c = [c1; c2].
The algorithm needs to be able to do this, without knowing what the maximum value of the counter of each variable is. How can I do this?
First, you would load your mat file data using the load function, placing it in a structure. Let's say that gave you the following sample data:
>> s = struct('a1',1:5,'b',[],'a2',1:5,'a3',1:5,'c1',1:3,'c2',3:5)
s =
a1: [1 2 3 4 5]
b: []
a2: [1 2 3 4 5]
a3: [1 2 3 4 5]
c1: [1 2 3]
c2: [3 4 5]
Then, we'll order the fields alphabetically using orderfields, find the field names using fieldnames, use regexprep to strip all trailing numbers off of the field names, then get the unique substrings using unique:
>> s = orderfields(s);
>> [strs, inds] = unique(regexprep(fieldnames(s), '\d*$', ''), 'last')
strs =
'a'
'b'
'c'
inds =
3
4
6
Using the indices returned by unique, we can calculate how many times each substring appears by doing diff([0; inds]). Then, we group the structure data into a cell array using these counts and struct2cell and mat2cell:
>> data = mat2cell(struct2cell(s), diff([0; inds]))
data =
{3x1 cell}
{1x1 cell}
{2x1 cell}
Notice that we have a cell array of cell arrays. If you know for sure that each set of entries for each substring will concatenate properly (as in our example), you can concatenate them using cellfun and cell2mat as follows:
>> data = cellfun(#cell2mat, data, 'UniformOutput', false)
data =
[3x5 double]
[]
[2x3 double]
Now we have a cell array of matrices, and a new structure can be made using cell2struct:
>> snew = cell2struct(data, strs)
snew =
a: [3x5 double]
b: []
c: [2x3 double]

MATLAB - Need to split a Matrix into column variables with names sourced from another matrix?

I am new to Matlab and I am having some trouble.
I have two matrices that I obtained via importing data these are 'label' (a cell matrix of text) and 'data' (a matrix of doubles?). I need to be able to create variables relating to each column to allow them to be individually plotted and used in calculations. These variables should be automatically named using text from the label matrix. I can't use textread as these matices vary in size depending on source data
Below is an example of my issue
Data =
1 2 3 4
5 6 7 8
9 10 11 12
label = A B C D
I require some code to make Matlab automatically create variables as follows
A =
1
5
9
B =
2
6
10
etc.
I tried using 'eval' to evaluate my label matrix and then '=' to assign the column, but I get an error message because my data matrix is a 'doubles' matrix not a 'cell' matrix.
Thanks for any help you can offer
I recommend dynamic field names:
Data= [1 2 3 4;
5 6 7 8;
9 10 11 12];
Label={'A','B','C','D'};
for iter=1:length(Label)
DataStruct.(Label{iter})=Data(:,iter);
___________<--- field name created automatically
end
>> DataStruct
DataStruct =
A: [3x1 double]
B: [3x1 double]
C: [3x1 double]
D: [3x1 double]
>> DataStruct.A
ans =
1
5
9
This approach has the advantage that it keeps together(in a conceptual unit) all the data that came from the spreadsheet or other source, and won't accidentally overwrite variables in your workspace if the name of a column happens to already exist as a variable (or even worse, potentially, a function... )
I do agree that its a tricky task....Here is the solution
Data=[1 2 3 4; 5 6 7 8; 9 10 11 12]; % A matrix
label=['A', 'B', 'C', 'D']; % its a cell array
for i=1:numel(label)
v=genvarname(label(i)); % Generating the variable names
eval([v ' = Data(i,:)']); % Assinging values into named variables
end
Hasan's code works well but "label" has to be a cell array and not a vector so you have to write label={'A', 'B', 'C', 'D'} and label{i}. If you want 4 columns write Data(:,i).
Data=[1 2 3 4; 5 6 7 8; 9 10 11 12]; % A matrix
label={'A', 'B', 'C', 'D'}; % its a cell array
for i=1:numel(label)
v=genvarname(label{i}); % Generating the variable names
eval([v ' = Data(:,i)']); % Assinging values into named variables
end