Accessing data from cell arrays at the same time - matlab

If A is a (x,y) cell array having n cells and each of them is a vector of size (m,n) and of type double.
Example: If A is a 1x2 cell array
A =
[100x1 double] [100x1 double]
Suppose I want to access the first element of each cells at the same time, how can we do so?
Similarly, if we need to access the ith element from every cell, how do we generalise the code?

cell creation with two 1*10 arrays:
A {1} = zeros(1,10) ;
A {2} = zeros (1,10) ;
A =
[1x10 double] [1x10 double]
Adding some data which will be used for fetching later:
A {1}(5) = 5 ;
A {2}(5) = 10 ;
Routine to fetch the data at same index from both arrays inside cell:
cellfun (#(x) x(5),A)
ans =
5 10

As User1551892 suggested, you could use cellfun. Another way is to restruct the cell to a matrix first.
The speed on the operation depends on the number of cells and the size of the matrix within each cell.
% Number of cells
x = 3;
y = 2;
% Size of matrix
m = 1;
n = 100;
% Add some random numbers
A = cell(x,y);
for i = 1:numel(A)
A{i} = round(rand(m,n)*100);
end
% Index to pick in each matrix
idx = 5;
% Convert to matrix
B = [A{:}];
% Pick the number
val = B(idx:(n*m):end);
Doing som tic-toc measurements, the method above is faster for the example values. As long as the one of n or m is small the method is ok.
But if both m and n grows large, cellfun is better (faster)
val = cellfun(#(x) x(idx), A);

An alternative way would be to simply access the cell elements directly , for example we have a cell like you defined
A{1}(1:10) = randi([2 5],1,10);
A{2}(1:10) = randi([2 5],1,10);
now if you want to access the ith elements simply declare i and they will be retrieved in the matrix below
i = 3;
ObsMatrix = [A{1}(i) A{2}(i)]
ObsMatrix =
2 5
If A has unknown number of cell you can simply use a for loop , It will pick ith element from every cell index and put it in ObsMat
i = 3;
for j=1:numel(A)
ObsMat(end + 1) = A{j}(3);
end
cellfun is also a wrapper function for for loop
ObsMat =
2 5

Related

How to make calculations on certain cells (within a table) that meet specific criteria?

I have the following code:
L_sum = zeros(height(ABC),1);
for i = 1:height(ABC)
L_sum(i) = sum(ABC{i, ABC.L(i,4:281)});
end
Here my table:
Problem: My sum function sums the entire row values (col. 4-281) per date whereas I only want those cells to be added whose headers are in the cell array of ABC.L, for any given date.
X = ABC.L{1, 1}; gives (excerpt):
Red arrow: what sum function is referencing (L of same date).
Green arrow: what I am trying to reference now (L of previous date).
Thanks for your help
In general, in matlab you dont need to use for loops to do simple operations like selective sums.
Example:
Data=...
[1 2 3;
4 5 6;
7 8 9;
7 7 7];
NofRows=size(Data,1);
RowsToSum=3:NofRows;
ColToSum=[1,3];
% sum second dimension 2d array
Result=sum(Data(RowsToSum,ColToSum), 2)
% table mode
DataTable=array2table(Data);
Result2=sum(DataTable{RowsToSum,ColToSum}, 2)
To do that you need to first extract the columns you want to sum, and then sum them:
% some arbitrary data:
ABC = table;
ABC.L{1,1} = {'aa','cc'};
ABC.L{2,1} = {'aa','b'};
ABC.L{3,1} = {'aa','d'};
ABC.L{4,1} = {'b','d'};
ABC{1:4,2:5} = magic(4);
ABC.Properties.VariableNames(2:5) = {'aa','b','cc','d'}
% summing the correct columns:
L_sum = zeros(height(ABC),1);
col_names = ABC.Properties.VariableNames; % just to make things shorter
for k = 1:height(ABC)
% the following 'cellfun' compares each column to the values in ABC.L{k},
% and returns a cell array of the result for each of them, then
% 'cell2mat' converts it to logical array, and 'any' combines the
% results for all elements in ABC.L{k} to one logical vector:
col_to_sum = any(cell2mat(...
cellfun(#(x) strcmp(col_names,x),ABC.L{k},...
'UniformOutput', false).'),1);
% then a logical indexing is used to define the columns for summation:
L_sum(k) = sum(ABC{k,col_to_sum});
end

Random permutation of each cell in a cell array

I have a 1-by-4 cell array, D. Each of the cell elements contains 2-by-2 double matrices. I want to do random permutation over each matrix independently which in result I will have the same size cell array as D but its matrices' elements will be permuted and then the inverse in order to obtain the original D again.
for a single matrix case I have the code and it works well as follows:
A=rand(3,3)
p=randperm(numel(A));
A(:)=A(p)
[p1,ind]=sort(p);
A(:)=A(ind)
but it doesn't work for a cell array.
The simplest solution for you is to use a loop:
nd = numel(D);
D_permuted{1,nd} = [];
D_ind{1,nd} = [];
for d = 1:nd)
A=D{d};
p=randperm(numel(A));
A(:)=A(p)
[~,ind]=sort(p);
D_permuted{d} = A;
D_ind{d} = ind;
end
Assuming your D matrix is just a list of identically sized (e.g. 2-by-2) matrices, then you could avoid the loop by using a 3D double matrix instead of the cell-array.
For example if you hade a D like this:
n = 5;
D = repmat([1,3;2,4],1,1,n)*10 %// Example data
Then you can do the permutation like this
m = 2*2; %// Here m is the product of the dimensions of each matrix you want to shuffle
[~,I] = sort(rand(m,n)); %// This is just a trick to get the equivalent of a vectorized form of randperm as unfortunately randperm only accepts scalars
idx = reshape(I,2,2,n);
D_shuffled = D(idx);

How to store results created into a cell array during a multiple for loop into a 3d array? In Matlab

In Matlab, at the end of three different for loops (for a=1:240,b=1:5 and c=1:3), I generate a {1,3} cell array where each cell contains a (1,5) array that reports only the last result of the 240 iterations.
How can I generate, apart of this cell array, a (240,5,3) 3d array that stores the result of each iteration?
Or, equivalently, a cell array that stores again the information and then convert it into a (240,5,3) 3d array?
The code would be along the lines of:
%// Size of the problem
Na = 240;
Nb = 5;
Nc = 3;
%// Allocate empty cell array
result = cell(Na, Nb, Nc);
%// Loop
for a = 1:Na
for b = 1:Nb
for c = 1:Nc
%// Here is the code for computing the
%// result x of the last iteration.
result{a,b,c} = x;
end;
end;
end;

Matlab Mean over same-indexed elements across cells

I have a cell array of 53 different (40,000 x 2000) sparse matrices. I need to take the mean over the third dimension, so that for example element (2,5) is averaged across the 53 cells. This should yield a single (33,000 x 2016) output. I think there ought to be a way to do this with cellfun(), but I am not able to write a function that works across cells on the same within-cell indices.
You can convert from sparse matrix to indices and values of nonzeros entries, and then use sparse to automatically obtain the sum in sparse form:
myCell = {sparse([0 1; 2 0]), sparse([3 0; 4 0])}; %// example
C = numel(myCell);
M = cell(1,C); %// preallocate
N = cell(1,C);
V = cell(1,C);
for c = 1:C
[m n v] = find(myCell{c}); %// rows, columns and values of nonzero entries
M{c} = m.';
N{c} = n.';
V{c} = v.';
end
result = sparse([M{:}],[N{:}],[V{:}])/C; %'// "sparse" sums over repeated indices
This should do the trick, just initialize an empty array and sum over each element of the cell array. I don't see any way around using a for loop without concatenating it into one giant 3D array (which will almost definitely run out of memory)
running_sum=zeros(size(cell_arr{1}))
for i=1:length(cell_arr)
running_sum=running_sum+cell_arr{i};
end
means = running_sum./length(cell_arr);

How to divide a data arry into blocks like this using a FOR loop?

How to divide a data array into blocks like this using a for loop?
Please consider my sample code:
a = -1-j; b = 2-j; % some constants
data = a+(b-a)*rand(1,256); % data
b=[1,2,4,8,16] % number of blocks
How to divide my data into blocks b=[1,2,4,8,16] in a adjacent grouping of data indices like this using a for loop running over b:
out1=1x256=same as data(1x256)(no division into blocks)
out2=[data(1:128) zeros(1,128);zeros(1,128) data(129:256)]; % 2x256
out4=[ data(1:64) zeros(1,192); % 4x256
zeros(1,64) data(65:128) zeros(1,128);
zeros(1,128) data(129:192) zeros(1,64);
zeros(1,192) data(193:256)];
out8= [ data(1:32) zeros(1,224); % 8x256
zeros(1,32) data(33:64) zeros(1,192);
zeros(1,64) data(65:96) zeros(1,160);
zeros(1,96) data(97:128) zeros(1,128)
zeros(1,128) data(129:160) zeros(1,96);
zeros(1,160) data(161:192) zeros(1,64);
zeros(1,192) data(193:224) zeros(1,32);
zeros(1,224) data(225:256)];
Similarly,
out16=[data(1:16) zeros(17,240); % 16x256
zeros(1,16) data(17:32) zeros(1,224);
...
... ]
No need for a loop. Use linear indexing to address the entries that need to be written with the data:
n = 4; %// n arbitrary, but should divide k
k = length(data);
outn = zeros(n,k); %// initialize
cols = 1:k; %// column indices: 1 2 3 ... k
rows = floor(0:n/k:n-n/k)+1; %// row indices: 1 1 ... 1 2 2 ... 2 3 ...
outn(rows+n*(cols-1)) = data; %// write data into those rows and cols
First of all, it requires a matrix which indicates where the data belongs:
z=size(data,2);
s=bsxfun(#(x,y)(floor(x)==y),[1:b/z:(b+1-b/z)],[1:b]');
Now we can use this matrix to fill out
out=zeros(b,z);
out(s)=data;
Complete code:
a = -1-j; b = 2-j; z=256; % some constants
data = a+(b-a)*rand(1,z); % data
out={};
for b=[1,2,4,8,16]
s=bsxfun(#(x,y)(floor(x)==y),[1:b/z:(b+1-b/z)],[1:b]');
out{end+1}=zeros(b,z);
out{end}(s)=data;
end
With a comma-separated list from the {:} cell array indexing syntax, you can use blkdiag directly to generate the output matrix. Just use mat2cell to segment data. Used in a loop over each value of b:
N = numel(data); % ensure data is a row vector
out={};
for b = [1 2 4 8 16],
dataCell = mat2cell(data,1,(N/b)*ones(1,b));
out{end+1} = blkdiag(dataCell{:});
end