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.
Related
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]);
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
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
I have a dataset that includes all data in 1 column. However a new sub-dataset occurs every n rows. Using MATLAB, I need to grab each of these sub-datasets and place in a separate sequential column. For example, this:
Column 1
1
3
2
1
3
2
1
3
2
into this:
Column 1 | Column 2 | Column 3 | ...
1 1 1
3 3 3
2 2 2
You can use the reshape command like so:
my_matrix = reshape(my_vector, num_rows, num_cols);
You can also replace num_cols in the above with [] to have MATLAB automatically figure out how many columns are needed to fit the data into num_rows rows. Similarly, you can replace num_rows with [] and have MATLAB figure out the number of rows needed to fit the data into num_cols columns.
Note that MATLAB will throw an error if my_vector does not contain exactly num_rows * num_cols elements. In other words, it will not pad with zeros or truncate your data if the sizes do not match.
I have two tables (or actually I have several) that should be merged using innerjoin. It works as expected; except that it sort on the "Keys", which destroys my data since it actually must be arranged in the original row order.
From the help section:
C is sorted by the values in the key variables
t1 = Case Val
3 1
1 1
2 1
t2 = Val2 Case Subset
2 2 2
1 2 2
2 3 1
tnew = innerjoin(t1,t2)
tnew = Case Val Val2 Subset
2 ...
% will start with "2" since its a lower value than "3", but in t1 "3" was in lower row than "2", it is rearranged
How should I avoid the sorting? Hopeless to use innerjoin?
In addition to the resulting table, innerjoin returns two extra outputs: The row indices of the first table and the row indices of the second table that correspond to the rows in the output.
You can simply use the second output to determine the rows in t1 that were used and you could sort these. Then use the sort order to change the ordering of the rows in the result of the join.
%// Setup the data
t1 = table([3;1;2], [1;1;1], 'VariableNames', {'Case', 'Val'});
t2 = table([2;1;2],[2;2;3],[2;2;1], 'VariableNames', {'Val2', 'Case', 'Subset'});
%// Perform the inner join and keep track of where the rows were in t1
[tnew, rows_in_t1] = innerjoin(t1, t2);
%// Sort them in order to maintain the order in t1
[~, sortinds] = sort(rows_in_t1);
%// Apply this sort order to the new table
tnew = tnew(sortinds,:);
%// Case Val Val2 Subset
%// ____ ___ ____ ______
%// 3 1 2 1
%// 2 1 2 2
%// 2 1 1 2