Manipulate values in Matlab cell array - matlab

Suppose I have a 3x1 cell array called subj that has the following elements:
cell 1: 300x20 double
cell 2: 300x15 double
cell 3: 300X18 double
I want to remove the last quarter rows from every element in each cell as follows:
subj{1}(length(subj{1})*0.25+1:end,:) = []
subj{2}(length(subj{2})*0.25+1:end,:) = []
subj{3}(length(subj{3})*0.25+1:end,:) = []
However I want to be do this in one line and can't figure out a way to do this in Matlab. I messed around with converting the cell array to a matrix, but since there different numbers of columns, it makes it slightly more complicated. Is there a vectorized way to do this in one line? I will be applying machine learning algorithms to each element of subj and it would be great to have this be vectorized for later parts of my code.

Better not assigning empty arrays to a matrix (actually that doesn't work) but reassign the matrix itself:
% loop over the cell array
for i = 1:length(subj)
% determine the index/number of rows. Don't forget to round as MATLAB requires integers for slicing!
idx = round( length(subj{i})*0.25 );
% get the new matrix
NewMat = subj{i}(1:idx,:);
% assign new matrix to the old address, i.e. the content of the cell
subj{i} = NewMat;
end
MATLAB allocates contiguous memory for matrices, so cropping it shouldn't cause much overhead. In particular not as it uses "lazy copying" and; therefore, only copies the matrix when you change any of its values.

Related

Pre-Allocating Single Cell's Memory

I am writing a code and would like to know how to pre-allocate the memory for a single cell. I understand that one can easily pre-allocate an array of cells, but this isn't what I'm looking for.
My code follows the following logic:
for i = 1:numel(k)
R{i} = % Some 4x4 matrix That changes each iteration
end
R = blkdiag(R{:});
The goal here is to build a comma-separated list of an arbitrary amount of matrices, say:
R = {A,B,C,D,E,...}
Such that blkdiag will return the following:
R = [A 0 0...
0 B 0...
0 0 C...
... ]
The code I have right now works fine, I'd just like to know how to pre-allocate memory for this case such that it runs faster if I had an awful lot of matrices.
Putting a matrix into a cell array doesn't cause the cell array to be resized, if your cell array was preallocated. R = cell(numel(k),1) will preallocate the cell array. Each element of this array is a reference to an array (or arbitrary type, could be a numeric array, another cell array, a struct array, an array of custom objects, doesn't matter).
When the cell array is first created, each cell contains an empty matrix, []. Replacing this matrix just changes the reference stored in the cell array to point to a different array. R{3} = x doesn't reallocate memory, it only changes the reference in R{3} to now point to whatever matrix was stored in the variable x.
On the other hand, if you want to add values to the array stored in R{3}, you should preallocate that array:
R{3} = zeros(5,1); % preallocate the array pointed to by R{3}
for ii=1:5
R{3}(ii) = ii;
end

MATLAB automatically assigns unwanted dimensions to a dynamically updated cell array

I want to generate a 3D cell array called timeData so that timeData(:,:,a) for some integer a is an nx1 matrix of data, and the number of rows n varies with the value of a in a 1:1 correspondence. To do this, I am generating a 2D array of data called data that is nx1. This assignment statement takes place within a for loop as follows:
% Before iterating, I define an array of indices where I want to store the
% data sets in timeData. This choice of storage location is for
% organizational purposes.
A = [2, 5, 9, 21, 34, 100]; % Notice they are in ascending order, but have
% gaps that have no predictability.
sizeA = size(A);
numIter = A(1);
for m = 1:numIter % numIter is the number of data sets that I need to store
% in timeData
% At this point, some code that is entirely irrelevant to my question
% generates a nx1 array of data. One example of this data array is below.
data = [1.1;2.3;5.5;4.4]; % This is one example of what data could be. Its
% number of rows, n, changes each iteration, as
% do its contents.
B = size(data);
timeData(1:B(1),1,A(m)) = num2cell(data);
end
This code does put all contents of data in the appropriate locations within timeData as I want. However, it also adds {0x0 double} rows to all 2D arrays of timeData(:,:,a) for any a whose corresponding number of rows n was not the largest number of rows. Thus, there are many of these 2D arrays that have 10 to a couple hundred 0-valued rows that I don't want. For values of a that did not have a corresponding data set, the content of timeData(:,:,a) is an nx1 array of {0x0 double}.
I need to iterate over the contents of timeData in subsequent code, and I need to be able to find the size of the data set that is in timeData(:,:,a) without somehow discounting all the {0x0 double}.
How can I modify my assignment statement to fix this?
Edit: Desired output of the above example is the following with n = 5. Let this data set be represented by a = 9.
timeData(:,:,9) = {[1.1]}
{[2.3]}
{[5.5]}
{[8.6]}
{[4.4]}
Now, consider the possibility that a previous or subsequent value of the A matrix had a data set with n = 7, and n = 7 is the largest data set (largest n value). timeData(:,:,9) outputs like so in my code:
timeData(:,:,9) = {[1.1]}
{[2.3]}
{[5.5]}
{[8.6]}
{[4.4]}
{[0x0 double]}
{[0x0 double]}
#Dev-iL, as I understand it, your answer gives me the ability to delete the cells that have {[0x0 double]} in them (this is what I mean by "discounting"). This is a good plan B, but is there a way to prevent the {[0x0 double]} cells from showing up in the first place?
Edit 2: Update to the above statement "your answer gives me the ability to delete the cells that have {[0x0 double]} in them (this is what I mean by "discounting")". The cellfun(#isempty... ) function makes the {[0x0 double]}cells go to {[0x0 cell]}, it does not remove them. In other words, size(timeData(:,:,9)) is the same before and after the command is performed. This is not what I want. I want size(timeData(:,:,9)) to be 5x1 no matter what n is for any other value of a.
Edit 3: I just realized that the most desired output would be the following:
timeData(:,:,9) = {[1.1;2.3;5.5;8.6;4.4]} % An n x 1 column matrix within
% the cell.
but I can work with this outcome or the outcome as described above.
Unfortunately, I don't understand the structure of your dataset, which is why I can't suggest a better assignment method. However, I'd like to point out an operation that can you help deal with your data after it's been created:
cellfun(#isempty,timeData);
What the above does is return a logical array the size of timeData, indicating which cells contain something "empty". Typically, an array of arbitrary datatype is considered "empty" when it has at least one dimension that is equal to 0.
How can you use it to your advantage?
%% Example 1: counting non-empty cells:
nData = sum(~cellfun(#isempty,timeData(:)));
%% Example 2: assigning empty cells in place of empty double arrays:
timeData(cellfun(#isempty,timeData)) = {{}};

Avoid looping in matlab when creating cells containing cell arrays

I'm trying to create a map that has two-element cell arrays as values. Map expects that keys and values have the same number of elements. This code packs those cell arrays into cells in a loop, but I'm suspecting that it can be simplified somehow. Example code:
cells1={'foo1';'foo2';'foo3'};
cells2={'bar1';'bar2';'bar3'};
cells3={'baz1';'baz2';'baz3'};
values=cell(size(cells1));
for ii=1:size(cells1,1)
values{ii}={{cells2{ii},cells3{ii}}};
end
keys=cells1;
containers.Map(keys,values);
you can use vector concatenation and num2cell with 2nd dimension argument (twice if you want to obtain identical result):
% your code
cells1={'foo1';'foo2';'foo3'};
cells2={'bar1';'bar2';'bar3'};
cells3={'baz1';'baz2';'baz3'};
values=cell(size(cells1));
for ii=1:size(cells1,1)
values{ii}={{cells2{ii},cells3{ii}}};
end
% simplified
c = num2cell(num2cell([cells2,cells3],2),2);
% you can also do c = num2cell([cells2,cells3],2); which isn't identical but may be suficcient
isequal(c,values) % yes

How to compare two cell elements in matlab?

I am using two cells for storing the targeted and the expected value of a neural network process in matlab. I have used two 1*1 cell array for storing the values respectively. And here is my code.
cinfo=cell(1,2)
cinfo(1,1)=iter(1,10)%value is retrieved from a dataset iter
cinfo(1,2)=iter(1,11)
amp1=cinfo(1,1);
amp2=cinfo(1,2);
if amp1 == amp2
message=sprintf('NOT DETECTED BY THE DISEASE');
uiwait(msgbox(message));
But when i run the above code, the get the following error :
??? Undefined function or method 'eq' for input arguments of type 'cell'.
Error in ==> comparison at line 38
if amp1 == amp2
How to solve this problem?
The problem is how you indexed things. A 1x1 cell array does not make a lot of sense, instead get the actual element in the single cell, by indexing with curly brackets:
amp1=cinfo{1,1}; # get the actual element from the cell array, and not just a
amp2=cinfo{1,2}; # 1x1 cell array by indexing with {}
if (amp1 == amp2)
## etc...
However, note that if amp1 and amp2 are not scalars the above will act weird. Instead, do
if (all (amp1 == amp2))
## etc...
Use isequal. That will work even if the cell's contents have different sizes.
Example:
cinfo=cell(1,2);
cinfo(1,1) = {1:10}; %// store vector of 10 numbers in cell 1
cinfo(1,2) = {1:20}; %// store vector of 20 numbers in cell 2
amp1 = cinfo(1,1); %// single cell containing a length-10 numeric vector
amp2 = cinfo(1,2); %// single cell containing a length-20 numeric vector
if isequal(amp1,amp2)
%// ...
In this example, which parallels your code, amp1 and amp2 are cell arrays consisting of a single cell which contains a numeric vector. Another possibility is to directly store each cell's contents into amp1, amp2, and then compare them:
amp1 = cinfo{1,1}; %// length-10 numeric vector
amp2 = cinfo{1,2}; %// length-20 numeric vector
if isequal(amp1,amp2)
%// ...
Note that even in this case, the comparisons amp1==amp1 or all(amp1==amp2) would give an error, because the vectors have different sizes.

How to add elements to a vector in a loop

Let's say I have a cell array raweeg each cell of which is a matrix with time points in the first column and some markers in the second. I want to create a vector to store the time points, when the marker is not equal to -1. I found a non-elegant (and not working) way to create a vector of zeros of size 1x1 and then to append the following values in a loop.
P.S.: There are exactly 96 non-"-1" values and corresponding time points.
startpoints = zeros(1,1);
for i = length(raweeg{1,1}(:,1))
if raweeg{1,1}(i,2) ~= -1
startpoints(end+1,1) = raweeg{1,1}(i,1);
end
end
Thank you
Vectorize it like this, for a given cell of raweeg:
startpoints = raweeg{1,1}(raweeg{1,1}(:,2) ~= -1, 1);
This is called logical indexing.
Just be sure your markers are not generated with floating point computations, or the comparisons will likely fail often.
P.S. The problem in your code is the for loop statement, which should be:
for i = 1:length(raweeg{1,1}(:,1))
Or better, for i = 1:size(raweeg{1,1},1).
With out the "1:" part, it just has a single iteration, the last row.