Given two matrices of distinct sizes, say matrices A and B, how to quickly create a cell array to store them? I know how to do this using the standard way as the following.
c = cell(1,2);
c{1}=A,
c{2}=B;
Is there a better way? Basically, what I am asking is to initialize a given cell array quickly in matlab. Many thanks for your time and attention.
You can easily write the statement in one line with C = {A,B}. This creates a cell-array with two columns and one row.
Let's test it with random data:
A = rand(2,2);
B = rand(3,3);
C = {A,B}
This is the result:
C =
[2x2 double] [3x3 double]
In case you need two rows instead of two columns, just change the , to ; like you would do to create a 'normal' matrix.
A = rand(2,2);
B = rand(3,3);
C = {A;B}
This is the result:
C =
[2x2 double]
[3x3 double]
Otherwise you can directly do
C = {A,B};
Related
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])
I have a double value, A, which is
[1,4,7,6]
I also have B, which is an array that contains many more values. I have a new variable, C, which is essentially a double value of all these numbers (all of them in one cell, vs. five).
[1,4,7,6]
[2,6,9,12]
[3,1,17,13]
[5,7,13,19]
[1,5,9,15]
How do I remove the elements (not the actual values) from C? I want to end up with this.
[2,6,9,12,3,1,17,13,5,7,13,19,1,5,9,15]
How do I get this? I've used these commands:
C(A) = [];
and
C = C(setdiff(1:length(C),A));
The problem is that when I run that command, I get this instead of what I want.
[4,7,2,12,3,1,17,13,5,7,13,19,1,5,9,15]
Clearly that isn't the same as what I have. It's throwing off the rest of my results and I need to fix this specific issue.
Thanks in advance :)
EDIT:
So I figured out that it's spewing the CORRECT numbers out, just in the wrong order. I have to sort it in order for it to work correctly. This is a problem because it causes the next command to be non-functional because the ismember command has issues with the removal (I don't know why, I'm still working on it).
Double array case
If B is a double array, you can use setdiff with 'rows' and 'stable' options, like so -
C = reshape(setdiff(B,A,'rows','stable').',1,[])
With ismember, you can perform the same operation, like so -
C = reshape(B(~ismember(B,A,'rows'),:).',1,[])
You can also use a bsxfun approach as suggested by #Amro -
C = reshape(B(~all(bsxfun(#eq, B, A),2),:).',1,[])
Cell array case
If B is a cell array with number of elements in each cell equal to the number of elements in A, then you can firstly convert it to a double array - B = vertcat(B{:}) and then use either of the above mentioned tools.
Or you can use a cellfun based approach that avoids conversion to a double array, like so -
excl_rows = B(~cellfun(#(x1,x2) isequal(x1,x2), B, repmat({A},size(B,1),1)),:)
C = horzcat(excl_rows{:})
Or another cellfun based approach that avoids repmat -
exclB = B(~cellfun(#(x1) isequal(x1,A), B),:)
C = horzcat(exclB{:})
Example with explanation -
%// Inputs
A = [1,4,7,6]
B = {[1,4,7,6]
[2,6,9,12]
[3,1,17,13]
[5,7,13,19]
[1,5,9,15]}
%// Compare each cell of B with A for equality.
%// The output must be a binary array where one would be for cells that have
%// elements same as A and zero otherwise.
ind = cellfun(#(x1) isequal(x1,A), B)
%// Thus, ~ind would be a binary array where one would reperesent unequal
%// cells that are to be selected in B for the final output.
exclB = B(~ind)
%// exclB is still a cell array with the cells that are different from A.
%// So, concatenate the elements from exclB into a vector as requested.
C = horzcat(exclB{:})
Output -
A =
1 4 7 6
B =
[1x4 double]
[1x4 double]
[1x4 double]
[1x4 double]
[1x4 double]
ind =
1
0
0
0
0
exclB =
[1x4 double]
[1x4 double]
[1x4 double]
[1x4 double]
C =
2 6 9 12 3 1 17 13 5 7 13 19 1 5 9 15
I have defined a structures array as such:
oRandVecs = struct('vV',{[],[]},...
'ind_min',{[],[]},...
'mean',{[],[]},...
'vV_descending',{[],[]},...
'largest_diff',{[],[]});
oRandVecs(1).vV and oRandVecs(2).vv both get column vectors assigned to them. However, the problem is that the output is as follows:
>> oRandVecs(1)
ans =
vV: [4x1 double]
ind_min: 2
mean: 6.5500
vV_descending: [4x1 double]
largest_diff: 2.8000
Instead of actually showing the vector, it only describes its type.
What am I to do?
The reason why is because it's simply too big to display on the screen with that structure :) If you want to actually display it, use dot notation to display your data.
In other words, do this:
disp(oRandVecs(1).vV);
You can also do that with the other variable:
disp(oRandVecs(1).vV_descending);
The answer by rayryeng is probably the way to go.
An alternative is to convert from structure to cell and then use celldisp:
celldisp(struct2cell(oRandVecs(1)))
Example:
>> oRandVecs = struct('vV',{[],[]},...
'ind_min',{[],[]},...
'mean',{[],[]},...
'vV_descending',{[],[]},...
'largest_diff',{[],[]}); %// define empty struct
>> oRandVecs(1).vV = (1:4).'; %'// fill some fields: column vector, ...
>> oRandVecs(1).mean = 5:7; %// ... row vector, ...
>> oRandVecs(1).vV_descending = randn(2,3); %// ... matrix
>> celldisp(struct2cell(oRandVecs(1)))
ans{1} =
1
2
3
4
ans{2} =
[]
ans{3} =
5 6 7
ans{4} =
0.016805198757746 0.236095190511728 0.735153386198679
2.162769508502985 -0.158789830267017 0.661856091557715
ans{5} =
[]
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.
I have 2 columns of data imported from using textscan. The data looks like this where U is undetect and D is detect
mydata=
.51 U
.57 D
.48 U
.47 D
my data = [4x1 double] [4x1 char]
I want to sort the data by the first column and so the data would look like this
.47 D
.48 U
.51 U
.57 D
I would like to preserve the cell structure so that the following command to assign logical value still hold true:
c = zeros(size(mydata,1),1); % preallocate empty matrix
c = mydata{2} == 'U';
for i = 1:size(mydata,1)
curValue = mydata{i,2};
data{i,3} = ~isempty(curValue) && ischar(curValue) && strcmp(curValue ,'U');
end
I read about sortrows but the function is used to sort matrix containing just numbers.
Does anyone have a solution for sorting arrays with a mixture of numbers and characters.
You can SORT by one vector and apply the sorting index to another vector.
[mydata{1},idx] = sort(mydata{1});
mydata{2} = mydata{2}(idx);
I don't think you can directly sort the cell array, because each cell is considered a different "entity". You can always sort the numbers, use the indices to sort the characters, and then put it back in the cell array:
nums = mydata{1};
chars = mydata{2};
[~, ind] = sort(nums);
sortednums = nums(ind);
sortedchars = chars(ind);
mydata{1} = sortednums;
mydata{2} = sortedchars;