Is there any way to process this loop faster? - matlab

I have the following code and it is taking a very long time to go through it... I dont think its an infinite loop but it is as follows:
Y = zeros(1069,30658);
D1 = LagOp({0,1,1,1},'Lags',[0,1,2,1]);
for n = 2:30658;
for j = 2:1063
if filter(D1,Ret((D1.Degree + j),n),'Initial',Ret(2:D1.Degree,n)) < 0;
Y(j+3,n) = -1*Ret(j+3,n);
else
Y(j+3,n)=Ret(j+3,n) ;
end
end
end
Basically I want to flip the sign of the current element in the matrix if the previous 3 elements before it add up to being less than 0. Otherwise to leave it alone. Could it be the ... else statement causing the trouble here ?
Edited: I figured out a more efficient way but I am working on figuring out how to change it to 3 values ahead instead with the following code:
for n = 1:30658
Y(:,n) = RET(:,n);
t = conv(Y(:,n), [1 1 1], 'valid');
mask = [false(3,1); t(1:end-1)<0];
Y(mask,n) = -Y(mask,n);
end`
So So for example, if I have a some numbers in an array given by -1 -2 -3 -4 -5 -6 -1 -2 3 -2 -1, then at the number -4 it would look at the sum of the previous 3 values (-1 - 2 - 3 < 0) and then change the sign of the value 3 ahead so -1 becomes positive and this would continue but the change in signs will not having any affect on the sums iterating for every row.
Thanks,

Related

Finding correct loop

I have a dataset consisting of 80k rows. It's stored in a cell.
In the third column the values should go such as -3 in the first row, -2 in the second -1 in the third and so on all through the whole dataset.
As :
-3
-2
-1
-3
-2
-1
...
Now I want to check whether or not this number sequence is actually being followed throughout the whole dataset. I know for a fact it isn't and therefore I want to make some kind of loop that automatically removes the whole rows of data that doesn't follow the -3, -2, -1 steps.
My initial thought was to use diff command to change index, but can't seem to get it right.
Second was to create a loop that would remove data every time it didn't follow the specific number sequence.
for i = 1:length(Dataset)
if Dataset{272,1}(i,3) == -3
continue
else
eraseidx = Dataset{272,1}(i,3)
if Dataset{272,1}(i+1,3) == -2
continue
else
eraseidx = Dataset{272,1}(i,3)
if Dataset{272,1}(i+2,3) == -1
continue
else
eraseidx = Dataset{272,1}(i,3)
end
end
end
end
(Reason for choosing Dataset{272,1} is that I know there is a fault).
Anyone have a method for solving this?
Your loop has one main problem: you nest all conditions under each other, so you check for i+1 and i+2 only if the first condition where false, but then you check again for them as you come to the next iteration of the loop. If Dataset{272,1}(i+1,3) == -2, then you already know that on the next iteration (when you compare Dataset{272,1}(i,3) to -3) it will return false, but is it false or true?! according to your loop it depends on when you ask this...
Here are two options to correct this, still using a loop. The first way it to loop on all k (I replace i with k to not override the imaginary unit in MATLAB), but compare Dataset{272,1}(i+1,3) to a different number:
c = [-1 -3 -2];
for k = 1:length(Dataset)
if Dataset{272,1}(k,3) ~= c(mod(k,3)+1);
eraseidx = Dataset{272,1}(k,3);
end
end
Another option is to compare the data in triplets:
for k = 1:3:length(Dataset)
if Dataset{272,1}(k,3) ~= -3
eraseidx = Dataset{272,1}(k,3);
end
if Dataset{272,1}(k+1,3) ~= -2
eraseidx = Dataset{272,1}(k+1,3);
end
if Dataset{272,1}(k+2,3) ~= -1
eraseidx = Dataset{272,1}(k+2,3);
end
end
Right now you only save the problematic records to eraseidx, but you overwrite it each time any of the conditions is fulfilled, so you need to also index eraseidx:
eraseidx = zeros(length(Dataset),1);
c = [-1 -3 -2];
for k = 1:length(Dataset)
if Dataset{272,1}(k,3) ~= c(mod(k,3)+1);
eraseidx(k) = Dataset{272,1}(k,3);
end
end
However, if you only want to delete those records you can save the k alone as logical indexing, and not all the record. Also, it seems to me that your loop should run on 1:length(Dataset{272,1}) so:
eraseidx = false(length(Dataset{272,1}),1);
c = [-1 -3 -2];
for k = 1:length(Dataset{272,1})
eraseidx(k) = Dataset{272,1}(k,3) ~= c(mod(k,3)+1);
end
And this could be easily vectorised to:
c = [-1 -3 -2];
k = 1:length(Dataset{272,1});
eraseidx = Dataset{272,1}(k,3) ~= c(mod(k,3)+1).';
So now eraseidx will be a logical vector, so that Dataset{272,1}(eraseidx,:) will be all the records from Dataset{272,1} to be deleted. Edit: To delete them you just write: Dataset{272,1}(eraseidx,:) = [].
Vectorize on all Dataset
In case all the data in all cells has the same size and shape, you can use cell2mat to convert it to a ND-array, and then perform a vectorized operation on all data at once:
data = reshape(cell2mat(Dataset.'),[],3,numel(Dataset)); % convert to 3D array
c = [-1 -3 -2];
k = 1:size(data,1);
correct = c(mod(k,3)+1).'; % the correct values to compare
eraseidx = squeeze(bsxfun(#ne,data(:,3,:),correct));
Now each column in eraseidx corresponds to a third column in Dataset, so the result for Dataset(k,1) is given in eraseidx(:,1).
To delete all true records in eraseidx you can use a simple loop:
for k = 1:numel(Dataset)
Dataset{k}(eraseidx(:,k),:) = [];
end
Notice that you cannot delete the records directly from data because arrays cannot have different number of rows in each element of the third dimension.
If Dataset has to be a cell-array...
If you're using cells to keep the data in Dataset because it is not in the same size and shape, you can adjust the above loop for all the process:
c = [-1 -3 -2];
for k = 1:numel(Dataset)
eraseidx = Dataset{k,1}(:,3) ~= c(mod(1:length(Dataset{k,1}),3)+1).';
Dataset{k,1}(eraseidx,:) = [];
end
Or you can use cellfun (which is basically a compact loop):
c = [-1 -3 -2];
delfun = #(M) M(M(:,3)==c(mod(1:length(M),3)+1).',:);
Dataset_fixed = cellfun(delfun,Dataset,'UniformOutput',false);
delfun is an anonymous function that retrieve only the wanted records from each cell in Dataset. Now Dataset_fixed is Dataset without the deleted rows.

For-loop exits too early, need help as to why

I've written a simple function that takes a vector vec, iterates through it, performing an operation whose result is stored in another vector vecRes of same size at same index, and returns vecRes upon completing the loop. Below is function code:
function [ vecRes ] = squareTerms( vec )
vecSize = size(vec);
vecRes = zeros(vecSize);
for i = 1:vecSize
vecRes(i) = vec(i)^2;
end
end
Problem is that it seems to exit too early, after only one iteration in fact as the output appears as:
vecRes = 1 0 0 0 0 0 0 0 0 0
For input:
vec = 1 2 3 4 5 6 7 8 9 10
I can't figure out why it does so. Any help is greatly appreciated.
Size returns 2 values, rows and columns. Probably you are a having a 1xN vector. So size returns [1 N] and your loop runs 1 time.
>>> size ([1 2 3])
>
> ans =
>
> 1 3
>
>>> 1:size ([1 2 3])
>
> ans =
>
> 1
Others have pointed out the problem. My preferred solution in this sort of case is to use numel, i.e.
vecRes = zeros(size(vec));
for i = 1:numel(vec)
vecRes(i) = vec(i) ^ 2;
end
Of course, in this case, vectorisation is better still:
vecRes = vec .^ 2;
Replace
for i = 1:vecSize
with
for i = 1:vecSize(2)
vecSize is an array of numbers, not just a single value. For example, if vec is a 1 by 8 vector, then size(vec) will return [1, 8].
Therefore, your for-loop-statement,
for i = 1:vecSize
, is actually equivalent to something like:
for i = 1:[1, 8]
This doesn't make much sense. There are a number of ways to fix the problem. You could write:
for i = 1:length(vec)
or
for i = 1:numel(vec) % "numel" stands for "number of elements"
If the vector is 1xn instead of nx1, you can write:
for i = 1:size(vec, 2)
Yet another alternative is:
for i = 1:max(vecSize)
However, the most sensible option is not to write the squareTerms function at all and simply write
vecRes = vec.^2;
Note the dot before the caret. vec^2 and vec . ^2 are not the same thing.
If you put a dot before an operator sign, the operation will be performed element-wise. For example,
C = A * B
performs matrix multiplication, but
C = A .* B
will cause the first element of A to by multiplied by the first element of B, and the result will be assigned to the first element of C. Then, the product of the second elements of A and B will be taken, and the result will be stuck in the second element of C, and so on.
vecRes = vec.^2;

multichoice Matlab for loops [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Can anyone tell me how I would work this out manually?
Consider the following MATLAB function:
function Anew = mystery( A )
N=5;
for ii=2:N
Anew(ii)= A(ii-1);
end
end
If we define v = [0,1,2,3,4,5,6,7,8,9,10]. What would be the output of x = mystery(v) be?
a) x = [1 2 3 4 5 6 7 8 9 10]
b) x = [1 2 3 4 5 6]
c) x = [0 1 2 3 4 5]
d) x = [0 0 1 2 3]
OK, let's step through this code line by line.
The first line:
N = 5;
This basically creates a variable called N and stores the value of 5 in it. No biggie.
Next line:
for ii = 2 : N
This is a for loop, and each time the loop iterates, the value of ii will change by 1. The first time the loop runs, ii = 2, then the next time it starts again, ii = 3 up to ii = 5, then the loop stops.
So, let's start at the beginning with ii = 2. The statement inside the loop is equivalent to:
Anew(2) = A(2-1);
This simplifies to:
Anew(2) = A(1);
If you look at the code, Anew was never defined up until this point. When you try to assign a value to a location in an array that was not previously declared, MATLAB will fill up the values that are before the location of where you assigned to be zero automatically. As such, if you did:
Anew(8) = 9; %// For example
Anew would look like this:
Anew =
0 0 0 0 0 0 0 9
The 8th position has the value of 9, while the other positions before the 8th one are all zero. Therefore, by doing Anew(2) = A(1);, the first position of Anew is zero, while the second position of Anew gets the first value of A and puts it here. As such, Anew currently looks like:
Anew =
0 0
Let's do ii = 3. This means that in your loop, the statement simplifies to:
Anew(3) = A(3-1);
.... which is:
Anew(3) = A(2);
This means that the third position of Anew gets the second element of A copied over here. Note that the original size of Anew was 2. By doing Anew(3) = A(2);, MATLAB will automatically adjust the size of Anew, and then put what A(2) is into the third position of Anew. Therefore, Anew looks like:
Anew =
0 0 1
As a little test, if we were to do Anew(6) = A(2);, this is what it would look like:
Anew =
0 0 0 0 0 1
Note that we previously had Anew = [0 0]; before this point. By doing Anew(6) = A(2);, the 3rd, 4th and 5th positions of Anew get filled with 0, and the 6th position gets the value of 1, which is A(2).
You can probably see a pattern now. Each position of Anew gets the element of A shifted to the left by 1. Therefore, for ii = 4:
Anew(4) = A(3);
What it looks like now is:
Anew =
0 0 1 2
Finally for ii = 5, we get:
Anew(5) = A(4);
What it looks like now is:
Anew =
0 0 1 2 3
After the end of this loop, Anew gets returned as the output of mystery.
Therefore, the answer is (d): x = [0 0 1 2 3];.
Hope this helps!

Changing the elements of a matrix using a for loop in matlab

I'm having a few issues getting MATLAB to do what I want.
say I have a matrix x = [1 2 3 4; 1 4 4 5; 6 4 1 4]
I'm trying to write code that will go through the matrix and change each 4 to a 5, so it modifies the input matrix
I've tried a few things:
while index <= numel(x)
if index == 4
index = 5;
end
index = index + 1;
end
for item = x
if item == 4
item = 5;
end
end
the simplest thing i tried was
for item = x
if item == 4
item = 5;
end
end
i noticed by looking at the workspace that the value of item did indeed change but the value of x (the matrix) stayed the same.
How do I get the output that i'm looking for?
If you just want to change all the 4s to 5s then:
x(x==4)=5
basically x==4 will result in a logical matrix with 1s everywhere there was a 4 in x:
[0 0 0 1
0 1 1 0
0 1 0 1]
We then use logical index to only affect the values of x where those 1s are and change them all to 5s.
If you wanted to do this using a loop (which I highly recommend against) then you can do this:
for index = 1:numel(x)
if x(index) == 4
x(index) = 5;
end
end
Short answer to achieve what you want:
x(x==4) = 5
Answer to why your code doesn't do what you expected:
You are changing the item to a 5. But that item is a new variable, it does not point to the same item in your matrix x. Hence the original matrix x remains unchanged.

matlab fxn: find contiguous regions and return bounds in struct array

This is half a question and half a challenge to the matlab gurus out there:
I'd like to have a function take in a logical array (false/true) and give the beginning and ending of all the contiguous regions containing trues, in a struct array.
Something like this:
b = getBounds([1 0 0 1 1 1 0 0 0 1 1 0 0])
should return
b = 3x1 struct array with fields:
beg
end
and
>> b(2)
ans =
beg: 4
end: 6
I already have an implementation, but I don't really know how to deal with struct arrays well so I wanted to ask how you would do it - I have to go through mat2cell and deal, and when I have to deal with much larger struct arrays it becomes cumbersome. Mine looks like this:
df = diff([0 foo 0]);
a = find(df==1); l = numel(a);
a = mat2cell(a',ones(1,l))
[s(1:l).beg] = deal(a{:});
b = (find(df==-1)-1);
b = mat2cell(b',ones(1,l))
[s(1:l).end] = deal(b{:});
I don't see why you are using mat2cell, etc. You are making too much of the problem.
Given a boolean row vector V, find the beginning and end points of all groups of ones in the sequence.
V = [1 0 0 1 1 1 0 0 0 1 1 0 0];
You get most of it from diff. Thus
D = diff(V);
b.beg = 1 + find(D == 1);
This locates the beginning points of all groups of ones, EXCEPT for possibly the first group. So add a simple test.
if V(1)
b.beg = [1,b.beg];
end
Likewise, every group of ones must end before another begins. So just find the end points, again worrying about the last group if it will be missed.
b.end = find(D == -1);
if V(end)
b.end(end+1) = numel(V);
end
The result is as we expect.
b
b =
beg: [1 4 10]
end: [1 6 11]
In fact though, we can do all of this even more easily. A simple solution is to always append a zero to the beginning and end of V, before we do the diff. See how this works.
D = diff([0,V,0]);
b.beg = find(D == 1);
b.end = find(D == -1) - 1;
Again, the result is as expected.
b
b =
beg: [1 4 10]
end: [1 6 11]
By the way, I might avoid the use of end here, even as a structure field name. It is a bad habit to get into, using matlab keywords as variable names, even if they are only field names.
This is what I went with:
df = diff([0 foo 0]);
s = struct('on',num2cell(find(df==1)), ...
'off',num2cell(find(df==-1)-1));
I forgot about num2cell and the nice behavior of struct with cell arrays.