Convert matrix to cell array of cell arrays - matlab

I want to change a matrix N*123456 to a cells of cells, each sub-cell contains a N*L matrix
Eg:
matrixSize= 50*123456
N=50
L=100
Output will be 1*1235 cell and each cell has a 50*L matrix (last cell has only 50*56)
I know there is a function mat2cell in matlab:
Output = mat2cell(x, [50], [100,100,100,......56])
But it doesn't sound an intuitive solution.
So is there a good solution?

If I understand you correctly, assuming your matrix is denoted m, this is what you wanted:
a=num2cell(reshape(m(:,1:size(m,2)-mod(size(m,2),L)),N*L,[]),1);
a=cellfun(#(n) reshape(n,N,L), a,'UniformOutput',false);
a{end+1}=m(:,end-mod(size(m,2),L)+1:end);
(this can be shortened to a single line if you wish)...
Lets test with some minimal numbers:
m=rand(50,334);
N=50;
L=100;
yields:
a =
[50x100 double] [50x100 double] [50x100 double] [50x34 double]
note that I didn't check for the exact dimension in the reshape, so you may need to reshape to ...,[],N*L) etc.

Just use elementary maths.
q = floor(123456/100);
r = rem(123456,100);
Output = mat2cell(x, 50, [repmat(100,1,q),r])

Related

Extract data from a Cell Array using a vector and converting into an array

I have a cell array [5x1] which all cells are column vectors such as:
exInt =
[46x1 double]
[54x1 double]
[40x1 double]
[51x1 double]
[ 9x1 double]
I need to have a vector (vec) containing the cells in extInt I need to extract and then I have to convert these into a single column array. Such as:
vec = [1,3];
Output = cell2mat(extInt{vec})
Output should become something an array [86x1 double].
The way I have coded I get:
Error using cell2mat
Too many input arguments.
If possible, I would like to have a solution not using a loop.
The best approach here is to use cat along with a comma-separted list created by {} indexing to yield the expected column vector. We specify the first dimension as the first argument since you have all column vectors and we want the output to also be a column vector.
out = cat(1, extInt{vec})
Given your input, cell2mat attempts to concatenate along the second dimension which will fail for your data since all of the data have different number of rows. This is why (in your example) you had to transpose the data prior to calling cell2mat.
Update
Here is a benchmark to compare execution times between the cat and cell2mat approaches.
function benchit()
nRows = linspace(10, 1000, 100);
[times1, times2] = deal(zeros(size(nRows)));
for k = 1:numel(nRows)
rows = nRows(k);
data = arrayfun(#(x)rand(randi([10, 50], 1), 1), 1:rows, 'uni', 0);
vec = 1:2:numel(data);
times1(k) = timeit(#()cat_method(data, vec));
data = arrayfun(#(x)rand(randi([10, 50], 1), 1), 1:rows, 'uni', 0);
vec = 1:2:numel(data);
times2(k) = timeit(#()cell2mat_method(data, vec));
end
figure
hplot(1) = plot(nRows, times1 * 1000, 'DisplayName', 'cat');
hold on
hplot(2) = plot(nRows, times2 * 1000, 'DisplayName', 'cell2mat');
ylabel('Execution Times (ms)')
xlabel('# of Cell Array Elements')
legend(hplot)
end
function out = cat_method(data, vec)
out = cat(1, data{vec});
end
function out = cell2mat_method(data, vec)
out = cell2mat(data(vec)');
end
The reason for the constant offset between the two is that cell2mat calls cat internally but adds some additional logic on top of it. If you just use cat directly, you circumvent that additional overhead.
You have a small error in your code
Change
Output = cell2mat(extInt{vec});
to
Output = cell2mat(extInt(vec));
For cells, both brackets and parentheses can be used to get information. You can read some more about it here, but to summarize:
Use curly braces {} for setting or getting the contents of cell arrays.
Use parentheses () for indexing into a cell array to collect a subset of cells together in another cell array.
In your example, using brackets with index vector vec will produce 2 separate outputs (I've made a shorter version of extInt below)
extInt = {[1],[2 3],[4 5 6]};
extInt{vec}
ans =
1
ans =
4 5 6
As this is 2 separate outputs, it will also be 2 separate input to the function cell2mat. As this function only takes one input you get an error.
One alternative is in your own solution. Take the two outputs and place them inside a new (unnamed) cell
{extInt{vec}}
ans =
[1] [1x3 double]
Now, this (single) result goes into cell2mat without a problem.
(Note though that you might need to transpose your result before depending on if you have column or row vectors in your cell. The size vector (or matrix) to combine need to match/align.)
Another way as to use parentheses (as above in my solution). Here a subset of the original cell is return. Therefore it goes directly into the cell2matfunction.
extInt(vec)
ans =
[1] [1x3 double]
I have been messing around and I got this working by converting this entry into a new cell array and transposing it so the dimensions remained equivalent for the concatenating process
Output = cell2mat({extInt{vec}}')
use
Output = cell2mat(extInt(vec))
Since you want to address the cells in extInt not the content of the cells
extInt(vec)
extInt{vec}
try those to see whats going on

How to do dot product in a cell array in MATLAB?

I have a cell array (C) containing 5 matrices. Each matrix represents different set of vectors (i.e. Each matrix has two columns. One is x coordinate; the other is y coordinate. The row number varying depends on the number of vectors)
C{1} = [20x2 double];
C{2} = [23x2 double];
C{3} = [32x2 double] ...
In this case, there are 20 vectors in C{1}; 23 vectors in C{2} and so on. Is there any way (other than one or two for loop)to do the dot product for the two adjacent vectors for each matrix?
C{1} = [2,3; 1,2; 5,4; 8,3; ...]
calculate the dot product for [2,3]&[1,2] then [1,2]&[5,4] then [5,4]&[8,3] and so on.
So at the end, I would expect to get a cell array with 5 cells. Each cell is an [n-1,1] array (n is the length of the matrix).
dots = [5x1 cell].
dots{1} = [19x1 double];
dots{2} = [22x1 double];
dots{3} = [31x1 double] ...
You can use cellfun to compute the dot product between each coordinate (row) and the next coordinate (row).
dots = cellfun(#(x)dot(x(1:end-1,:), x(2:end, :), 2), C, 'uniform', 0)
Explanation
We grab the first rows to compare using x(1:end-1,:) and then want to perform the dot product with the next row x(2:end,:). When performing the dot product, we want to specify that we want the dot product along the second dimension so we provide a 2 for the third input to dot.
dp = dot(C{1}(1:end-1,:), C{1}(2:end,:), 2);
We use cellfun to perform this on each cell array element.
Example
C = {rand(10,2), rand(20,2), rand(30,2), rand(40, 2), rand(50,2)};
dots = cellfun(#(x)dot(x(1:end-1,:), x(2:end, :), 2), C, 'uniform', 0)
[9x1 double] [19x1 double] [29x1 double] [39x1 double] [49x1 double]

Matlab - Two Column Matrices into One Column Matrix with rows elements

I have two column matrices:
size(X) = 50 x 1
size(Y) = 50 x 1
which I got from ind2sub
I want to create a structure str such that
str(i).XYZ returns [X(i), Y(i)] for i in [1,50]
I am trying to use
str = struct('XYZ', num2cell([X,Y]));
However, I believe for this to work properly, I need to modify [X,Y] to a matrix of row vectors, each row vector being [X(i), Y(i)]. Not sure if there is a better approach
You are basically on the right way, but num2cell([X,Y]) creates a 2x50 cell, which results in a 2x50 struct. You want to split your input matrix [X,Y] only among the second dimensions so each cell is a 2x1, use num2cell([X,Y],2)
str = struct('XYZ', num2cell([X,Y],2));
Concatenate the two vectors, convert from matrix to cell, and then from cell to struct array:
str = cell2struct(mat2cell([X Y], ones(1,size(X,1)), size(X,2)+size(Y,2) ).', 'XYZ');

double array in cell, how to indexing?

I have an cell including array as below format
a{x,y,z}(i,j)
a is 3 dimensional cell
and
each cell have i*j array
a <79x95x68 cell>
val(:,:,1) =
Columns 1 through 2
[6x6 double] [6x6 double]
[6x6 double] [6x6 double]
[6x6 double] [6x6 double]
i want to rearrange that as below format
a{i,j}(x,y,z)
how to? any good idea? i have to do iteration?
matlab say, a{:,:}(x,y,z) is bad cell referencing.........
here's a suboptimal way to go, it isn't memory efficient, but it is pretty straightforward:
say that x=79,y=95,z=68 are the dimensions of your original cell array, and that each of them gives the same dimensionality ixj matrix (6 by 6). So first you can make a matrix out of the cell array:
b=horzcat(a{:});
then we can reshape it to a 5-d array (this is just for pedagogical purposes) so you already have it ordered as (i,j,x,y,z)...
c=reshape(b,6,6,x,y,z);
then you can either work with c(i,j,x,y,z), or assign c to a cellarray:
d=cell(6,6);
for i=1:6
for j=1:6
d{i,j}=squeeze(c(i,j,:,:,:));
end
end

splitting a matlab matrix into several equal parts

I have a matrix of size 64500x17. It represents detected texton features that I have to use to find 5 centroids for kmeans.
What I need is:
split this matrix into 5 12900x17 matrices
find the means
concatenate these into a 5x17 matrix to feed in to the start parameter of kmeans.
I know how to do almost everything (cat, kmeans, etc), but I am merely trying to find a method for splitting the matrix into 5 parts, or summing/dividing into the desired size.
I am forbidden from overusing for loops (due to efficiency), unless absolutely necessary.
I can't find any pertinent example in other questions, so if this has been answered, please bear with me.
You can use mat2cell and this oneliner
C = mat2cell(A, repmat(12900, 5, 1), 17);
The second parameter to mat2cell is the row split of the matrix.
Now C is a cell array:
C =
[12900x17 double]
[12900x17 double]
[12900x17 double]
[12900x17 double]
[12900x17 double]
and the partial matrices can be accessed as
C{1} etc.
Just use indexing and store the extracted matrices in cells for easier handling:
data = rand(64500,17);
Nsubsets = 5;
Nsubsize = size(data,1)/Nsubsets;
splitted_data = cell(Nsubsets ,1);
splitted_data_means = cell(Nsubsets,1);
for ii=1:Nsubsets
splitted_data{ii} = data((ii-1)*Nsubsize + (1:Nsubsize),:);
splitted_data_means{ii} = mean(splitted_data{ii});
end
you can then join these means with:
joined_means = cell2mat(splitted_data_means);
Or just for the heck-of-it with the one-liner:
joined_means = cell2mat(arrayfun(#(ii) mean(data((ii-1)*12900+(1:12900),:)),(1:5)','uni',false));
which would be even simpler with #angainor's mat2cell:
joined_means = cell2mat(cellfun(#mean,mat2cell(data, 12900*ones(5,1), 17),'uni',false));
To take the first submatrix use colon notation:
A(1:12900,:)
then
A(12901:12900*2,:)
and so on.
The probably fastest solution is:
data = rand(64500,17);
Nsubsets = 5;
Nsubsize = size(data,1)/Nsubsets;
joined_means=squeeze(mean(reshape(data,Nsubsize,Nsubsets,size(data,2)),1));
Split the first and second dimension, then you can calculate the mean over the first dimension of Nsubsets elements each.