Can't figure out "if else" code correctly? - matlab

if APC<-2.9079
BUYz='z'
SELLy='y'
elseif APC>0.44
BUYy='y'
SELLz='z'
else
end
x and y are both single column matrices.
I want the system to check if the APC column is above or below the values as mentioned above, if yes, pick up corresponding values from x and y.
Do you think I have entered this correctly?
When I try the code it does not create BUYy or any of the others.
Thanks for all the help.
Clarification:
I have loaded an excel file in Matlab using xlsread. It has columns such as x, y, APC, Date etc.
I am using the "if else" statement in the command window after loading the file.

First a brief introduction to if and elseif for vectors.
Suppose A = [1 2 3], then the following will not result in B = 5.
if A > 2
B = 5;
end
The reason for this is because what the if sees is (A > 2) == [0 0 1]. The first 0 will cause the statement to be false, thus it will skip the rest.
Similarly, the following will also not result in B = 5.
if A < 2
B = 5;
end
The reason for this is because the if now sees (A < 2) == [1 0 0]. The if requires all of the elements to be true for it to "jump into it". The two below are equivalent:
if A < x
and
if all(A < x)
elseif behaves the exact same way.
Suppose y = [1 2 3], doing x = 'y' will not give you x = [1 2 3] but x = y (the character "y", not the variable. If you want the x variable to be equal to the y variable you simply do x = y.
So, what can you do?
If I understand you correctly, you have a vectors similar to this (might be decimals, but that doesn't matter).
APC = [1, -3, 4, -2, 0];
x = [1 2 3 4 5];
y = [6 7 8 9 10];
You want BUYx = x(2), and SELLy = y(2) since the second element is the only one in APC that's less than -2.9079.
You also want BUYy = [y(1), y(3)] and SELLx = [x(1), x(3)], since the first and third element of APC is larger than 0.44.
What you can do is:
BUYx = x(APC < -2.9079)
SELLy = y(APC < -2.9079)
BUYy = y(APC > 0.44)
SELLx = x(APC > 0.44)
This returns:
BUYx =
2
SELLy =
7
BUYy =
6 8
SELLx =
1 3
If you only want the first elements and not all of them, you can use find like this:
BUYx = x(find(APC < -2.9079,1,'first'))
SELLy = y(find(APC < -2.9079,1,'first'))
BUYy = y(find(APC > 0.44,1,'first'))
SELLx = x(find(APC > 0.44,1,'first'))
find(x < y, 5, 'first') find the first 5 elements where x < y. find(APC < -2.9079, 1, 'first') finds only the first element where APC < -2.9079.
or just do as the first approach and then: BUYx = BUYx(1) to only get the first elements.
It might be I have misinterpreted your question, but I think this will get you well on your way nevertheless. Good luck!

Related

How can I index multiple array segments at once without a loop?

I want to change the value in column 2 based on the values in column 1 in one array (main), using a start and end index from another array (conditions).
In conditions column 1 holds the start index, column 2 the end index.
main = zeros(8, 2);
main(:, 1) = 1:8;
conditions = [2, 3; 6, 8]
main =
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
conditions =
2 3
6 8
I know how to do it using a loop (shown below), but am looking for a faster method.
for ii = 1:size(conditions, 1)
main(main(:, 1) >= conditions(ii, 1) & main(:, 1) <= conditions(ii, 2), 2) = 1;
end
main =
1 0
2 1
3 1
4 0
5 0
6 1
7 1
8 1
Doing main(main(:, 1) >= conditions(:, 1) & main(:, 1) <= conditions(:, 2), 2) = 1 results in the error Matrix dimensions must agree.
Is there a non-loop method?
Your attempt is almost correct. If you transpose the conditions, then you'll be comparing a column of main with a row of conditions, leading to MATLAB doing implicit singleton expansion, giving a matrix output. This matrix can then be collapsed using any.
main = zeros(8, 2);
main(:, 1) = 1:8;
conditions = [2, 3; 6, 8];
index = (main(:,1) >= conditions(:, 1).') & (main(:, 1) <= conditions(:, 2).');
index = any(index,2);
main(index,2) = 1;
(I've separated out the code into 3 lines for clarity, but of course they can all be a single line.)
Note that for versions of MATLAB prior to R2016b, this code won't work, you'll need to use bsxfun instead:
index = bsxfun(#ge,main(:,1),conditions(:, 1).') & bsxfun(#le,main(:, 1),conditions(:, 2).');
NOTE: This is a solution for integers only as the original question only presented the integer case.
First, figure out how many elements there are included in the interval
dCon = diff(conditions,[],2)+1;
Then construct an increasing sequence of indexes to the maximum number of elements (this list would be enormous for the float case, and thus this solution does not, feasibly/efficiently, extend to floats)
idx0 = repmat(1:max(dCon),length(dCon),1);
Cap off the indexes that are too large
idx0(idx0>dCon)=1;
Now add the starting point
idx = idx0 + conditions(:,1)-1;
now idx contains all the numbers you want to change. Use ismember to find all elements in main and change them to 1.
main(ismember(main(:,1),idx(:)),2)=1;
EDIT: This is the full example with the vector from Gnovice in the comments
main = zeros(10, 2);
main(:, 1) = [1; 2; 2; 2; 3; 3; 4; 6; 6; 8];
conditions = [2, 3; 6, 8]
dCon = diff(conditions,[],2)+1;
idx0 = repmat(1:max(dCon),length(dCon),1);
idx0(idx0>dCon)=1;
idx = idx0 + conditions(:,1)-1;
main(ismember(main(:,1),idx(:)),2)=1;

How to make ndgrid work with 1-dimensional data in MATLAB?

First of all, I could not find a better title to describe my problem, sorry for that. Maybe someone could suggest a better title.
I have the following code:
gridSize = (gridResolution - 1) .* gridStepSize;
positionsVectorY = gridSize(1) / 2 : -gridStepSize(1) : -gridSize(1) / 2;
positionsVectorX = -gridSize(2) / 2 : gridStepSize(2) : gridSize(2) / 2;
[ gridPositionMatrixY, gridPositionMatrixX ] = ndgrid(positionsVectorY, positionsVectorX);
This code works fine for me if gridSize(1) > 0, gridSize(2) > 0 and if gridResolution(1) > 1, gridResolution(2) > 1. However, if that is not the case, the matrix / matrices are empty. For example, [y, x] = ndgrid([], 1 : 3) returns empty matrices: Empty matrix: 0-by-3. What I would need in that case is [y, x] = ndgrid(0, 1 : 3).
So, my question is: What is the best way to change the above code to create the desired matrices?
I could simply check if positionsVectorY is empty and replace it with zeros. But I'm wondering if there is a more "elegant" solution to this.
Thank you,
Adrian
EDIT: An example:
Here is an example where my code works:
positionsVectorY = 1 : 2;
positionsVectorX = 1 : 3;
[y, x] = ndgrid(positionsVectorY, positionsVectorX)
The output is
y =
1 1 1
2 2 2
x =
1 2 3
1 2 3
And here is a special case where it does not work: If the resolution in y direction is 1, and the size of the grid is 0 in y direction, then my code generates an empty array positionsVectorY. Then:
positionsVectorY = [];
positionsVectorX = 1 : 3;
[y, x] = ndgrid(positionsVectorY, positionsVectorX)
The output is:
y =
Empty matrix: 0-by-3
x =
Empty matrix: 0-by-3
That is not what I want, I want that my code generates
positionsVectorY = 0; % instead of []
positionsVectorX = 1 : 3;
[y, x] = ndgrid(positionsVectorY, positionsVectorX)
in this special case, with the output:
y =
0 0 0
x =
1 2 3
What I want in the end, is to modify my code so it works for the general case, but also for the special case where the resolution in y or x direction can be 1. My temporary solution is using if-statements,
if(isempty(positionsVectorY))
positionsVectorY = 0;
end
if(isempty(positionsVectorX))
positionsVectorX = 0;
end
But I would like to remove them and do it in a more elegant way.

Counting Number of Specific Outputs of a Function

If I have a matrix and I want to apply a function to each row of the matrix. This function has three possible outputs, either x = 0, x = 1, or x > 0. There's a couple things I'm running into trouble with...
1) The cases that output x = 1 or x > 0 are different and I'm not sure how to differentiate between the two when writing my script.
2) My function isn't counting correctly? I think this might be a problem with how I have my loop set up?
This is what I've come up with. Logically, I feel like this should work (except for the hiccup w/ the first problem I've stated)
[m n] = size(matrix);
a = 0; b = 0; c = 0;
for i = 1 : m
x(i) = function(matrix(m,:));
if x > 0
a = a + 1;
end
if x == 0
b = b + 1;
end
if x == 1
c = c + 1;
end
end
First you probably have an error in line 4. It probably should be i instead of m.
x(i) = function(matrix(i,:));
You can calculate a, b and c out of the loop:
a = sum(x>0);
b = sum(x==0);
c = sum(x==1);
If you want to distinguish x==1 and x>0 then may be with sum(xor(x==1,x>0)).
Also you may have problem with precision error when comparing double values with 0 and 1.

How do I assign an element in a series of 3D arrays of into a single vector?

So I want all 6 elements of the third column to go into a vector of 6 elements. How would I do this?
You can use the (:) operator to collapse an nD matrix to a single vector. For your example, do something like this:
mat = (50 < seals(:, 3, 1)) & (seals(:, 3, 1) < 100)
vec = mat(:);
First of all, you cannot use the comparison operator to compare against an interval the way you do. I suggest you try to run this bit of code:
x = 1:10;
4 < x < 7
On my system I get the answer
ans =
1 1 1 1 1 1 1 1 1 1
which, I suspect, is not what you want. The solution is to divide your condition like this
(4 < x) & (x < 7)
giving
ans =
0 0 0 0 1 1 0 0 0 0
as expected.
Now, back to your actual question. If you know how many elements the resulting vector should have, then you can use reshape:
mask = (50 < seals(:, 3, 1)) & (seals(:, 3, 1) < 100)
x = nanmean(seals(mask, :, :));
v = reshape(x(:, 3, :), 6, 1);
However, in this case you're using a search criteria to find which values to select and therefore probably don't know beforehand how long the final vector will be. Another option is then to first retrieve the values you want and then reshape them into a vector using the colon operator (:) like this:
mask = (50 < seals(:, 3, 1)) & (seals(:, 3, 1) < 100)
x = nanmean(seals(mask, :, :));
y = x(:, 3, :);
v = y(:);
In both cases I've also introduced a separate selection mask to slightly increase readability.

Matlab swap

I am trying to create a function that will swap a specific number in a matrix with a specific number in the same matrix. For examlpe, if I start with A = [1 2 3;1 3 2], I want to be able to create B = [2 1 3; 2 3 1], simply by telling matlab to swap the 1's with the 2's. Any advice would be appreciated. Thanks!
If you have the following matrix:
A = [1 2 3; 1 3 2];
and you want all the ones to become twos and the twos to become ones, the following would be the simplest way to do it:
B = A;
B(find(A == 1)) = 2;
B(find(A == 2)) = 1;
EDIT:
As Kenny suggested, this can even be further simplified as:
B = A;
B(A == 1) = 2;
B(A == 2) = 1;
Another way to deal with the original problem is to create a permutation vector indicating to which numbers should the original entries be mapped to. For the example, entries [1 2 3] should be mapped respectively to [2 1 3], so that we can write
A = [1 2 3; 1 3 2];
perm = [2 1 3];
B = perm(A)
(advantage here is that everything is done in one step, and that it also works for operations more complicated than swaps ; drawback is that all elements of A must be positive integers with a known maximum)
Not sure why you would to perform that particular swap (row/column interchanges are more common). Matlab often denotes ':' to represent all of something. Here's how to swap rows and columns:
To swap rows:
A = A([New order of rows,,...], :)
To Swap columns:
A = A(:, [New order of columns,,...])
To change the entire i-th column:
A(:, i) = [New; values; for; i-th; column]
For example, to swap the 2nd and 3rd columns of A = [1 2 3;1 3 2]
A = A(:, [1, 3, 2])
A = [1 2 3; 1 3 2]
alpha = 1;
beta = 2;
indAlpha = (A == alpha);
indBeta = (A == beta);
A(indAlpha) = beta;
A(indBeta ) = alpha
I like this solution, it makes it clearer what is going on. Less magic numbers, could easily be made into a function. Recycles the same matrix if that is important.
I don't have a copy of MatLab installed, but I think you can do some thing like this;
for i=1:length(A)
if (A(i)=1), B(i) = 2, B(i)=A(i)
end
Note, that's only convert 1's to 2's and it looks like you also want to convert 2's to 1's, so you'll need to do a little more work.
There also probably a much more elegant way of doing it given you can do this sort of thing in Matlab
>> A = 1:1:3
A = [1,2,3]
>> B = A * 2
B = [2,4,6]
There might be a swapif primitive you can use, but I haven't used Matlab in a long time, so I'm not sure the best way to do it.
In reference to tarn's more elegant way of swapping values you could use a permutation matrix as follows:
>> a =[1 2 3];
>> T = [1 0 0;
0 0 1;
0 1 0];
>> b = a*T
ans =
1 3 2
but this will swap column 2 and column 3 of the vector (matrix) a; whereas the question asked about swapping the 1's and 2's.
Update
To swap elements of two different values look into the find function
ind = find(a==1);
returns the indices of all the elements with value, 1. Then you can use Mitch's suggestion to change the value of the elements using index arrays. Remeber that find returns the linear index into the matrix; the first element has index 1 and the last element of an nxm matrix has linear index n*m. The linear index is counted down the columns. For example
>> b = [1 3 5;2 4 6];
>> b(3) % same as b(1,2)
ans = 3
>> b(5) % same as b(1,3)
ans = 5
>> b(6) % same as b(2,3)
ans = 6