Seems like an embarassingly simple question, but how can I transpose a Matlab table vector?
For a simple transposition of a column vector aTable to a row vector I tried standard syntaxes:
aTableT = aTable.';
aTableT = reshape(aTable, 1, height(aTable));
and
aTableT = rot90(aTable);
According to Mathworks the last one should work for table array, see here. However, I get this error code:
Error using table/permute (line 396)
Undefined function 'permute' for input arguments of type 'table'.
Error in rot90 (line 29)
B = permute(B,[2 1 3:ndims(A)]);
NB: fliplr isn't useful either. Pretty sure I've covered the obvious angles - any ideas?
thanks!
Try converting your table into an array, transposing that, then convert back to a table. In other words, try doing this:
aTableArray = table2array(aTable);
aTableT = array2table(aTableArray.');
I read the documentation for rot90 too, and it says that rot90 should definitely work for tables, and I get the same error as you. As such, since transposing obviously works for arrays / matrices, let's do a quick workaround by converting to a matrix, transposing that, then converting back to a table. This worked for me!
I extend the table() class with a few additional methods and fix some existing problems in https://github.com/okomarov/tableutils.
Specific to this question, I define a transpose of a matrix-like table, i.e. if the table has one value per cell, and all variables (columns) are of the same class, then you can transpose the table with my package.
An example:
t = array2table(magic(4))
t =
Var1 Var2 Var3 Var4
____ ____ ____ ____
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
>> t'
ans =
Row1 Row2 Row3 Row4
____ ____ ____ ____
Var1 16 5 9 4
Var2 2 11 7 14
Var3 3 10 6 15
Var4 13 8 12 1
Related
T = table([1;4;0],[0;5;0],[3;6;0])
How can I delete rows that contain only zeros? rmmissing doesn't seem to do the job.
You can do this by using table brace indexing, together with any. Like this:
>> T(any(T{:,:}, 2), :)
ans =
2x3 table
Var1 Var2 Var3
____ ____ ____
1 0 3
4 5 6
Breaking this down - the expression T{:,:} results in a numeric matrix formed from the elements of the table. Calling any(..., 2) results in a logical column vector which is true if any of the elements of the corresponding row are non-zero. Finally, this is combined with standard table () indexing to select only the rows that have a non-zero element.
Objective:
I would like to get, for each period and group of a timetable, the result of a given function of var1 and var2 [i.e. the ratio of (the sum of var1 over the group) by (the sum of var2 over the group)]
using unstack and a function handle:
Data
A = [1 2 3 4 2 4 6 8]';
B = [4 2 14 7 8 4 28 14]';
C=["group1";"group1";"group2";"group2";"group1";"group1";"group2";"group2"];
Year = [2010 2010 2010 2010 2020 2020 2020 2020]';
Year = datetime(string(Year), 'Format', 'yyyy');
t=table(Year,C,A,B,'VariableNames',{'Year' 'group' 'var1' 'var2'});
t=table2timetable(t,'RowTimes','Year');
Desired Output [EDIT]
A table with three columns: year, Ratio_group1, Ratio_group2. Where for instance:
Ratio_group1 for 2010 = (1+2) / (4+2) =0.5.
Function
f = #(x,y) sum(x)./sum(y); %or f = #(x) sum(x(1,:))./sum(x(2,:));
[Ratio,is] = unstack(t,{'var1','var2'},"group",'AggregationFunction',f);
Errors that I get:
%Not enough input arguments.
%Or: Index in position 1 exceeds array bounds (must not exceed 1)
Another failed test inspired from https://www.mathworks.com/help/matlab/ref/double.groupsummary.html
(See Method Function Handle with Multiple Inputs)
[Ratio,is] = unstack(t,{["var1"],["var2"]},"group",'AggregationFunction',f);
%Error: A table variable subscript must be a numeric array continaing real positive integers, a logical array (...)
This can be done using findgroups and splitapply (or equivalently accumarray):
result = splitapply(#(x,y) sum(x)/sum(y), t.var1, t.var2, findgroups(t.Year, t.group));
I've two matrix a and b and I'd like to combine the rows in a way that in the first row I got no duplicate value and in the second value, columns in a and b which have the same row value get the maximum value in new matrix. i.e.
a = 1 2 3
8 2 5
b = 1 2 5 7
2 4 6 1
Desired output
c = 1 2 3 5 7
8 4 5 6 1
Any help is welcomed,please.( the case for accumulation is asked here)
Accumarray accepts functions both anonymous as well as built-in functions. It uses sum function as default. But you could change this to any in-built or anonymous functions like this:
In this case you could use max function.
in = horzcat(a,b).';
[uVal,~,idx] = unique(in(:,1));
out = [uVal,accumarray(idx,in(:,2),[],#max)].'
Based upon your previous question and looking at the help file for accumarray, which has this exact example.
[ii, ~, kk] = unique([a(1,:) b(1,:)]);
result = [ ii; accumarray(kk(:), [a(2,:) b(2,:)], [], #max).'];
The only difference is the anonymous function.
I have more 8+ tables in Matlab of different lengths. They all include dates in the their first column. I would like to get the intersection of all these tables on the date columns. The following small example with 3 tables shows what I want:
Date1=datenum(2011,6,7,0:24:240,0,0).';
Date2=datenum(2011,6,8,0:24:240,0,0).';
Date3=datenum(2011,6,5,0:24:240,0,0).';
T1 = table(Date1,ones(11,1),'VariableNames',{'Date','Var1'})
T2 = table(Date2,ones(11,1)*2,'VariableNames',{'Date','Var2'})
T3 = table(Date3,ones(11,1)*3,'VariableNames',{'Date','Var3'})
Thus, I would like the following output:
Date Var1 Var2 Var3
______ ____ ____ ____
734662 1 2 3
734663 1 2 3
734664 1 2 3
734665 1 2 3
734666 1 2 3
734667 1 2 3
734668 1 2 3
734669 1 2 3
Is there a function in Matlab that can do this?
The intersect function may be of use for your case.
I am not sure how you use the tables, but the code below should let you find the indices of the intersection for each DateN vector. Once you have the indices, you can rebuild a global table which only incorporate the common indices between all tables.
[C,ia,ib ] = intersect(Date1,Date2) ; %// get indices of intersection of first 2 vectors (Date1&2)
[D,ja,ix3] = intersect( C ,Date3) ; %// get indices of intersection of last result (Date1&2) with last vector (Date 3)
ix1 = ia(ja) ; %// take only the common indices of the 2 intersection operations (For Date1)
ix2 = ib(ja) ; %// take only the common indices of the 2 intersection operations (For Date2)
%// Build the "common" table
intersectionTable = [ Date1(ix1) Var1(ix1) Var2(ix2) Var3(ix3) ] ;
I wrote a very closely related code for another question and I am putting down a polished function code here that finds the intersecting elements and the corresponding indices for several arrays at the same time without resorting to any kind of looping for the computation part. Here's the code -
function [out_val,out_idx] = intersect_arrays(varargin)
%// Concatenate all vector arrays into a 2D array
if isrow(varargin{1})
M = vertcat(varargin{:});
else
M = horzcat(varargin{:}).'; %//'
end
%// Find unique values for all elements in all arrays
unqvals = unique(M(:),'stable')'; %//'
%// Find unqiue elements common across all arrays (intersecting elements)
out_val = unqvals(all(any(bsxfun(#eq,M,permute(unqvals,[1 3 2])),2),1));
%// Find first indices across all arrays holding the intersecting elements
[~,idx] = max(bsxfun(#eq,M,permute(out_val,[1 3 2])),[],2);
out_idx = squeeze(idx).'; %//'
return
Now, to solve your case, we can use the function code like so -
num_arrays = 3; %// Number of arrays to be used
%// Find intersecting elements and their corresppinding indices in each array
[int_ele,int_idx] = intersect_arrays(T1.Date,T2.Date,T3.Date) %// Add inputs here
%// Create an array of all Var data
all_idx = cat(2,T1.Var1,T2.Var2,T3.Var3) %// Add inputs here
%// Select Var data based on the intersecting indices
select_idx = all_idx(bsxfun(#plus,int_idx,[0:num_arrays-1]*size(T1.Var1,1)))
%// Output results as a numeric array and table
out_array = [int_ele(:) select_idx]
out_table = cell2table(num2cell(out_array),'VariableNames',...
{'Date','Var1','Var2','Var3'})
Output -
out_table =
Date Var1 Var2 Var3
______ ____ ____ ____
734662 1 2 3
734663 1 2 3
734664 1 2 3
734665 1 2 3
734666 1 2 3
734667 1 2 3
734668 1 2 3
734669 1 2 3
If A and B are tables (or datasets) having the same the same columns (and in the same order), then an expression like ismember(A(:, somecols), B(:, somecols)) will produce a boolean array suitable for indexing A with, as in
A(ismember(A(:, somecols), B(:, somecols)), :)
The line above evaluates to a table (or dataset, depending on the class of A) consisting of those rows of A that match some row of B at the columns specified in somecols.
But now suppose that B has exactly one row. More realistically, suppose that the criterion for selecting rows from A is simply to match this one single row of B, say the first one.
One could do this:
A(ismember(A(:, somecols), B(1, somecols)), :)
The main quibble I have with this is that it is not "semantically clear", because ismember is being used, in effect, to test for equality.
It would be semantically clearer if one could write
A(isequal(A(:, somecols), B(1, somecols)), :)
but this does line not produce the desired results. (Specifically, it returns no matches even when A(:, ...) contains rows matching B(1, ...).)
My question is, what is the predicate that will correctly produce the logical vector corresponding to the question "does this row of A match this reference row at somecols"?
For the table data type you can also use innerjoin, but ismember is fairly clear in this case. Consider the tables At and Bt, where Bt has two common rows and one unique row:
>> A = randi(7,4,5);
>> commonRows = [1 3];
>> B = [A(commonRows,:); randi(2,1,5)+7];
>> At = array2table(A,'VariableNames',sprintfc('C%d',1:size(A,2)))
At =
C1 C2 C3 C4 C5
__ __ __ __ __
4 1 5 7 7
2 6 5 1 4
4 4 6 7 4
2 7 7 5 6
>> Bt = array2table(B,'VariableNames',sprintfc('C%d',1:size(A,2)))
Bt =
C1 C2 C3 C4 C5
__ __ __ __ __
4 1 5 7 7
4 4 6 7 4
8 8 9 9 9
The second output argument of innerjoin, IA, gives you the indexes of rows in A that are also in B. As in your example, consider a subset of the columns, specified by somecols:
>> somecols = [2 5]
somecols =
2 5
>> [Ct,IA] = innerjoin(At(:,somecols), Bt(1,somecols))
Ct =
C2 C5
__ __
1 7
IA =
1
>> [Ct,IA] = innerjoin(At(:,somecols), Bt(2,somecols))
Ct =
C2 C5
__ __
4 4
IA =
3
>> [Ct,IA] = innerjoin(At(:,somecols), Bt(3,somecols))
Ct =
empty 0-by-2 table
IA =
[]
If IA is empty (or not) is a suitable test:
>> [~,IA] = innerjoin(At, Bt(3,:));
>> isempty(IA)
ans =
1
>> [~,IA] = innerjoin(At, Bt(2,:));
>> isempty(IA)
ans =
0
Or just test the first output, the common table rows:
>> isempty(innerjoin(At, Bt(3,:)))
ans =
1
>> isempty(innerjoin(At, Bt(1,:)))
ans =
0
I agree that with the ismember option it may not be immediately clear what you are intending (though there is nothing wrong with it exactly). Another way you could do which I guess might be more semantically clear (though potentially less efficient) is to use bsxfun like so:
all(bsxfun(#eq,A(:,somecols),B(1,somecols)),2);
If you were to expand this into what is essentially happening under the hood, it would be something like:
a = A(:,somecols);
b = repmat(B(1,somecols),size(A,1),1);
abeq = all(a == b,2);
A(abeq,:);
Basically you're replicating the one B row so that it is the same size as A(:,somecols) and then comparing each value in each array. Finally, you're checking which rows have a whole row of true (by using all), which indicates it matches the single row of B.
EDIT: Sorry, apparently I misunderstood the question - if you're using the table datatype (which I didn't actually know existed until a few minutes ago - thanks horchler), then this approach probably won't work.
EDIT2: Notlikethat pointed out the existence of the function rowfun, which acts on each row in a table. I can't test this (my version of MATLAB isn't new enough) but I assume that something like this would do what you are wanting:
A(rowfun(#(x) isequal(B(1,somecols),x),A(:,somecols)),:);