How to assign a matrix to a cell of a cell array - matlab

I'm working on matlab and try to assign a matrix to one cell of a cell array. However, there was always something wrong. Here is the code:
C = {};
myMatrix = xlsread('myexcelfile');
C{'ID', 'info'} = myMatrix;
Then matlab prompted that
"Expected one output from a curly brace or dot indexing expression, but there were 12 results."
But if I don't use 'ID' and 'Info' but use '1' and '2' instead, the matrix could be assigned successfully.
Could anyone help me? Thanks!

Assuming we have got three persons and each one has got a name and ID number and the data size that corresponds to each person is 2x3. I utilize a cell for storing data and fill it via random number.(In your case you should use xlsread('myexcelfile') to fill this cell). Each ID number is concatenated with a string because Matlab does not accept a string which is directly converted by number, for names in rows and columns of the table.
clc;clear all;close all;
% assuming we have got three persons in the dataset
cell_data=cell(3,3); % I use cell instead of matrix for storing data
ID_number=[38;48;58];% this vector contains the ID numbers of each person
for i=1:numel(ID_number);rng('shuffle');cell_data{i,i}=rand(2,3);end % using random number as dataset
ID=strcat('ID ',string(ID_number));%'38' is not a valid variable name so concat number with 'ID ' string
Customer = string({'Jones';'Brown';'Smith'});
Customer = cellstr(Customer);
T = table('RowNames',Customer);
for i=1:numel(ID_number)
T.(char(ID(i)))=cell_data(:,i);
end
%
After creating our table we can get input as follows:
input_cell = inputdlg({'Name','ID number'});% 2x1 cell
ID_input=strcat('ID ',input_cell{2,1});
T( {input_cell{1,1}} , {ID_input} )
And if the input formats are adapted to the table, we can get output like this:
table
ID48
____________
Brown [2×3 double]
You can add some conditions to the script for the cases that inputs are not adapted to the table format.

Related

How to make conditional calculations in a table using loop mechanisms?

I have the following table ('ABC'):
Goal: For each date, create 2 new variables (e.g. 'LSum' and 'USum'). 'LSum' should calculate the sum of all cell values across the column universe (4-281), but only with those values whose header is in the cell array of ABC.L, for that specific date. In the same fashion, 'USum' should calculate the sum of all cell values across the columns, but only with those values whose header is in the cell array of ABC.U, for that specific date.
% load content
load ('ABC.mat');
% run through every date, starting from the top
for row=1:size(ABC,1);
% for-loop for 'L' that determines for what specific cells (of col. 4-281) the following calculation has to be done: how?
% for-loop for 'U' that determines for what specific cells (of col. 4-281) the following calculation has to be done: how?
% now generate new variables
LSum = sum(); % But how can I use if clause here to select only eligible cells that enter into the sum calculation?
USum = sum(); % Same problem here as LSum
end;
% Concatenate table ABC and the newly formed variables into 1 table
ABC = [ABC(:,1:3) LSum USum ABC(:,3+1:end)];
Thanks for your help, especially for the looping through date and the cell arrays of 'L' and 'U' at the same time.
Possible way how to avoid loops is to utilize rowfun() function. Suppose we have table similar to yours.
Augment the table by column with table variable names.
tb = horzcat(tb,repmat({tb.Properties.VariableNames},1,height(tb))');
Define function which is applied onto every row.
function out = selectiveSum(varargin)
[~,~,sumColsId] = intersect(varargin{2},varargin{end});
out = sum(cell2mat(varargin(sumColsId)));
end
Run rowfun().
sums = rowfun(#selectiveSum,tb);
The function deals just with one selector array (L column). Add the second one and let the selectiveSum() return 1x2 vector.

Using Matlab to randomly split an Excel Sheet

I have an Excel sheet containing 1838 records and I need to RANDOMLY split these records into 3 Excel Sheets. I am trying to use Matlab but I am quite new to it and I have just managed the following code:
[xlsn, xlst, raw] = xlsread('data.xls');
numrows = 1838;
randindex = ceil(3*rand(numrows, 1));
raw1 = raw(:,randindex==1);
raw2 = raw(:,randindex==2);
raw3 = raw(:,randindex==3);
Your general procedure will be to read the spreadsheet into some matlab variables, operate on those matrices such that you end up with three thirds and then write each third back out.
So you've got the read covered with xlsread, that results in the two matrices xlsnum and xlstxt. I would suggest using the syntax
[~, ~, raw] = xlsread('data.xls');
In the xlsread help file (you can access this by typing doc xlsread into the command window) it says that the three output arguments hold the numeric cells, the text cells and the whole lot. This is because a matlab matrix can only hold one type of value and a spreadsheet will usually be expected to have text or numbers. The raw value will hold all of the values but in a 'cell array' instead, a different kind of matlab data type.
So then you will have a cell array valled raw. From here you want to do three things:
work out how many rows you have (I assume each record is a row) by using the size function and specifying the appropriate dimension (again check the help file to see how to do this)
create an index of random numbers between 1 and 3 inclusive, which you can use as a mask
randindex = ceil(3*rand(numrows, 1));
apply the mask to your cell array to extract the records matching each index
raw1 = raw(:,randindex==1); % do the same for the other two index values
write each cell back to a file
xlswrite('output1.xls', raw1);
You will probably have to fettle the arguments to get it to work the way you want but be sure to check the doc functionname page to get the syntax just right. Your main concern will be to get the indexing correct - matlab indexes row-first whereas spreadsheets tend to be column-first (e.g. cell A2 is column A and row 2, but matlab matrix element M(1,2) is the first row and the second column of matrix M, i.e. cell B1).
UPDATE: to split the file evenly is surprisingly more trouble: because we're using random numbers for the index it's not guaranteed to split evenly. So instead we can generate a vector of random floats and then pick out the lowest 33% of them to make index 1, the highest 33 to make index 3 and let the rest be 2.
randvec = rand(numrows, 1); % float between 0 and 1
pct33 = prctile(randvec,100/3); % value of 33rd percentile
pct67 = prctile(randvec,200/3); % value of 67th percentile
randindex = ones(numrows,1);
randindex(randvec>pct33) = 2;
randindex(randvec>pct67) = 3;
It probably still won't be absolutely even - 1838 isn't a multiple of 3. You can see how many members each group has this way
numel(find(randindex==1))

Convert cell array columns into matrix columns

I have a cell array (16x5) and I would like to extract all the values held in each column of the cell array and place them into a column within a matrix such that the columns are preserved (i.e. new matrix column for each cell array column).
What is the best way to do this?
I have tried:
for k=1:Samples
data(k,:) = [dist{:,k}];
end
But this returns the error
Subscripted assignment dimension mismatch.
However I am not sure why.
EDIT - Cell array structure:
Since your loop code is valid, I assume the error is being raised because data is preallocated with dimensions not matching the length of the comma-expanded dist column (Matlab will grow matrices with explicit indices but not with the : operator).
You just need to get the length of the data after the comma-separated expansion:
nElem = numel([dist{:,1}]);
Samples = size(dist,2);
data = zeros(Samples,nElem);
for k=1:Samples
data(k,:) = [dist{:,k}];
end
Or if you want it in columns
data = zeros(nElem,Samples);
for k=1:Samples
data(:,k) = [dist{:,k}]';
end

Adding 0's to cell array such that each column contains an equal number of entries - MATLAB

I have a 16x100 (varies in size) cell array and I would like to extract each of it's columns into a column of a matrix. When each column of the cell array contains an identical number of entries I can use:
elem = numel([dist{:,1}]);
repeat = size(dist,2);
data = zeros(elem,repeat);
for k=1:repeat
results(:,k) = [dist{:,k}]';
end
However there are some instances where there are not an equal number thus it returns the error:
Subscripted assignment dimension mismatch.
What is the best way around this? Is there a way to add zeroes to equalise the number of entries?
Perfect setup for bsxfun's masking capability here!
Now, I am assuming your data is setup as described in your previous question -
To solve the case of filling up "empty spaces" with zeros, you can setup an output array with maximum possible number of elements in each column and then fillup the valid spaces with the values from the input cell array, with the valid spaces being detected by the logical mask created with bsxfun. Read on through the comments inlined within the code listed next to find out the exact ideas on solving it -
%// Get the number of elements in each column of the input cell array
lens = sum(cellfun('length',a),1)
%// Store the maximum number of elements possible in any column of output array
max_lens = max(lens)
%// Setup output array, with no. of rows as max number of elements in each column
%// and no. of columns would be same as the no. of columns in input cell array
results = zeros(max_lens,numel(lens))
%// Create as mask that has ones to the "extent" of number of elements in
%// each column of the input cell array using the lengths
mask = bsxfun(#le,[1:max_lens]',lens) %//'
%// Finally, store the values from input cell array into masked positions
results(mask) = [a{:}]

regarding saving the numerical and string values altogether

I have a string matrix with N rows and 2 columns. Each cell stores a string. I have another N*1 vector, where each entry is a numerical value.
How can I save these two structures into a single text file row by row.
In other words, each row of the saved text file is composed of three elements, the first two elements come from a row of the string matrix and the third element comes from the corresponding row of that vector.
Thanks.
If I understand correctly, then fake data can be represented as this:
% Both have N=2 rows
strMat1 = {'a','b';'c','d';};
strMat2 = {1;2};
And if you want the output of this data to be a text file with:
ac1
bd2
Then you should do this:
txtOut = [];
if size(strMat1,1) == size(strMat2,1);
for row = 1:size(strMat1,1)
txtOut= [txtOut strMat1{:,row} num2str(strMat2{row}) '\n'];
end
else
disp('Size disagreement')
end
fid=fopen('textData.txt','wt');
fprintf(fid,txtOut)
It checks the vectors to make sure there are the same number of rows and then creates a txtOut string to be passed to a fprintf command.
Hope this helps! If you wanted the output to be spaced differently, just add spaces to the appending line in the form of ' ' .