generate a name vector MATLAB - matlab

How would I generate a vector like
x1,x2,x3,x4,...,xn
the problem is concatenate ','and a 'x' char
n=100
A = (1:n);

This is a slight improvement on #Jonas's answer. SPRINTF will do the repeating for you avoiding the need for a mask:
>> n = 5;
>> out = sprintf('x%u,', 1:n);
>> out(end) = []
out =
x1,x2,x3,x4,x5

To generate the string 'x1,x2' etc, you can create a mask for SPRINTF using REPMAT like so:
n = 5;
mask = repmat('x%i,',1,n);
out = sprintf(mask,1:n);
out = out(1:end-1)
out =
x1,x2,x3,x4,x5
Note that in case you actually want to create a vector containing the strings 'x1','x2' etc, you'd use ARRAYFUN to generate a cell array:
out = arrayfun(#(x)sprintf('x%i',x),1:n,'uniformOutput',false)
out =
'x1' 'x2' 'x3' 'x4' 'x5'

The better answer is, don't do it. While you CAN do so, this will likely cause more heartache for you in the future than you want. Having hundreds of such variables floating around is silly, when you can use an array to index the same data. Thus perhaps x{1}, x{2}, ....

Related

loop and concatenate variable in workspace

I am trying to concatenate matrices station_1, station_2,.....station_10 from my matlab workspace and trying to concatenate all stations automatically using a loop and not calling them one by one like this
cat(1,station_1,station_2,station_3,station_4... ,station_5,station_6,station_7,station_8... ,station_9,station_10 )
Any ideas?
the code below is what i was trying to improve
for jj= 1 : 10 T= cat(1,eval(['station_', num2str(jj)])); MegaMat = cat(1,T) end
Reading your code I think at the end of your loop you will have T = station_10.
If you want to concatenate all of them you would do
T = []
for jj= 1:10
T = cat(1, T, eval(['station_', num2str(jj)]));
end
MegaMat = T;
Using eval is not a good practice. Instead of creating station_1 to station_10 you could create a cell array
station{1} = ...
station{2} = ...
Then you could iterate like
T = []
for jj = 1:length(station)
T = cat(1, T, station{jj});
end
If the number of arrays is big this will be slow due to memory reallocation and copy. In that case is more efficient to initialize T as a matrix of the final dimension and write slices.
Appendix:
There is an interesting notation trick pointed by #Cris Luengo in the comments, that is when you have a cell array station, use the notation [station{:}], I have to admit, this notation is new to me. The only caveat is that if you set the items station{i} = ... then you will have the matrices concatenated horizontally rather than vertically.
The answer from #Mateo V, is also good, probably with leas overhead since it calls eval only once. That approach can be refined giving a one linear solution, and to be honest It felt not very unreadable.
MegaMat = eval(['cat(1', num2str(1:10, ', station_%d'), ')']);
No need for loops:
str = num2str(1:10, 'station_%i,'); % returns string 'station_1, station_2, ..., station_10,'
str = str(1:end-1); % remove last comma
eval(['MegaMat = cat(1, ', str, ');'])

Matlab loop through functions using an array in a for loop

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

Most efficient way to store numbers as strings inside a table

I want to store efficiently some numbers as strings (with different lengths) into a table. This is my code:
% Table with numbers
n = 5;
m = 5;
T_numb = array2table((rand(n,m)));
% I create a table with empty cells (to store strings)
T_string = array2table(cell(n,m));
for i = 1:height(T_numb)
for ii = 1:width(T_numb)
T_string{i,ii} = cellstr(num2str(T_numb{i,ii}, '%.2f'));
end
end
What could I do to improve it? Thank you.
I don't have access to the function cell2table right now, but using the undocumented function sprintfc might work well here (check here for details).
For instance:
%// 2D array
a = magic(5)
b = sprintfc('%0.2f',a)
generates a cell array like this:
b =
'17.00' '24.00' '1.00' '8.00' '15.00'
'23.00' '5.00' '7.00' '14.00' '16.00'
'4.00' '6.00' '13.00' '20.00' '22.00'
'10.00' '12.00' '19.00' '21.00' '3.00'
'11.00' '18.00' '25.00' '2.00' '9.00'
which you can convert to a table using cell2table.
So in 1 line:
YourTable = cell2table(sprintfc('%0.2f',a))
This seems to be quite fast -
T_string = cell2table(reshape(strtrim(cellstr(num2str(A(:),'%.2f'))),size(A)))
Or with regexprep to replace strtrim -
cell2table(reshape(regexprep(cellstr(num2str(A(:),'%.2f')),'\s*',''),size(A)))
Here, A is the 2D input numeric array.

Sum of Data(end) in a cell array of timeseries

Given the code below:
% Generate some random data
n = 10;
A = cell(n, 1);
for i=1:n
A{i} = timeseries;
A{i}.Data = rand(100, 1);
A{i}.Time = 1:100;
end
I would like to make the sum of Data(end) without explicitly writing a for loop. Is there a smart way to select Data(end) in all cells in a single line? A{:}.Data(end) does not work.
You can do it with cellfun but that is essentially just a for loop wrapped up:
cellfun(#(x) x.Data(end), A)
I prefer Dan's answer, but for reference, I'll post an alternative using arrayfun. This is also just a for loop wrapped up to save keystrokes, but not necessarily time.
sum(arrayfun(#(n) A{n}.Data(end), 1:numel(A)))
You can also extract all of the Data fields into a single matrix, which might be worth it if you're planning on doing multiple operations on it:
A2 = [A{:}];
A3 = [A2.Data];
sum(A3(end,:))

Can I store a MATLAB slice in a variable?

I have a lengthy slice sequence that I need to apply to lots of MATLAB matrices. How can I do this?
i.e. can I simplify,
y(1:some_var*3,1:some_other_var*3,1:another_var*3) = x1(1:some_var*3,1:some_other_var*3,1:another_var*3) .* x2(1:some_var*3,1:some_other_var*3,1:another_var*3) ./ x3(1:some_var*3,1:some_other_var*3,1:another_var*3)
to something like,
inds = slice(1:some_var*3,1:some_other_var*3,1:another_var*3)
y(inds) = x1(inds) .* x2(inds) ./ x3(inds)
like I can do in Python?
In your case, you can create a logical mask:
%# assuming x1,x2,x3,y are all of the same size
mask = false(size(x1));
mask(1:some_var*3,1:some_other_var*3,1:another_var*3) = true;
y(mask) = x1(mask).*x2(mask)./x3(mask);
Other functions that you might want to read about: FIND, SUB2IND
One option is to store each vector of indices in a cell of a cell array, then extract the cell array content as a comma-separated list like so:
inds = {1:some_var*3, 1:some_other_var*3, 1:another_var*3};
y(inds{:}) = x1(inds{:}) .* x2(inds{:}) ./ x3(inds{:});
If you have large matrices, with relatively small/sparse sets of indices, this may be more efficient than using a logical mask as Amro suggested.