Elegant way of stripping the 1st layer of cell array in MATLAB? - matlab

I have a 1x2 cell array a such that
a{1, 1} is a 5x1 int array containing [1 2 3 4 5]
a{1, 2} is a 5x1 cell array containing 'aa', 'bb', 'cc', 'dd', 'ee'
What is the most elegant way of stripping the first layer, producing a 5x2 cell array as follows?
1 'aa'
2 'bb'
3 'cc'
4 'dd'
5 'ee'

How about:
% original cell
a = cell(1,2);
a{1} = [1 2 3 4 5];
a{2} = {'aa', 'bb', 'cc', 'dd', 'ee'};
% flattened
aa = reshape([num2cell(a{1}) a{2}], [], 2)

I figured one solution out, but am not sure about its "elegantness".
a = cell(1, 2);
a{1, 1} = [1, 2, 3, 4, 5];
a{1, 2} = {'aa','bb','cc','dd','ee'};
result = [num2cell(a{1, 1})' a{1, 2}']
result =
[1] 'aa'
[2] 'bb'
[3] 'cc'
[4] 'dd'
[5] 'ee'

You can try this code:
a{1, 1} = [1,2,3,4,5];
a{1, 2} = {'aa','bb','cc','dd','ee'};
temp = num2cell(a{1});
b = {temp{:};a{2}{:}}.'
b =
[1] 'aa'
[2] 'bb'
[3] 'cc'
[4] 'dd'
[5] 'ee'

Related

Join time series in matlab and replace missing data points with NaN [duplicate]

I have two matrices like the following ones:
'01/01/2010' 1
'02/01/2010' 2
'03/01/2010' 3
'05/01/2010' 11
'06/01/2010' 17
'01/01/2010' 4
'02/01/2010' 5
'04/01/2010' 6
'05/01/2010' 7
, and after doing a few tricky things in MATLAB, I want to create the following three matrices:
'01/01/2010' 1 4
'02/01/2010' 2 5
'03/01/2010' 3 NaN
'04/01/2010' NaN 6
'05/01/2010' 11 7
'06/01/2010' 17 NaN
'01/01/2010' 1 4
'02/01/2010' 2 5
'05/01/2010' 11 7
Any idea on how to join these tables?
Cheers.
EDIT: Really sorry for my typos, guys. I updated both the question and the input/output data. Please, feel free to provide suggestions.
I believe what you are trying to achieve are called inner join, and full outer join in the database world.
First we start with the two datasets:
d1 = {
'01/01/2010' 1
'02/01/2010' 2
'03/01/2010' 3
'05/01/2010' 11
'06/01/2010' 17
};
d2 = {
'01/01/2010' 4
'02/01/2010' 5
'04/01/2010' 6
'05/01/2010' 7
};
Here is the code to perform the two types of join:
%# get all possible dates, and convert them to indices starting at 1
[keys,~,ind] = unique( [d1(:,1);d2(:,1)] );
%# full outer join
ind1 = ind(1:size(d1,1));
ind2 = ind(size(d1,1)+1:end);
fullOuterJoin = cell(numel(keys),3);
fullOuterJoin(:) = {NaN}; %# fill with NaNs
fullOuterJoin(:,1) = keys; %# union of dates
fullOuterJoin(ind1,2) = d1(:,2); %# insert 1st dataset values
fullOuterJoin(ind2,3) = d2(:,2); %# insert 2nd dataset values
%# inner join
loc1 = ismember(ind1, ind2);
loc2 = ismember(ind2, ind1);
innerJoin = cell(sum(loc1),3);
innerJoin(:,1) = d1(loc1,1); %# intersection of dates
innerJoin(:,2) = d1(loc1,2); %# insert 1st dataset values
innerJoin(:,3) = d2(loc2,2); %# insert 2nd dataset values
Alternatively, we could have extracted the inner join from the outer join dataset by simply removing rows with any NaN values:
idx = all(~isnan(cell2mat(fullOuterJoin(:,2:end))), 2);
innerJoin = fullOuterJoin(idx,:);
Either way, the result:
>> fullOuterJoin
fullOuterJoin =
'01/01/2010' [ 1] [ 4]
'02/01/2010' [ 2] [ 5]
'03/01/2010' [ 3] [NaN]
'04/01/2010' [NaN] [ 6]
'05/01/2010' [ 11] [ 7]
'06/01/2010' [ 17] [NaN]
>> innerJoin
innerJoin =
'01/01/2010' [ 1] [4]
'02/01/2010' [ 2] [5]
'05/01/2010' [11] [7]
In MATLAB, you cannot have strings as matrix elements. For that you need to use a cell array. This is a solution using cell arrays and containers.Maps.
FirstCellArray = {
'01/01/2010', 1;
'02/01/2010', 2;
'03/01/2010', 3;
'05/01/2010', 11;
'06/01/2010', 17
};
SecondCellArray = {
'01/01/2010', 4;
'02/01/2010', 5;
'04/01/2010', 6;
'05/01/2010', 7;
};
AllDatesCellArray = union(FirstCellArray(:,1), SecondCellArray(:,1));
% Create containers.Maps for both cell arrays. containers.Maps are hash tables.
DateToFirstNumberMap = containers.Map(FirstCellArray(:,1), FirstCellArray(:,2));
DateToSecondNumberMap = containers.Map(SecondCellArray(:,1), SecondCellArray(:,2));
WithNaNsCellArray = AllDatesCellArray;
for Index = 1:size(WithNaNsCellArray, 1)
Key = AllDatesCellArray{Index, 1};
try
NumberOne = cell2mat(values(DateToFirstNumberMap, cellstr(Key)));
catch
NumberOne = NaN;
end
WithNaNsCellArray{Index, 2} = NumberOne;
try
NumberTwo = cell2mat(values(DateToSecondNumberMap, cellstr(Key)));
catch
NumberTwo = NaN;
end
WithNaNsCellArray{Index, 3} = NumberTwo;
end
WithoutNaNsCellArray = WithNaNsCellArray;
NaNIndicesVector = (isnan([WithNaNsCellArray{:,2}]) | isnan([WithNaNsCellArray{:,3}]));
WithoutNaNsCellArray(NaNIndicesVector == 1, :) = [];
Then WithNaNsCellArray contains the result with NaN rows and WithoutNaNsCellArray contains the result without NaN rows.
WithNaNsCellArray =
'01/01/2010' [ 1] [ 4]
'02/01/2010' [ 2] [ 5]
'03/01/2010' [ 3] [NaN]
'04/01/2010' [NaN] [ 6]
'05/01/2010' [ 11] [ 7]
'06/01/2010' [ 17] [NaN]
WithoutNaNsCellArray =
'01/01/2010' [ 1] [4]
'02/01/2010' [ 2] [5]
'05/01/2010' [11] [7]
The statistics toolbox contains a function called JOIN that basically does what you want.
http://www.mathworks.de/de/help/stats/dataset.join.html
Unfortunately, it probably can't handle strings and polytyped matrices. But you might be able to use JOIN to shorten the solutions proposed by the other answers.

Displaying the output of a cell in matlab

I have a cell of the of the following :
displayop =
[2114x1 datetime] [2114x1 double] [2114x1 double] {2114x1 cell}
How I can see the output of displayop ? I have tried using cell2mat, but gives me the following error: All contents of the input cell array must be of the same data type.
I am looking at the below output for displayop:
03/11/2016 7544 7544 'UP'
Here is an example using MATLAB's tables:
% a sample cell array resembling your data
>> displayop = {datetime(2016,3,(1:10)') (1:10)' rand(10,1) cellstr(num2str((11:20)'))}
displayop =
[10x1 datetime] [10x1 double] [10x1 double] {10x1 cell}
Now:
% convert to table, which is displayed nicely
>> table(displayop{:}, 'VariableNames',{'dt','x','y','str'})
ans =
dt x y str
___________ __ ________ ____
01-Mar-2016 1 0.049654 '11'
02-Mar-2016 2 0.90272 '12'
03-Mar-2016 3 0.94479 '13'
04-Mar-2016 4 0.49086 '14'
05-Mar-2016 5 0.48925 '15'
06-Mar-2016 6 0.33772 '16'
07-Mar-2016 7 0.90005 '17'
08-Mar-2016 8 0.36925 '18'
09-Mar-2016 9 0.1112 '19'
10-Mar-2016 10 0.78025 '20'
Bonus:
You can still use plain old cell-arrays:
>> C = [num2cell(displayop{1}) num2cell(displayop{2}) num2cell(displayop{3}) displayop{4}]
C =
[01-Mar-2016] [ 1] [0.0497] '11'
[02-Mar-2016] [ 2] [0.9027] '12'
[03-Mar-2016] [ 3] [0.9448] '13'
[04-Mar-2016] [ 4] [0.4909] '14'
[05-Mar-2016] [ 5] [0.4893] '15'
[06-Mar-2016] [ 6] [0.3377] '16'
[07-Mar-2016] [ 7] [0.9001] '17'
[08-Mar-2016] [ 8] [0.3692] '18'
[09-Mar-2016] [ 9] [0.1112] '19'
[10-Mar-2016] [10] [0.7803] '20'

How to expand my cell without losing information

I have this a cell that holds 4 vectors, and I'd like to expand it so it could hold another vector. Thanks in advance.
a = cell(4, 1);
a{1} = [1, 2, 3];
a{2} = [1, 4, 9];
a{3} = [1, 4, 9];
a{4} = [1; 5];
And I would like to add a new vector [2, 7] so that I will get this
a{1} = [2, 7];
a{2} = [1, 2, 3];
a{3} = [1, 4, 9];
a{4} = [1, 4, 9];
a{5} = [1; 5];
How could I do that ?
a = cell(4, 1);
a{1} = [1, 2, 3];
a{2} = [1, 4, 9];
a{3} = [1, 4, 9];
a{4} = [1; 5];
a = [[2, 7];a]
Yielding:
a =
[1x2 double]
[1x3 double]
[1x3 double]
[1x3 double]
[2x1 double]
The name for what you are trying to do is concatenation. In MATLAB, square brackets are an implicit method of concatenation. While you typically think about these being used to concatenate numbers to form a vector or matrix:
x = [1, 2, 3, 4] % 1 x 4
You can also use them to concatenate other data types (including cell arrays)
y = [{1,2}, 5, {4, 5}]; % 1 x 3 Cell Array
It is also important to keep track of the dimension of concatenation. With square brackets you can either concatenate across the columns (2nd dimension) using a comma or across the rows (1st dimension using a semi-colon).
size([1,2,3])
1 x 3
size([1;2;3])
3 x 1
While square brackets are a quick and easy solution, I prefer to be a little more explicit. For this, MATLAB has the following functions: cat, horzcat, and vertcat. I personally prefer cat since you can specify concatenation in any arbitrary dimension.
x = cat(2, 100, 200, 300); % 1 x 3
100 200 300
x = cat(1, 100, 200, 300); % 3 x 1
100
200
300
x = cat(3, 100, 200, 300) % 1 x 1 x 3
x(:,:,1) =
100
x(:,:,2) =
200
x(:,:,3) =
300
So back to your original question, you want to concatenate in the 1st dimension (rows) so you could simply do the following:
a = cell(4, 1);
a{1} = [1, 2, 3];
a{2} = [1, 4, 9];
a{3} = [1, 4, 9];
a{4} = [1; 5];
a = cat(1, [2, 7], a);
Also remember that this form of using concat or the square brackets can be applied to most datatypes within MATLAB including structs among others.

Join Matrices in MATLAB

I have two matrices like the following ones:
'01/01/2010' 1
'02/01/2010' 2
'03/01/2010' 3
'05/01/2010' 11
'06/01/2010' 17
'01/01/2010' 4
'02/01/2010' 5
'04/01/2010' 6
'05/01/2010' 7
, and after doing a few tricky things in MATLAB, I want to create the following three matrices:
'01/01/2010' 1 4
'02/01/2010' 2 5
'03/01/2010' 3 NaN
'04/01/2010' NaN 6
'05/01/2010' 11 7
'06/01/2010' 17 NaN
'01/01/2010' 1 4
'02/01/2010' 2 5
'05/01/2010' 11 7
Any idea on how to join these tables?
Cheers.
EDIT: Really sorry for my typos, guys. I updated both the question and the input/output data. Please, feel free to provide suggestions.
I believe what you are trying to achieve are called inner join, and full outer join in the database world.
First we start with the two datasets:
d1 = {
'01/01/2010' 1
'02/01/2010' 2
'03/01/2010' 3
'05/01/2010' 11
'06/01/2010' 17
};
d2 = {
'01/01/2010' 4
'02/01/2010' 5
'04/01/2010' 6
'05/01/2010' 7
};
Here is the code to perform the two types of join:
%# get all possible dates, and convert them to indices starting at 1
[keys,~,ind] = unique( [d1(:,1);d2(:,1)] );
%# full outer join
ind1 = ind(1:size(d1,1));
ind2 = ind(size(d1,1)+1:end);
fullOuterJoin = cell(numel(keys),3);
fullOuterJoin(:) = {NaN}; %# fill with NaNs
fullOuterJoin(:,1) = keys; %# union of dates
fullOuterJoin(ind1,2) = d1(:,2); %# insert 1st dataset values
fullOuterJoin(ind2,3) = d2(:,2); %# insert 2nd dataset values
%# inner join
loc1 = ismember(ind1, ind2);
loc2 = ismember(ind2, ind1);
innerJoin = cell(sum(loc1),3);
innerJoin(:,1) = d1(loc1,1); %# intersection of dates
innerJoin(:,2) = d1(loc1,2); %# insert 1st dataset values
innerJoin(:,3) = d2(loc2,2); %# insert 2nd dataset values
Alternatively, we could have extracted the inner join from the outer join dataset by simply removing rows with any NaN values:
idx = all(~isnan(cell2mat(fullOuterJoin(:,2:end))), 2);
innerJoin = fullOuterJoin(idx,:);
Either way, the result:
>> fullOuterJoin
fullOuterJoin =
'01/01/2010' [ 1] [ 4]
'02/01/2010' [ 2] [ 5]
'03/01/2010' [ 3] [NaN]
'04/01/2010' [NaN] [ 6]
'05/01/2010' [ 11] [ 7]
'06/01/2010' [ 17] [NaN]
>> innerJoin
innerJoin =
'01/01/2010' [ 1] [4]
'02/01/2010' [ 2] [5]
'05/01/2010' [11] [7]
In MATLAB, you cannot have strings as matrix elements. For that you need to use a cell array. This is a solution using cell arrays and containers.Maps.
FirstCellArray = {
'01/01/2010', 1;
'02/01/2010', 2;
'03/01/2010', 3;
'05/01/2010', 11;
'06/01/2010', 17
};
SecondCellArray = {
'01/01/2010', 4;
'02/01/2010', 5;
'04/01/2010', 6;
'05/01/2010', 7;
};
AllDatesCellArray = union(FirstCellArray(:,1), SecondCellArray(:,1));
% Create containers.Maps for both cell arrays. containers.Maps are hash tables.
DateToFirstNumberMap = containers.Map(FirstCellArray(:,1), FirstCellArray(:,2));
DateToSecondNumberMap = containers.Map(SecondCellArray(:,1), SecondCellArray(:,2));
WithNaNsCellArray = AllDatesCellArray;
for Index = 1:size(WithNaNsCellArray, 1)
Key = AllDatesCellArray{Index, 1};
try
NumberOne = cell2mat(values(DateToFirstNumberMap, cellstr(Key)));
catch
NumberOne = NaN;
end
WithNaNsCellArray{Index, 2} = NumberOne;
try
NumberTwo = cell2mat(values(DateToSecondNumberMap, cellstr(Key)));
catch
NumberTwo = NaN;
end
WithNaNsCellArray{Index, 3} = NumberTwo;
end
WithoutNaNsCellArray = WithNaNsCellArray;
NaNIndicesVector = (isnan([WithNaNsCellArray{:,2}]) | isnan([WithNaNsCellArray{:,3}]));
WithoutNaNsCellArray(NaNIndicesVector == 1, :) = [];
Then WithNaNsCellArray contains the result with NaN rows and WithoutNaNsCellArray contains the result without NaN rows.
WithNaNsCellArray =
'01/01/2010' [ 1] [ 4]
'02/01/2010' [ 2] [ 5]
'03/01/2010' [ 3] [NaN]
'04/01/2010' [NaN] [ 6]
'05/01/2010' [ 11] [ 7]
'06/01/2010' [ 17] [NaN]
WithoutNaNsCellArray =
'01/01/2010' [ 1] [4]
'02/01/2010' [ 2] [5]
'05/01/2010' [11] [7]
The statistics toolbox contains a function called JOIN that basically does what you want.
http://www.mathworks.de/de/help/stats/dataset.join.html
Unfortunately, it probably can't handle strings and polytyped matrices. But you might be able to use JOIN to shorten the solutions proposed by the other answers.

Joining data from different cell arrays in Matlab

I have data in Matlab that is in cell array format with columns representing different items. The cell arrays have different columns, as in the following example:
a = {'A', 'B', 'C' ; 1, 1, 1; 2, 2, 2 }
a =
'A' 'B' 'C'
[1] [1] [1]
[2] [2] [2]
b = {'C', 'D'; 3, 3; 4, 4}
b =
'C' 'D'
[3] [3]
[4] [4]
I would like to be able to join the different cell arrays in the following manner:
c =
'A' 'B' 'C' 'D'
[1] [1] [1] [NaN]
[2] [2] [2] [NaN]
[NaN] [NaN] [3] [3]
[NaN] [NaN] [4] [4]
In the real example I have hundreds of columns and several rows, so creating a new cell array manually is not an option for me.
If you were willing to store your data in dataset arrays (or convert them to dataset arrays for this purpose), you could do the following:
>> d1
d1 =
A B C
1 1 1
2 2 2
>> d2
d2 =
C D
3 3
4 4
>> join(d1,d2,'Keys','C','type','outer','mergekeys',true)
ans =
A B C D
1 1 1 NaN
2 2 2 NaN
NaN NaN 3 3
NaN NaN 4 4
I'm assuming you want to join the two arrays based on their first row only.
% get the list of all keys
keys = unique([a(1,:) b(1,:)]);
lena = size(a,1)-1; lenb = size(b,1)-1;
% allocate space for the joined array
joined = cell(lena+lenb+1, length(keys));
joined(1,:) = keys;
% add a
tf = ismember(keys, a(1,:));
joined(2:(2+lena-1),tf) = a(2:end,:);
% add b
tf = ismember(keys, b(1,:));
joined((lena+2):(lena+lenb+1),tf) = b(2:end,:);
This will give you the joined array except that it has empty cells instead NaNs. I hope this is OK.
Here is my solution adapted from an old another to a similar question (simply transpose rows/columns):
%# input cell arrays
a = {'A', 'B', 'C' ; 1, 1, 1; 2, 2, 2 };
b = {'C', 'D'; 3, 3; 4, 4};
%# transpose rows/columns
a = a'; b = b';
%# get all key values, and convert them to indices starting at 1
[allKeys,~,ind] = unique( [a(:,1);b(:,1)] );
indA = ind(1:size(a,1));
indB = ind(size(a,1)+1:end);
%# merge the two datasets (key,value1,value2)
c = cell(numel(allKeys), size(a,2)+size(b,2)-1);
c(:) = {NaN}; %# fill with NaNs
c(:,1) = allKeys; %# available keys from both
c(indA,2:size(a,2)) = a(:,2:end); %# insert 1st dataset values
c(indB,size(a,2)+1:end) = b(:,2:end); %# insert 2nd dataset values
Here is the result (transposed to match original orientation):
>> c'
ans =
'A' 'B' 'C' 'D'
[ 1] [ 1] [1] [NaN]
[ 2] [ 2] [2] [NaN]
[NaN] [NaN] [3] [ 3]
[NaN] [NaN] [4] [ 4]
Also here is the solution using the DATASET class from the Statistics Toolbox:
aa = dataset([cell2mat(a(2:end,:)) a(1,:)])
bb = dataset([cell2mat(b(2:end,:)) b(1,:)])
cc = join(aa,bb, 'Keys',{'C'}, 'type','fullouter', 'MergeKeys',true)
with
cc =
A B C D
1 1 1 NaN
2 2 2 NaN
NaN NaN 3 3
NaN NaN 4 4