Converting a cell row to a cell column - matlab

I have a matrix B (1 * 5 cell) I want to change it to B (5 * 1 cell) knowing that each element of the matrix contains (1 * 18 cell) and each is a cell
original matrix
[1] [2] [3] [4] [5]`
[1] (1*18 cell) (1*18 cell) (1*18 cell) (1*18 cell) (1*18 cell)
My goal is:
1) convert line from B to column% I try to use C = A (:); And C = B. '
2) make B a cellless matrix with cell2mat% Error using cell2mat (line 53)
Can not support cell arrays containing cell arrays or objects.
The desired output is:
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] ... [18]
[1] 2 1.5 1.69 1.02 1 1.36 1 2 1.67 1.20 1.36 ...
[2] 2 1.53 1.99 1 1.36 1 2 1 1 1.99 1.02 ...
[3] 1.02 1 1.36 1.3 2 1.67 1.20 1.36 1.99 2 1.5 ...
[4] 2 1.53 1.99 1 1.36 1 2 1 1 1.36 1.99 ...
[5] 1.5 1.69 1.02 1.2 1.36 1 2 1 1.36 1.5 1.5 ...
thanks

You can just use cat (combined with {} indexing to create a comma-separated list) to concatenate all of the cell arrays in B along the first dimension
out = cat(1, B{:});
If you want the result to no longer be a cell, use cell2mat on the output
cell2mat(out)

Related

How can I efficiently pivot a table with replications in MATLAB from tall to wide format?

I have a tall MATLAB table like this:
spam =
Data cat1 cat2 time
__________ ___________ __________ ______
-0.41763 1 0 0
0.11719 1 0 0
... ... ... ...
-0.16546 1 0 1
... ... ... ...
-0.21763 1 0 2
0.31719 2 0 0
... ... ... ...
0.58116 3 1 0
... ... ... ...
Data is of double format, cat1 (8 levels) and cat2 (3 levels) are categorical, and time (3 levels) is ordinal (but could be double). Each time point of each cat1 and cat2 level includes 30 (technical) replicates (denoted by ... above).
I wish to use these data in fitrm, which requires them in the wide format. Hence I need to transform the Data column to three separate variables.
Using unstack I get something like this:
spam = unstack(spam, 'Data', 'time')
Warning: Variable names were modified to make them valid MATLAB identifiers.
spam =
cat1 cat2 x0 x1 x2
______ _________ ___________ _______ ________
1 0 -7.6605e-15 2.3168 0.45234
2 0 6.2172e-15 5.1661 24.89
3 1 8.8818e-16 56.697 40.441
4 1 -7.9936e-15 -22.741 -17.191
5 1 -1.4433e-15 -7.7803 -20.817
6 2 5.5511e-16 7.8535 -0.21172
7 2 5.3291e-15 13.658 5.8402
8 2 2.2204e-15 9.1739 13.814
Obviously this result does not include all the information in the tall table.
Specifically, the replicates have not been carried to the result.
Using accumarray, in a similar fashion to that shown in another stack page could be promising, but in my case it seemed easier to perform the one-time transformation by hand.
Is anyone aware of a more efficient approach?
I realize now that perhaps the easiest way is to just add an extra variable replication in the tall table and then use unstack as above.
Example (with different data, taken from my answer here):
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
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

Using nested for-loop to generate a table of numbers

I try to write a function in which print this output:
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
I wrote this code, but I'm not getting the desired output:
rows = 5;
% there are 5 rows
for i=1:rows
for j=1:i
b=i*j;
end
fprintf('%d\n',b)
end
How to I need to correct this algorithm or can you tell me, if there are any other alternate methods to solve this?
I don't know what you mean by "print", but this is how you could start:
%// initial vector
a = 1:5;
A = tril( bsxfun(#plus,a(:)*[0:numel(a)-1],a(:)) )
%// or
A = tril(a.'*a) %'// thanks to Daniel!
mask = A == 0
out = num2cell( A );
out(mask) = {[]}
A =
1 0 0 0 0
2 4 0 0 0
3 6 9 0 0
4 8 12 16 0
5 10 15 20 25
out =
[1] [] [] [] []
[2] [ 4] [] [] []
[3] [ 6] [ 9] [] []
[4] [ 8] [12] [16] []
[5] [10] [15] [20] [25]
To print it to a file, you can use.
out = out.'; %'
fid = fopen('output.txt','w')
fprintf(fid,[repmat('%d \t',1,n) '\r\n'],out{:})
fclose(fid)
and you get:
just for the command window:
out = out.'; %'
fprintf([repmat('%d \t',1,n) '\r\n'],out{:})
will be sufficient. Choose your desired delimiter, if you don't like '\t'.
If you insist on a nested for loop, you can do it like this:
rows = 5;
% there are 5 rows
for ii = 1:rows
for jj = 1:ii
b = ii*jj;
if ii <= jj
fprintf('%d \n',b)
else
fprintf('%d ',b)
end
end
end
displays:
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25

Combine matrices using loop and condition in matlab

I have the following two matrices
c=[1 0 1.05
1 3 2.05
1 6 2.52
1 9 0.88
2 0 2.58
2 3 0.53
2 6 3.69
2 9 0.18
3 0 3.22
3 3 1.88
3 6 3.98]
f=[1 6 3.9
1 9 9.1
1 12 9
2 0 0.3
2 3 0.9
2 6 1.2
2 9 2.5
3 0 2.7]
And the final matrix should be
n=[1 6 2.52 3.9
1 9 0.88 9.1
2 0 2.58 0.3
2 3 0.53 0.9
2 6 3.69 1.2
2 9 0.18 2.5
3 0 3.22 2.7]
The code I used gives as a result only the last row of the previous matrix [n].
for j=1
for i=1:rs1
for k=1
for l=1:rs2
if f(i,j)==c(l,k) && f(i,j+1)==c(l,k+1)
n=[f(i,j),f(i,j+1),f(i,j+2), c(l,k+2)];
end
end
end
end
end
Can anyone help me on this?
Is there something more simple?
Thanks in advance
You should learn to use set operations and avoid loops wherever possible. Here intersect could be extremely useful:
[u, idx_c, idx_f] = intersect(c(:, 1:2) , f(:, 1:2), 'rows');
n = [c(idx_c, :), f(idx_f, end)];
Explanation: by specifying the 'rows' flag, intersect finds the common rows in c and f, and their indices are given in idx_c and idx_f respectively. Use vector subscripting to extract matrix n.
Example
Let's use the example from your question:
c = [1 0 1.05;
1 3 2.05
1 6 2.52
1 9 0.88
2 0 2.58
2 3 0.53
2 6 3.69
2 9 0.18
3 0 3.22
3 3 1.88
3 6 3.98];
f = [1 6 3.9
1 9 9.1
1 12 9
2 0 0.3
2 3 0.9
2 6 1.2
2 9 2.5
3 0 2.7];
[u, idx_c, idx_f] = intersect(c(:, 1:2) , f(:, 1:2), 'rows');
n = [c(idx_c, :), f(idx_f, end)];
This should yield the desired result:
n =
1.0000 6.0000 2.5200 3.9000
1.0000 9.0000 0.8800 9.1000
2.0000 0 2.5800 0.3000
2.0000 3.0000 0.5300 0.9000
2.0000 6.0000 3.6900 1.2000
2.0000 9.0000 0.1800 2.5000
3.0000 0 3.2200 2.7000
According to this answer on Mathworks support you can use join from the statistics toolbox, specifically in your case, an inner join.
Unfortunately I don't have access to my computer with matlab on it, but give it a try and let us know how/if it works.
You can reduce the number of loops by comparing both the first and second columns of at once, then using the "all" function to only collapse the values if they both match. The following snippet replicates the "n" array you had provided.
n = [];
for r1 = 1:size(c, 1)
for r2 = 1:size(f,1)
if all(c(r1, [1 2]) == f(r2, [1 2]))
n(end+1, 1:4) = [c(r1,:) f(r2,3)];
end
end
end
If you insist on doing this in a loop you need to give n the proper dimension according
to the loop counter you are using, or concatenate it to itself of each iteration (this can be very slow for big matrices). For example, writing:
for j=1
for i=1:rs1
for k=1
for l=1:rs2
m=m+1;
if f(i,j)==c(l,k) && f(i,j+1)==c(l,k+1)
n(m,:)=[f(i,j),f(i,j+1),f(i,j+2), c(l,k+2)];
end
end
end
end
end
will save into the m-th row the for numbers when the loop reaches a counter value of m.
However, just be aware that this can be done also without a nested loop and an if condition, in a vectorized way. For example, instead of the condition if f(i,j)==c(l,k)... you can use ismember etc...
How about without any for loops at all (besides in native code)
mf = size(f,1);
mc = size(c,1);
a = repmat(c(:,1:2),1,mf);
b = repmat(reshape((f(:,1:2))',1,[]),mc,1);
match = a == b;
match = match(:, 1 : 2 : 2*mf) & match(:, 2 : 2 : 2*mf);
crows = nonzeros(diag(1:mc) * match);
frows = nonzeros(match * diag(1:mf));
n = [c(crows,:),f(frows,3)]

In the same order, finding an element in an array by comparing it with another array [duplicate]

I have a matrix
a = [ 1 'cancer'
2 'cancer'
3 'cancer'
4 'noncancer'
5 'noncancer' ]
I have another matrix with values
b = [ 4
5
2 ]
Now I have to compare the b matrix values with values of a and the output should be
output = [ 4 'noncancer'
5 'noncancer'
2 'cancer']
How can I do this in matlab ?
You can use ismember:
a = { 1 'cancer'
2 'cancer'
3 'cancer'
4 'noncancer'
5 'noncancer' };
b = [ 4
5
2 ];
a(ismember([a{:,1}], b),:)
This results in
ans =
[2] 'cancer'
[4] 'noncancer'
[5] 'noncancer'
To display the results in the order specified by b use (as requested in a follow-up question: In the same order, finding an element in an array by comparing it with another array)
[logicIDX, numIDX] = ismember(b, [a{:,1}]);
a(numIDX, :)
This results in:
ans =
[4] 'noncancer'
[5] 'noncancer'
[2] 'cancer'

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