#VALUES! while using IF and OR together - arrays

I have the File as following format
Name Number Position
A 1
B 2
C 3
D 4
Now on position A3 , I applied =IF(B2=1,"Goal Keeper",OR(IF(B2=2,"Defender",OR(IF(B2=3,"MidField","Striker"))))) But it giving me an error #value!
Looked up at google, and my formula is correct.
What i basically want it
1- Goalkeeper 2-Defender 3-Midfield 4-Striker
Yes the other way is to to just filter the number and copy paste the text
But I want to do it using formula and want to know where did I go wrong.

Your immediate problem lies with the expression (for example):
OR(IF(B2=3,"MidField","Striker"))
| \__/ \________/ \_______/ |
| bool string string |
\____________________________/
string
The OR function expects a series of boolean values (true or false) and you're giving it a string value from the inner IF.
You don't actually need the or bits in this specific case, the if is a full if-else. So you can just use:
=IF(B1=1,"Goal Keeper",IF(B2=2,"Defender",IF(B2=3,"MidField","Striker")))
This means that B1=1 will result in "Goal Keeper", otherwise it will evaluate IF(B2=2,"Defender",IF(B2=3,"MidField","Striker")).
Then that means that, if B2=2, it will result in "Defender", otherwise it will evaluate IF(B2=3,"MidField","Striker").
Finally, that means the B2=3 will result in "MidField", anything else will give "Striker".
The only situation I can envisage when OR would come in handy here would be when two different numbers were to generate the same string. Let's say both 1 and 4 should give "Goalie", you could use:
=IF(OR(B1=1,B1=4),"Goalie",IF(B2=2,"Defender","MidField"))
Keep in mind that a more general solution would be better implemented with the Excel lookup functions, ones that would search a table (on the spreadsheet somewhere) which mapped the integers to strings. Then, if the mapping needed to change, you would just update the table rather than going back and changing the formula in every single row.

If you are actually tasked with solving the problem by using the IF and OR function within the same equation, this is the only way I can see how:
=IF(OR(B1=1, B1 = 2, B1 = 3, B1 = 4),IF(B1 = 1, "Goal Keeper", IF(B1 = 2,"Defender",IF(B1 = 3,"MidField","Striker")))
If B1 does not equal 1-4, the OR function will return FALSE and completely bypass all of the nested IF statements.

Related

Structuring a for loop to output classifier predictions in python

I have an existing .py file that prints a classifier.predict for a SVC model. I would like to loop through each row in the X feature set to return a prediction.
I am currently trying to define the element from which to iterate over so as to allow for definition of the test statistic feature set X.
The test statistic feature set X is written in code as:
X_1 = xspace.iloc[testval-1:testval, 0:5]
testval is the element name used in the for loop in the above line:
for testval in X.T.iterrows():
print(testval)
I am having trouble returning a basic set of index values for X (X is the pandas dataframe)
I have tested the following with no success.
for index in X.T.iterrows():
print(index)
for index in X.T.iteritems():
print(index)
I am looking for the set of index values, with base 1 if possible, like 1,2,3,4,5,6,7,8,9,10...n
seemingly simple stuff...i haven't located an existing question via stackoverflow or google.
ALSO, the individual dataframes I used as the basis for X were refined with the line:
df1.set_index('Date', inplace = True)
Because dates were used as the basis for the concatenation of the individual dataframes the loops as written above are returning date values rather than
location values as I would prefer hence:
X_1 = xspace.iloc[testval-1:testval, 0:5]
where iloc, location is noted
please ask for additional code if you'd like to see more
the loops i've done thus far are returning date values, I would like to return index values of the location of the rows to accommodate the line:
X_1 = xspace.iloc[testval-1:testval, 0:5]
The loop structure below seems to be working for my application.
i = 1
j = list(range(1, len(X),1)
for i in j:

Excel how to return an array that meets a certain condition?

If I have data in cell range A1:A6 which is:
Apple
Banana
Cherry
Grape
Orange
Watermelon
Is there a way to return an array (in a single cell, for an intermediate step for a larger formula) which returns the above array except only those entries that satisfy a certain condition?
For example, if I wanted a formula to return an array of only those cells that contain the letter n, it would return this:
Banana
Orange
Watermelon
Is there a way to accomplish this?
Note I do not want to return an array of the same size, just with blank entries, i.e. I do not want:
""
Banana
""
""
Orange
Watermelon
Yes.
Here is the array formula (line break added for readability):
= INDEX(A1:A6,N(IF({1},MODE.MULT(IF(ISNUMBER(SEARCH("n",A1:A6)),
(ROW(A1:A6)-ROW(A1)+1)*{1,1})))))
Note, this is an array formula, meaning you must press Ctrl+Shift+Enter after typing the formula instead of just Enter.
There's some particularly odd things about this formula so I thought I would explain what is going below if you are interested. Some of what I explain below is probably obvious, but I am just being thorough.
To return a result from a list based on a single index, use this:
= INDEX(A1:A6,2)
This would return Banana.
To return results from a list based on multiple indices, you would think to use something like this:
= INDEX(A1:A6,{2;5;6})
This would ideally return {Banana;Orange;Watermelon}.
However, this does not return an array. Based on a recent question that I asked, a very clever workaround to this problem was given:
= INDEX(A1:A6,N(IF({1},{2;5;6})))
This will return the desired result of {Banana;Orange;Watermelon}.
This I consider part 1 of the explanation.
Part 2 of the explanation is how the following returns {2;5;6}:
= MODE.MULT(IF(ISNUMBER(SEARCH("n",A1:A6)),(ROW(A1:A6)-ROW(A1)+1)*{1,1}))
MODE.MULT is a function that returns the data in a set that appears most frequently. There are a few caveats, however:
Data must appear at least twice to be returned by MODE.MULT. If there is no duplicate data, it will return an error. For example, MODE.MULT({1;2;3}) would return an error because there is no repeating data in the array {1;2;3}. Another example: MODE.MULT({1;1;2} would return 1 because 1 appears most often in the data.
If there is a "tie" in terms of what data appears the most, MODE.MULT returns an array of all tied entries. For example MODE.MULT({1;1;2;2}) would return an array of {1;2}.
Most importantly, and probably the most peculiar but also most useful behavior of MODE.MULT, MODE.MULT completely ignores logical values (TRUE and FALSE values) when determining the mode of the data, even if they appear more often than the non-logical values in the data.
We can exploit these properties of MODE.MULT to get the desired array.
ISNUMBER(SEARCH("n",A1:A6)) returns an array of TRUE/FALSE values where the data contains an n. Something like this:
FALSE
TRUE
FALSE
FALSE
TRUE
TRUE
(ROW(A1:A6)-ROW(A1)+1) returns an array starting at 1 and increasing by 1 to however large the original array is:
1
2
3
4
5
6
(ROW(A1:A6)-ROW(A1)+1)*{1,1} effectively just copies this column:
1 1
2 2
3 3
4 4
5 5
6 6
The IF statement is used to return the number in the array above if TRUE, and FALSE otherwise. (Since the IF statement contains no "else" clause, FALSE is the default value given.)
In this example, the IF statement would return this:
FALSE FALSE
2 2
FALSE FALSE
FALSE FALSE
5 5
6 6
Taking MODE.MULT of the above formula will return {2;5;6} because as mentioned, MODE.MULT conveniently ignores the FALSE values in the array above when considering the mode.
It is necessary to consider the above array inside MODE.MULT instead of simply:
FALSE
2
FALSE
FALSE
5
6
Because as mentioned previously, MODE.MULT requires that at least two entries in the data are required to match for it to return a value.
=INDEX($A$2:$A$7,MATCH(1,(COUNTIF($C$1:C1,$A$2:$A$7)=0)*(FIND("n",$A$2:$A$7)>0),0))
This is an array formula so will need to entered with Ctrl+Shift+Enter
Input and output
The INDEX returns an element from a range
The MATCH allows us to find the position of the row(s) to return
The COUNTIF is to make sure we only select unique values in the results
The FIND returns only rows where there is a n present in the string
Try the following User Defined Function:
Public Function ContainsN(rng As Range) As String
Dim r As Range
ContainsN = ""
For Each r In rng
If InStr(1, UCase(r.Value), "N") > 0 Then ContainsN = ContainsN & Chr(10) & r.Value
Next r
ContainsN = Mid(ContainsN, 2)
End Function
I came across this post while searching for a solution to a similar problem: return an array of expiration dates for all batches of a specific SKU.
I transposed a filter function so that my array of Batch Exp dates would appear on the same line as my Inventory SKU.
=IFERROR(TRANSPOSE(FILTER('Batch EXP'!$A$2:$A$1000,('BatchEXP'!$B$2:$B$1000=Inventory!$R4))),"No Expiration")
Added a concatenate column onto my filter range where I could combine quantities (F4) associated with each expiration date (I4).
=CONCATENATE(TEXT(I4,"MM-DD-YY")," x ",TEXT(F4,"#,#"), " units")
It works great and returns all an array for SKUS that match the criteria I setout. Could even take one step further to only return batches > X %, qty, etc. Here is example of output for a SKU:
11-15-22 x 40 units 11-01-22 x 5,216 units

Excel nested if array

I am doing a nested min if array, and am having issue with it reading blanks.
=MIN(IF(Sheet1!$C:$C<=A24,IF(Sheet1!$AE:$AE>A24,Sheet1!$C:$C),IF(Sheet1!$C:$C<=A24,IF(Sheet1!$AE:$AE="",Sheet1!$C:$C))))
So in English, I'm asking that if the dates in sheet 1 column C are less than or equal to the value in A24, and the date in sheet 1 column AE is after the date in A24, OR the value in sheet 1 column AE is blank, give me the earliest date of what's left from column C. I hope that makes sense!
Any help would be greatly appreciated as I have spent literally hours on this trying isblanks, further nested if, all with no joy.
If you have Excel 2010 this AGGREGATE() Function will work:
=AGGREGATE(15,6,(Sheet1!C:C/((Sheet1!C:C<=A24)*((Sheet1!AE:AE>A24)+(Sheet1!AE:AE="")))),1)
If you have 2007 or earlier then the array formula should do it:
=MIN(IF(((Sheet1!C:C<=A24)*((Sheet1!AE:AE>A24)+(Sheet1!AE:AE=""))),Sheet1!C:C))
Being and array it must be entered with Ctrl-Shift-Enter instead of just Enter or Tab.
The issue is when using the or in arrays one should use +. So now if (Sheet1!AE:AE>A24) or (Sheet1!AE:AE="") are true it will return a 1 because 0+1=1.
Where the and portion is * because 0 * 1= 0. So both would need to be true to return the 1, or true.
Do you have to use nested if's?
Why not have the if statement evaluate all three conditions. An OR function to check two conditions (check for blanks OR value in col AE is greater an A24. Then, have the result of the OR function feed into an AND function along with the third check (column C less than or equal to A24). Then if the entire logical check of the IF function returns TRUE, use a MIN function to give you the minimum value in Column C. Likewise, if the logical check of the IF function evaluates to False,
do something else (ex. "No Match")
something like this:
=(IF(AND(COL_C <= $A$24, OR(COL_AE > $A$24, ISBLANK(COL_AE))),MIN(COL_C,"No Match"))

Ignore blank parameters in Excel array formula

I'm using an array formula to return sums and counts on a large data set.
The array formula can have up to 3 arguments but the formula needs to accommodate when any or all of the arguments are <blank>, WITHOUT using VBA.
For example
A1 = "Australia"
B1 = "Finance"
C1 = "Female"
D1 contains the formula
D1 = {count(if((region=A1)*(sector=B1)*(gender=C1),population))}
Sometimes one of the criteria will be blank
A1 = "Australia"
B1 = <blank>
C1 = "Male"
In this case I'd like the formula to return the equivalent of:
D1 = {count(if((region=A1)*(gender=C1),population))}
In the extreme case A1, B1 and C1 could be all blank in which case the formula in D1 should return the equivalent of Count(population)
Is there a way to create an array formula that accounts for these possibilities? I originally tried to create a dynamic argument string
E1 = "(region=A1)*(sector=B1)*(gender=C1)"
and then use the string as the argument within the array formula
D1 = {count(if(E1,population))}
but I could find a way to get this to work.
I've tried a number of solutions, but there is always a key element missing. By using isblank I can determine if the cell is blank, but in order for this to be useful I'd need to turn this returned value into an array of boolean values of length count(population).
Any and all ideas are greatly appreciated.
Thanks.
Have you tried Nz() ? Encapsulate your current code with that and give it a try. I've had issues with blanks/nulls here and there myself.
Another option could be the IIF() statement. But that might not do what you want it to. Here are reference links:
Nz: http://www.techonthenet.com/access/functions/advanced/nz.php
IIF: http://www.techonthenet.com/access/functions/advanced/iif.php
You don't need VBA and you also don't even need an array formula. You can use SUMPRODUCT() with wildcards.
Say we have:
In A2 enter:
=IF(A1="","*",A1)
and copy across. This will display either an asterisk or the value above.
Then use:
=SUMPRODUCT(ISNUMBER(SEARCH(A2,G1:G10,1))*ISNUMBER(SEARCH(B2,H1:H10,1))*ISNUMBER(SEARCH(C2,I1:I10,1)))
This is a way to get SUMPRODUCT() to accept the asterisk as a wildcard:

Finding whether a value is equal to the value of any array element in MATLAB

Can anyone tell me if there is a way (in MATLAB) to check whether a certain value is equal to any of the values stored within another array?
The way I intend to use it is to check whether an element index in one matrix is equal to the values stored in another array (where the stored values are the indices of the elements which meet a certain criteria).
So, if the indices of the elements which meet the criteria are stored in the matrix below:
criteriacheck = [3 5 6 8 20];
Going through the main array (called array) and checking if the index matches:
for i = 1:numel(array)
if i == 'Any value stored in criteriacheck'
%# "Do this"
end
end
Does anyone have an idea of how I might go about this?
The excellent answer previously given by #woodchips applies here as well:
Many ways to do this. ismember is the first that comes to mind, since it is a set membership action you wish to take. Thus
X = primes(20);
ismember([15 17],X)
ans =
0 1
Since 15 is not prime, but 17 is, ismember has done its job well here.
Of course, find (or any) will also work. But these are not vectorized in the sense that ismember was. We can test to see if 15 is in the set represented by X, but to test both of those numbers will take a loop, or successive tests.
~isempty(find(X == 15))
~isempty(find(X == 17))
or,
any(X == 15)
any(X == 17)
Finally, I would point out that tests for exact values are dangerous if the numbers may be true floats. Tests against integer values as I have shown are easy. But tests against floating point numbers should usually employ a tolerance.
tol = 10*eps;
any(abs(X - 3.1415926535897932384) <= tol)
you could use the find command
if (~isempty(find(criteriacheck == i)))
% do something
end
Note: Although this answer doesn't address the question in the title, it does address a more fundamental issue with how you are designing your for loop (the solution of which negates having to do what you are asking in the title). ;)
Based on the for loop you've written, your array criteriacheck appears to be a set of indices into array, and for each of these indexed elements you want to do some computation. If this is so, here's an alternative way for you to design your for loop:
for i = criteriacheck
%# Do something with array(i)
end
This will loop over all the values in criteriacheck, setting i to each subsequent value (i.e. 3, 5, 6, 8, and 20 in your example). This is more compact and efficient than looping over each element of array and checking if the index is in criteriacheck.
NOTE: As Jonas points out, you want to make sure criteriacheck is a row vector for the for loop to function properly. You can form any matrix into a row vector by following it with the (:)' syntax, which reshapes it into a column vector and then transposes it into a row vector:
for i = criteriacheck(:)'
...
The original question "Can anyone tell me if there is a way (in MATLAB) to check whether a certain value is equal to any of the values stored within another array?" can be solved without any loop.
Just use the setdiff function.
I think the INTERSECT function is what you are looking for.
C = intersect(A,B) returns the values common to both A and B. The
values of C are in sorted order.
http://www.mathworks.de/de/help/matlab/ref/intersect.html
The question if i == 'Any value stored in criteriacheck can also be answered this way if you consider i a trivial matrix. However, you are proably better off with any(i==criteriacheck)

Resources