Avoiding the use of for loops - matlab

I would like to get some help with how to avoid using for loops. I've seen several similar questions but have not been able to figure something specific to my needs. Currently I use loops and it is very bulky and messy. Below is the structure of the data and what I would like to achieve:
I have to index data from 1080 timepoints which come from variable mean_data which is a 1080x1 double. Some of the timepoints belong to specific task conditions and specific events that I am interested in. There are 3 conditions (cond1, cond2, cond3) and 4 task events (event1, event2, event3, event4). This information comes from variable params. Specially column 8 of params has the condition information (1, 2, 3 mean cond1, cond2, con3, respectively). The event information can be obtained from column 11 in params. Below is what I can do with loops:
for c=1:size(params,1)
if params(c,8)==1
cond1_event1(end+1,1)=mean([data(params(c,11)+3,1),data(params(c,11)+4,1)]);
cond1_event2(end+1,1)=mean([data(params(c,11)+6,1),data(params(c,11)+7,1)]);
cond1_event3(end+1,1)=mean([data(params(c,11)+8,1),data(params(c,11)+9,1)]);
cond1_event4(end+1,1)=mean([data(params(c,11)+10,1),data(params(c,11)+11,1)]);
elseif params(c,8)==2
cond2_event1(end+1,1)=mean([data(params(c,11)+3,1),data(params(c,11)+4+1,1)]);
etc.
elseif params(c,8)==3
cond3_event1(end+1,1)=mean([data(params(c,11)+3,1),data(params(c,11)+4,1)]);
etc.
end
end
The loops make it clear but it's just too long. Does anyone have any suggestions how to make this a bit more elegant? The output should yield 12 variables (3 condition x 4 events). Each variable is a nx1 double. Thank you.

You could simply use logical indexing, then use vertical concatenation.
idx = params(c, 8) == 1;
cond1_event1 = [cond1_event1; mean(...)];
Then repeat for the other conditions, or use a loop(1:3).

Related

Double for loop in MATLAB, storing the information

I have two for loops in MATLAB.
One of the for loops leads to different variables being inserted into the model, which are 43 and then I have 5 horizons.
So I estimate the model 215 times.
My problem is I want to store this in 215x5 matrix, the reason I have x5 is that I am estimating 5 variables, 4 are fixed and the other one comes from the for loop.
I have tried to do this in two ways,
Firstly, I create a variable called out,
out=zeros(215,5);
The first for loop is,
for i=[1,2,3,4,5];
The second for loop is,
for ii=18:60;
The 18:60 is how I define my variables using XLS read, e.g. they are inserted into the model as (data:,ii).
I have tried to store the data in two ways, I want to store OLS which contains the five estimates
First,
out(i,:)=OLS;
This method creates a 5 x 5 matrix, with the estimates for one of the (18:60), at each of the horizons.
Second,
out(ii,:)=OLS;
This stores the variables for each of the variables (18:60), at just one horizon.
I want to have a matrix which stores all of the estimates OLS, at each of the horizons, for each of my (18:60).
Minimal example
clear;
for i=[1,2,3,4,5];
K=i;
for ii=18:60
x=[1,2,3,i,ii];
out(i,:)=x;
end
end
So the variable out will store 1 2 3 5 60
I want the variable out to store all of the combinations
i.e.
1 2 3 1 1
1 2 3 1 2
...
1 2 3 5 60
Thanks
The simplest solution is to use a 3D matrix:
for jj=[1,2,3,4,5];
K=jj;
for ii=18:60
x=[1,2,3,jj,ii];
out(ii-17,jj,:)=x;
end
end
If you now reshape the out matrix you get the same result as the first block in etmuse's answer:
out = reshape(out,[],size(out,3));
(Note I replaced i by jj. i and ii are too similar to use both, it leads to confusion. It is better to use different letters for loop indices. Also, i is OK to use, but it also is the built-in imaginary number sqrt(-1). So I prefer to use ii over i.)
As you've discovered, using just one of your loop variables to index the output results in most of the results being overwritten, leaving only the results from the final iteration of the relevant loop.
There are 2 ways to create an indexing variable.
1- You can use an independent variable, initialised before the loops and incremented at the end of the internal loop.
kk=1;
for i=1:5
for ii=18:60
%calculate OLC
out(kk,:)=OLC;
kk = kk+1;
end
end
2- Use a calculation of i and ii
kk = i + 5*(ii-18)
(Use in loop as before, without increment)

Efficient Enumeration of subsets of variable size

There are 2 variables: i and j.
i runs from 1 to fixed constant N. j runs from 1 to M(i), meaning we have an array
M=zeros(N,1);
M=[3,2,5,4];
Also S is a set of say 10 integers. Corresponding to every i, I have to find all possible ways of choosing numbers from S up to a given max limit M(i).
My code:
desired_enumerations={};
for i=1:N
for j=1:M(i)
a = combnk(S,j);
for k=1:size(a,1)
desired_enumerations{end+1,1}=a(k,:);
end
end
end
My question:
I want to pre-compute all possible subsets of S up to max(M) elements outside the double for loop and then use that data inside the for loops so i don't have to enumerate the subsets inside double for loop and avoid repeated calculations.
What is an efficient way to do this?
EDIT:
Just as a bonus if someone could also give the time-complexity of the code in big-O notation. Or i can open a new question.

Fastest way to choose a matrix row given a certain condition

In Matlab, I have a 2x3 matrix, A, like this one:
A = [1 2 3; 4 5 6];
This matrix is defined inside of a function which takes a parameter, T. There are two cases that I need to take care of:
T < 10
T >= 10
If the user entered, say, T=40, then the 2nd row of A should be selected to make the calculations. On the other hand, if say T=5, the first row of A should be selected.
I can write a simple if-else condition like this:
if (T<10)
b = A(1,:) * ... %Do whatever with the first row
else
b = A(2,:) * ... %Do whatever with the second row
end
However I was wondering if it's possible to play around with Matlab indexes to save myself the overhead of having to write this if-else condition all around my code (this condition has to be checked many times, in different parts of my program).
For example, I was hoping to reach a simple expression like A(T<10, :) which would work fine if T<10 but for T>=10 would return an empty matrix.
I've been racking my brains for some hours but I'm a bit of a novice in optimising Matlab scripts. Could anyone kick me in the right direction?
You can use the following method:
A((T>=10) + 1, :)

Mathematica Table function to Matlab

I need to convert this to Matlab code, and am struggling without the "table" function.
Table[{i,1000,ability,savingsrate,0,RandomInteger[{15,30}],1,0},{i,nrhhs}];
So basically, these values are all just numbers, and I think I need to use a function handle, or maybe a for loop. I'm no expert, so I really need some help?
I'm not an expert in Mathematics (just used it long time ago). According to this documentation for Table function, you are using this form:
Table[expr, {i, imax}]
generates a list of the values of expr when i runs from 1 to imax.
It looks like your statement will produce list duplicating the list in first argument increasing i from 1 to nrhhs and using different random number.
In MATLAB the output can be equivalent to a matrix or a cell array.
To create a matrix with rows as your lists you can do:
result = [ (1:nrhhs)', repmat([1000,ability,savingsrate,0],nrhhs,1), ...
randi([15 30],nrhhs,1), repmat([1,0],nrhhs,1) ];
You can convert the above matrix to a cell array:
resultcell = cell2mat(result, ones(nrhhs,1));
The "Table" example you gave creates a list of nrhhs sub-lists, each of which contains 8 numbers (i, 1000, ability, savingsrate, 0, a random integer between 15 and 30 inclusive, 1, and 0). This is essentially (though not exactly) the same as an nrhhs x 8 matrix.
Assuming you do just want a matrix out, though, an analogous for loop in Matlab would be:
result = zeros(nrhhs,8); % preallocate memory for the result
for i = 1:nrhhs
result(i,:) = [i 1000 ability savingsrate 0 randi([15 30]) 1 0];
end
This method is likely slower than yuk's answer (which makes much more efficient use of vectors to avoid the for loop), but might be a little easier to pick apart depending on how familiar you are with Matlab.

Why does crossvalind fail?

I am using cross valind function on a very small data... However I observe that it gives me incorrect results for the same. Is this supposed to happen ?
I have Matlab R2012a and here is my output
crossvalind('KFold',1:1:11,5)
ans =
2
5
1
3
2
1
5
3
5
1
5
Notice the absence of set 4.. Is this a bug ? I expected atleast 2 elements per set but it gives me 0 in one... and it happens a lot that is the values are not uniformly distributed in the sets.
The help for crossvalind says that the form you are using is: crossvalind(METHOD, GROUP, ...). In this case, GROUP is the e.g. the class labels of your data. So 1:11 as the second argument is confusing here, because it suggests no two examples have the same label. I think this is sufficiently unusual that you shouldn't be surprised if the function does something strange.
I tried doing:
numel(unique(crossvalind('KFold', rand(11, 1) > 0.5, 5)))
and it reliably gave 5 as a result, which is what I would expect; my example would correspond to a two-class problem (I would guess that, as a general rule, you'd want something like numel(unique(group)) <= numel(group) / folds) - my hypothesis would be that it tries to have one example of each class in the Kth fold, and at least 2 examples in every other, with a difference between fold sizes of no more than 1 - but I haven't looked in the code to verify this.
It is possible that you mean to do:
crossvalind('KFold', 11, 5);
which would compute 5 folds for 11 data points - this doesn't attempt to do anything clever with labels, so you would be sure that there will be K folds.
However, in your problem, if you really have very few data points, then it is probably better to do leave-one-out cross validation, which you could do with:
crossvalind('LeaveMOut', 11, 1);
although a better method would be:
for leave_out=1:11
fold_number = (1:11) ~= leave_out;
<code here; where fold_number is 0, this is the leave-one-out example. fold_number = 1 means that the example is in the main fold.>
end