I am writing a code to do some very simple descriptive statistics, but I found myself being very repetitive with my syntax.
I know there's a way to shorten this code and make it more elegant and time efficient with something like a for-loop, but I am not quite keen enough in coding (yet) to know how to do this...
I have three variables, or groups (All data, condition 1, and condition 2). I also have 8 matlab functions that I need to perform on each of the three groups (e.g mean, median). I am saving all of the data in a table where each column corresponds to one of the functions (e.g. mean) and each row is that function performed on the correspnding group (e.g. (1,1) is mean of 'all data', (2,1) is mean of 'cond 1', and (3,1) is mean of 'cond 2'). It is important to preserve this structure as I am outputting to a csv file that I can open in excel. The columns, again, are labeled according the function, and the rows are ordered by 1) all data 2) cond 1, and 3) cond 2.
The data I am working with is in the second column of these matrices, by the way.
So here is the tedious way I am accomplishing this:
x = cell(3,8);
x{1,1} = mean(alldata(:,2));
x{2,1} = mean(cond1data(:,2));
x{3,1} = mean(cond2data(:,2));
x{1,2} = median(alldata(:,2));
x{2,2} = median(cond1data(:,2));
x{3,2} = median(cond2data(:,2));
x{1,3} = std(alldata(:,2));
x{2,3} = std(cond1data(:,2));
x{3,3} = std(cond2data(:,2));
x{1,4} = var(alldata(:,2)); % variance
x{2,4} = var(cond1data(:,2));
x{3,4} = var(cond2data(:,2));
x{1,5} = range(alldata(:,2));
x{2,5} = range(cond1data(:,2));
x{3,5} = range(cond2data(:,2));
x{1,6} = iqr(alldata(:,2)); % inter quartile range
x{2,6} = iqr(cond1data(:,2));
x{3,6} = iqr(cond2data(:,2));
x{1,7} = skewness(alldata(:,2));
x{2,7} = skewness(cond1data(:,2));
x{3,7} = skewness(cond2data(:,2));
x{1,8} = kurtosis(alldata(:,2));
x{2,8} = kurtosis(cond1data(:,2));
x{3,8} = kurtosis(cond2data(:,2));
% write output to .csv file using cell to table conversion
T = cell2table(x, 'VariableNames',{'mean', 'median', 'stddev', 'variance', 'range', 'IQR', 'skewness', 'kurtosis'});
writetable(T,'descriptivestats.csv')
I know there is a way to loop through this stuff and get the same output in a much shorter code. I tried to write a for-loop but I am just confusing myself and not sure how to do this. I'll include it anyway so maybe you can get an idea of what I'm trying to do.
x = cell(3,8);
data = [alldata, cond2data, cond2data];
dfunction = ['mean', 'median', 'std', 'var', 'range', 'iqr', 'skewness', 'kurtosis'];
for i = 1:8,
for y = 1:3
x{y,i} = dfucntion(i)(data(1)(:,2));
x{y+1,i} = dfunction(i)(data(2)(:,2));
x{y+2,i} = dfunction(i)(data(3)(:,2));
end
end
T = cell2table(x, 'VariableNames',{'mean', 'median', 'stddev', 'variance', 'range', 'IQR', 'skewness', 'kurtosis'});
writetable(T,'descriptivestats.csv')
Any ideas on how to make this work??
You want to use a cell array of function handles. The easiest way to do that is to use the # operator, as in
dfunctions = {#mean, #median, #std, #var, #range, #iqr, #skewness, #kurtosis};
Also, you want to combine your three data variables into one variable, to make it easier to iterate over them. There are two choices I can see. If your data variables are all M-by-2 in dimension, you could concatenate them into a M-by-2-by-3 three-dimensional array. You could do that with
data = cat(3, alldata, cond1data, cond2data);
The indexing expression into data that retrieves the values you want would be data(:, 2, y). That said, I think this approach would have to copy a lot of data around and probably isn't the best for performance. The other way to combine data together is in 1-by-3 cell array, like this:
data = {alldata, cond1data, cond2data};
The indexing expression into data that retrieves the values you want in this case would be data{y}(:, 2).
Since you are looping from y == 1 to y == 3, you only need one line in your inner loop body, not three.
for y = 1:3
x{y, i} = dfunctions{i}(data{y}(:,2));
end
Finally, to get the cell array of strings containing function names to pass to cell2table, you can use cellfun to apply func2str to each element of dfunctions:
funcnames = cellfun(#func2str, dfunctions, 'UniformOutput', false);
The final version looks like this:
dfunctions = {#mean, #median, #std, #var, #range, #iqr, #skewness, #kurtosis};
data = {alldata, cond1data, cond2data};
x = cell(length(data), length(dfunctions));
for i = 1:length(dfunctions)
for y = 1:length(data)
x{y, i} = dfunctions{i}(data{y}(:,2));
end
end
funcnames = cellfun(#func2str, dfunctions, 'UniformOutput', false);
T = cell2table(x, 'VariableNames', funcnames);
writetable(T,'descriptivestats.csv');
You can create a cell array of functions using str2func :
function_string = {'mean', 'median', 'std', 'var', 'range', 'iqr', 'skewness', 'kurtosis'};
dfunction = {};
for ii = 1:length(function_string)
fun{ii} = str2func(function_string{ii})
end
Then you can use it on your data as you'd like to :
for ii = 1:8,
for y = 1:3
x{y,i} = dfucntion{ii}(data(1)(:,2));
x{y+1,i} = dfunction{ii}(data(2)(:,2));
x{y+2,i} = dfunction{ii}(data(3)(:,2));
end
end
I have a huge sparse matrix a and I want to save it in a .csv. I can not call full(a) because I do not have enough ram memory. So, calling dlmwrite with full(a) argument is not possible. We must note that dlmwrite is not working with sparse formatted matrices.
The .csv format is depicted below. Note that the first row and column with the characters should be included in the .csv file. The semicolon in the (0,0) position of the .csv file is necessary too.
;A;B;C;D;E
A;0;1.5;0;1;0
B;2;0;0;0;0
C;0;0;1;0;0
D;0;2.1;0;1;0
E;0;0;0;0;0
Could you please help me to tackle this problem and finally save the sparse matrix in the desired form?
You can use csvwrite function:
csvwrite('matrix.csv',a)
You could do this iteratively, as follows:
A = sprand(20,30000,.1);
delimiter = ';';
filename = 'filecontaininghugematrix.csv';
dims = size(A);
N = max(dims);
% create names first
idx = 1:26;
alphabet = dec2base(9+idx,36);
n = ceil(log(N)/log(26));
q = 26.^(1:n);
names = cell(sum(q),1);
p = 0;
for ii = 1:n
temp = repmat({idx},ii,1);
names(p+(1:q(ii))) = num2cell(alphabet(fliplr(combvec(temp{:})')),2);
p = p + q(ii);
end
names(N+1:end) = [];
% formats for writing
headStr = repmat(['%s' delimiter],1,dims(2));
headStr = [delimiter headStr(1:end-1) '\n'];
lineStr = repmat(['%f' delimiter],1,dims(2));
lineStr = ['%s' delimiter lineStr(1:end-1) '\n'];
fid = fopen(filename,'w');
% write header
header = names(1:dims(2));
fprintf(fid,headStr,header{:});
% write matrix rows
for ii = 1:dims(1)
row = full(A(ii,:));
fprintf(fid, lineStr, names{ii}, row);
end
fclose(fid);
The names cell array is quite memory demanding for this example. I have no time to fix that now, so think about this part yourself if it is really a problem ;) Hint: just write the header element wise, first A;, then B; and so on. For the rows, you can create a function that maps the index ii to the desired character, in which case the complete first part is not necessary.
I have an index file (called runnumber_odour.txt) that looks like this:
run00001.txt ptol
run00002.txt cdeg
run00003.txt adef
run00004.txt adfg
I need some way of loading this in to a matrix in matlab, such that I can search through the second column to find one of those strings, load the corresponding file and do some data analysis with it. (i.e. if I search for "ptol", it should load run00001.txt and analyse the data in that file).
I've tried this:
clear; clc ;
% load index file - runnumber_odour.txt
runnumber_odour = fopen('Runnumber_odour.txt','r');
count = 1;
lines2skip = 0;
while ~feof(runnumber_odour)
runnumber_odourmat = zeros(817,2);
if count <= lines2skip
count = count+1;
[~] = fgets(runnumber_odour); % throw away unwanted line
continue;
else
line = strcat(fgets(runnumber_odour));
runnumber_odourmat = [runnumber_odourmat ;cell2mat(textscan(line, '%f')).'];
count = count +1;
end
end
runnumber_odourmat
But that just produces a 817 by 2 matrix of zeros (i.e. not writing to the matrix), but without the line runnumber_odourmat = zeros(817,2); I get the error "undefined function or variable 'runnumber_odourmat'.
I have also tried this with strtrim instead of strcat but that also doesn't work, with the same problem.
So, how do I load that file in to a matrix in matlab?
You can do all of this pretty easily using a Map object so you will not have to do any searching or anything like that. Your second column will be a key to the first column. The code will be as follows
clc; close all; clear all;
fid = fopen('fileList.txt','r'); %# open file for reading
count = 1;
content = {};
lines2skip = 0;
fileMap = containers.Map();
while ~feof(fid)
if count <= lines2skip
count = count+1;
[~] = fgets(fid); % throw away unwanted line
else
line = strtrim(fgets(fid));
parts = regexp(line,' ','split');
if numel(parts) >= 2
fileMap(parts{2}) = parts{1};
end
count = count +1;
end
end
fclose(fid);
fileName = fileMap('ptol')
% do what you need to do with this filename
This will provide for quick access to any element
You can then do what was described in the previous question you had asked, with the answer I provided.
I'm trying to create an expanding lookup table. I think the cell array is what I want but I'm not sure. The structure would be initialized with rows, and an unknown amount of columns. I want to be able to append to the end of each row, and access all values from a specific row.
desired structure:
[1] [4,5] [6,7]
[2] [4,5] [6,7] [3,6]
...
[n] [R1,B2] [R2,B2] ... [Rm, Bm]
this is what I have so far
%%% Build the R-table
n = 360;
k = {};
v = {};
for i = 1:n
k{end+1} = i; % how would I get n keys without this loop?
v{end+1} = {}; % how would I get n values without this loop?
end
rTable = containers.Map(k, v);
%%% add R,B pair to key I
I = 1;
R_add = 4;
B_add = 5;
current_list_temp = rTable(I); % can I add without using a temp variable?
current_list_temp{end+1} = {[R_add, B_add]};
rTable(I) = current_list_temp;
%%% read values for Nth pair in the Ith key
I = 1;
N = 1;
temp = rTable(I); % can I read the values without using a temp variable?
R_read = temp{N}{1}(1);
B_read = temp{N}{1}(2);
Is there a better way of doing this?
When used for indexing end translates to the largest allowed index and you can manipulate it by adding or multiplying it, so instead of
first_empty_cell = ?
cell{index, first_free_cell} = [4,5]
try
cell{index, end+1} = [4,5]
I have hit a roadblock where I am trying to iterate through a structure formed in the MATLAB workspace inside an EML (Embedded Matlab) function block in SIMULINK. Here is some example code:
% Matlab code to create workspace structure variables
% Create the Elements
MyElements = struct;
MyElements.Element1 = struct;
MyElements.Element1.var1 = 1;
MyElements.Element1.type = 1;
MyElements.Element2 = struct;
MyElements.Element2.var2 = 2;
MyElements.Element2.type = 2;
MyElements.Element3 = struct;
MyElements.Element3.var3 = 3;
MyElements.Element3.type = 3;
% Get the number of root Elements
numElements = length(fieldnames(MyElements));
MyElements is a Bus type Parameter for the MATLAB Function Block (EML) in SIMULINK. Below is the area I am running into trouble with. I know the number of elements inside my struct and I know the names, but the number of elements can change with any configuration. So I cannot hardcode based on the Element names. I have to iterate through the struct inside the EML block.
function output = fcn(MyElements, numElements)
%#codegen
persistent p_Elements;
% Assign the variable and make persistent on first run
if isempty(p_Elements)
p_Elements = MyElements;
end
% Prepare the output to hold the vars found for the number of Elements that exist
output= zeros(numElements,1);
% Go through each Element and get its data
for i=1:numElements
element = p_Elements.['Element' num2str(i)]; % This doesn't work in SIMULINK
if (element.type == 1)
output(i) = element.var1;
else if (element.type == 2)
output(i) = element.var2;
else if (element.type == 3)
output(i) = element.var3;
else
output(i) = -1;
end
end
Any thoughts on how I can iterate through a struct type in SIMULINK? Also, I cannot use any extrinsic functions like num2str because this is to be compiled on a target system.
I believe you are trying to use dynamic field names for structures. The correct syntax should be:
element = p_Elements.( sprintf('Element%d',i) );
type = element.type;
%# ...