I have a horizontal matrix of values in Excel that I want to be able to show a quantity in a series up to a predetermined total value. If the last value in the series is less than the specified quantity then the value that will satisfy the cumulative sum is the value used. Empty values thereafter.
For example: Max cumulative sum of 200 in 7 units of 30: 30,30,30,30,30,30,20.
Should be straightforward but I've had some trouble doing it. Thanks.
I've tried nested if thens with conditional sums but the formulas seems more less helpful than the basic explanation of what's needed.
I can do most of the function but the nested if thens are too complex and are creating problematic edge cases. Hoping someone has a more concise idea.
You could combine some MOD and INT together, cell A1put this formula and drag it to the right:
=IF(COLUMN()<=200/30,30,IF(COLUMN()=INT(200/30)+1,MOD(200,30),""))
Obviously you can reference these 200 and 30 from an absolute cell address.
Example to add to 308 in steps of 14:
Formula in A1:
=IF(COLUMN()<=$A3/$A4,$A4,IF(COLUMN()=INT($A3/$A4)+1,MOD($A3,$A4),""))
Another example to add to 312 in steps of 14:
You can use Min to determine the value for each cell, and Index to specify the range
Like this (also handle returning blanks for columns past the last value)
=IFERROR(1/(1/MIN($A$2-SUM(INDEX(4:4,1,1):INDEX(4:4,1,COLUMN()-1)),$A$3)),"")
Related
I am trying to calculate a running average on a filtered data table. All other posts online use Sumproduct(Subtotal) on the entire range but do not calculate a row by row running average
I am stuck on how to calculate columns C and D.
If column B (Score) > 0, I want to sum and average it under column C (Average Win)
If column B (Score) < 0, I want to sum and average it under column D (Average Loss)
The table is filterable by column A (Type) and the results should look as follows
Progress so far:
I have figured out how to calculate a Cumulative score based on filtered data. However this does not fully solve my problem. I appreciate any help!
=SUBTOTAL(3,B3)*SUBTOTAL(9,B$3:B3)
SUBTOTAL(3,B3) checks if the current row is visible, SUBTOTAL(9,B$3:b3) sums the values.
Final update needed
Jos - Thank you for your detailed explanation on how subtotal() works. I learned a ton through your explanation and will continue to study it. This is my first time being exposed to structured referencing so some of the syntax is a bit confusing to me still
The last formula I need is a running win % column where a Win is defined by score > 0. Please see the picture below
My assumptions believe that the same formula would work, except that we average a 1 or 0 in each row instead of the [Score] column.
Using the prior solution, why can't we modify the output of your prior solution to calculate a running win %?
[...] IF([Score]>0,IF(ROW([Score])<=ROW([#Score]),[Win])))),0)
Where [Win] is a helper column with the outputs 1 for win, 0 for loss.
This could be done by saying
if([#score]>0,1,0)
Instead of averaging out the actual #Score, this would average out a column of 1's and 0's with the desired output 0%, 50%, 66%, etc.
I am aware that the solution I provided does not work but I am trying to embrace the correct logic. I still struggle to understand how these structured column references are calculated on a row by row basis.
For example: Average(If([Score]>0,[Score])
How is this calculated on a row by row basis? When A3 does If([Score] > 0,), does this equal If({-10}>0)? When on A4, does If([Score]>0) equal If({-10,20} >0)? Thank you for your patience and help thus far.
I disagree with your result for Average Loss for the last row of your unfiltered table (surely -9.33...?), but try this for Average Win:
=IFERROR(AVERAGE(IF(SUBTOTAL(3,OFFSET(INDEX([Score],1),ROW([Score])-MIN(ROW([Score])),)),IF([Score]>0,IF(ROW([Score])<=ROW([#Score]),[Score])))),0)
Same formula for Average Loss, changing [Score]>0 to [Score]<0.
Explanation:
Using the data you provided and assuming:
The table's top-left cell is in A1
The table is filtered on the Type column for "A"
In order to determine which rows are filtered, we must pass an array of range references - i.e. for each cell within a chosen column of the table - to the SUBTOTAL function. It's a touch unfortunate that such an array of range references can only be generated via a volatile function (INDIRECT or OFFSET), but here, unless we resort to helper columns, we are left with no choice.
INDEX([Score],1)
simply returns a range reference to the first cell within the Score column. When using Excel tables, it's preferable not to write formulas which include a mixture of structured and non-structured referencing, even if that results in slightly longer expressions. So here, for example, we would not reference A2 within the formula.
ROW([Score])-MIN(ROW([Score]))
generates an array of integers from 0 up to one fewer than the number of rows in the table, i.e.
{0;1;2;3;4}
and so
=IFERROR(AVERAGE(IF(SUBTOTAL(3,OFFSET(INDEX([Score],1),ROW([Score])-MIN(ROW([Score])),)),IF([Score]>0,IF(ROW([Score])<=ROW([#Score]),[Score])))),0)
becomes
=IFERROR(AVERAGE(IF(SUBTOTAL(3,OFFSET(A2,{0;1;2;3;4},)),IF([Score]>0,IF(ROW([Score])<=ROW([#Score]),[Score])))),0)
OFFSET then generates an array of range references (though note that you will not be able to 'see' this step within the Evaluate Formula window - rather, an array of #VALUE! errors is displayed):
=IFERROR(AVERAGE(IF(SUBTOTAL(3,{A2;A3;A4;A5;A6}),IF([Score]>0,IF(ROW([Score])<=ROW([#Score]),[Score])))),0)
SUBTOTAL then determines which of these range references is filtered (note that care must be given here to the choice of first parameter), returning the relevant Boolean, so that:
SUBTOTAL(3,{A2;A3;A4;A5;A6})
resolves to:
{1;1;1;0;1}
And so we now have:
=IFERROR(AVERAGE(IF({1;1;1;0;1},IF([Score]>0,IF(ROW([Score])<=ROW([#Score]),[Score])))),0)
and the rest is straightforward.
So, I would use averageifs().
=averageifs(B:B,B:B,">=1",A:A,"A")
is one example, note I have added the control of Type A in the example.
See:
I have two Excel lists:
One extensive with 20 thousand lines. In which:
Two columns are important: First: Unique ID, Second: a value (number formatted).
It can be a value that appears several times, or only once.
I have to create the second list. In this list I have only one column of values that I would like to have.
I need a formula that will look for values from List 2 in List 1 and then match a Unique ID to each value.
It is important that, when no direct value exist. In this case it has to search for a sample which is in about 3-5% value deviation.
Example: there was no value 127, but within 3%, 125 was found.
I've tried indexing and comparison, but it does not seem to work.
VLOOKUP worked, but without 3-5% deviation
I am very grateful for the help.
Example: http://www.filedropper.com/excellist1and2
If the value exists in the list, you can use VLOOKUP or INDEX(MATCH to find it - that's the easy part. If the value is not in the list, then you need to find the nearest value.
The nearest "low" value will be the MAX value ≤ our input, and the nearest "high" value will be the MIN value ≥ our input.
If you have Office 365, you can use MINIFS($D$1:$D$6,$D$1:$D$6,">="&B1,$D$1:$D$6,"<="&(B1*1.05)) and MAXIFS($D$1:$D$6,$D$1:$D$6,"<="&B1,$D$1:$D$6,">="&(B1*0.95)) )` here. If not, you'll need an Array Formula, we can build that "±5%" in early, to simplify the formula.
Starting with the Low values, we want the MAX value ≤ our input and ≥ 95% of our input. Putting an Array Formula in a SUMPRODUCT so that we can use it in a normal formula, we get =SUMPRODUCT(MAX($D$1:$D$6*--($D$1:$D$6<=B1)*--($D$1:$D$6>=(B1*0.95))))
The High values are slightly harder, because we can't just multiply be 0 to cancel out anything too low, or over 105% of the target. We need to add a huge number like 1E+99 (a 1 with ninty-nine 0s after it) instead, so that the MIN will ignore them: SUMPRODUCT(MIN($D$1:$D$6+1E+99*(--($D$1:$D$6<B1)+--($D$1:$D$6>(B1*1.05)))))
The last steps are to decide which of these numbers is closer to the target, and then to find the Unique ID to match. The %closeness calculations are (TARGET - LOW)/TARGET and (HIGH - TARGET)/TARGET), and subtracting one from the other gives you 2-(HIGH + LOW)/TARGET - a Positive number means "High" is closer, a Negative number means that "Low" is closer, and 0 means they are both the same distance (I'll default this to the Low number). We then use SIGN to change it to ±1, add 2 to get 1,2 or 3 and finish up with CHOOSE to output our number. In pseudo-code, CHOOSE(2+SIGN(2-(HIGH+LOW)/TARGET),LOW,LOW,HIGH), and the full thing:
CHOOSE(2+SIGN(2-(SUMPRODUCT(MAX($D$1:$D$6*--($D$1:$D$6<=B1)*--($D$6>B1*0.95)))+SUMPRODUCT(MIN($D$1:$D$6+1E+99*(--($D$1:$D$6<B1)+--($D$1:$D$6>(B1*1.05))))))/B1),SUMPRODUCT(MAX($D$1:$D$6*--($D$1:$D$6<=B1)*--($D$6>B1*0.95))),SUMPRODUCT(MAX($D$1:$D$6*--($D$1:$D$6<=B1)*--($D$6>B1*0.95))),SUMPRODUCT(MIN($D$1:$D$6+1E+99*(--($D$1:$D$6<B1)+--($D$1:$D$6>(B1*1.05))))))
Now, we have a number. All we need to do is either use VLOOKUP, or use MATCH to get the row it is on, and INDEX to pull the data for that row:
Office 365:
=IFERROR(VLOOKUP(B1,$D$1:$E$6,2,FALSE),VLOOKUP(CHOOSE(2+SIGN(2-(MAXIFS($D$1:$D$6,$D$1:$D$6,"<="&B1,$D$1:$D$6,">="&(B1*0.95))+MINIFS($D$1:$D$6,$D$1:$D$6,">="&B1,$D$1:$D$6,"<="&(B1*1.05)))/B1),MAXIFS($D$1:$D$6,$D$1:$D$6,"<="&B1,$D$1:$D$6,">="&(B1*0.95)),MAXIFS($D$1:$D$6,$D$1:$D$6,"<="&B1,$D$1:$D$6,">="&(B1*0.95)),MINIFS($D$1:$D$6,$D$1:$D$6,">="&B1,$D$1:$D$6,"<="&(B1*1.05))),$D$1:E$7,2,FALSE))
Otherwise:
=IFERROR(VLOOKUP(B1,$D$1:$E$6,2,FALSE),VLOOKUP(CHOOSE(2+SIGN(2-(SUMPRODUCT(MAX($D$1:$D$6*--($D$1:$D$6<=B1)*--($D$6>B1*0.95)))+SUMPRODUCT(MIN($D$1:$D$6+1E+99*(--($D$1:$D$6<B1)+--($D$1:$D$6>(B1*1.05))))))/B1),SUMPRODUCT(MAX($D$1:$D$6*--($D$1:$D$6<=B1)*--($D$6>B1*0.95))),SUMPRODUCT(MAX($D$1:$D$6*--($D$1:$D$6<=B1)*--($D$6>B1*0.95))),SUMPRODUCT(MIN($D$1:$D$6+1E+99*(--($D$1:$D$6<B1)+--($D$1:$D$6>(B1*1.05)))))),$D$1:E$7,2,FALSE))
(Obviously, change $D$1:$D$6 and $D$1:$E$6 to your actual data table ranges, and B1 to the input-value range)
Working formula:
=INDEX({249,749,1999,4999,9999,10000,19999,50000},RANDBETWEEN(1,COUNTA(249,749,1999,4999,9999,10000,19999,50000)))
Amendment needed
249,749,1999,4999,9999,10000,19999,50000 are fixed INDEX and can be easily RANDBETWEEN.
I want to add a range of 500 to 1500 in INDEX and RANDBETWEEN.
Is there any way to include the range of 500 to 1500 in this formula? If not then what is correct way to create a formula as per my needs.
Here is one way.
In an empty column, type your numbers 249,1999,4999,9999,10000,19999,50000. I have removed 749 as it falls in the range 500-1500. Next type 500, 501 and then drag it down to 1500. Let's say you have them in Col A. You can also do this in a separate worksheet.
So if you start at A1 then the values will go up to row 1008 as shown in the image below.
Now use this formula
=INDEX(A1:A1008,RANDBETWEEN(1,1008))
=IF(Randbetween(1,1009)<=1001,randbetween(500,1500),INDEX({249,749,1999,4999,9999,10000,19999,50000},randbetween(1,8)))
A random integer is determined between 1 and the number of possible numbers. if it is less than or equal to the number in the sequential range 500 to 1500, which is 1001, then we tell then we use the randbetween (500,1500). If the initial number if greater than our range, then we have it pull a random number from our supplied list of numbers. 8 is the number of supplied numbers in the static array.
Now if I recall correctly, randbetween is a volatile function. As such anytime something in your work book changes, this formula will recalculate and provide a new number.
UPDATE:
Since you want to limit the 500-1500 range to 35% of the time, try using either of the formulas below:
=IF(Randbetween(1,100)<=35,randbetween(500,1500),INDEX({249,749,1999,4999,9999,10000,19999,50000},randbetween(1,8)))
=IF(Rand()<=0.35,randbetween(500,1500),INDEX({249,749,1999,4999,9999,10000,19999,50000},randbetween(1,8)))
I am trying to use index match functions to determine the appropriate rate for the below table.
So for example a consumer loan that is for a person that owns property, the car is 2 years or less in age and the total loan to value ratio is less than 140% should return a value of 5.15%
I believe this is what you wanted...
I would use a series of nested if functions to evaluate which column of LTV I would want the value to come from.
"That is what is done in the AND( ) part. If the value is greater than the 110% and smaller than 140% let's do the Index Match on the 110% Column, Otherwise do it on the 140% Column."
You could extend this for more columns with more IFs in the false condition.
Then it is a simple INDEX match with concatenation. It searches for the three parameters all concatenated in a single range of concatenations.
Hope it helped.
Proof of Concept
In order to achieve the above I had to make a minor edit to your header to be able to distinguish between the two 140% columns.
The functions used in this answer are:
AGGREGATE function
MATCH function
INDEX function
ROW function
IFERROR function
I placed the main part of the formula inside the IFERROR function as a way of dealing with things that may be out of range or when not all the input have been provided. I then assumed that what you were basing your search on would be provided in a series of cells. In my example I assumed the questions would be asked in the range H3 to K3 and I place the results in L3.
The main concept is centered around the INDEX function. I specified the index range as being the height of your table and the width of the percentage rates. Or for this example D2:F9.
=IFERROR(INDEX($D$2:$F$9,row number, column number),"Not Found")
That is the easy part. That more challenging part is determining the row and column number to look in. Lets start with the column number as it is the slightly easier of the two. I assumed the ratio to look for, or rather the header of the column to look in would be supplied. I basically used this equation to determine the column number:
=MATCH(K3,$D$1:$F$1,0)
which in layman's terms is which column between D and F, counting column D as 1, has the value equal to the contents of K3. So now that there is a formula to determine the column, we can drop that into our original formula and wind up with:
=IFERROR(INDEX($D$2:$F$9,row number,MATCH(K3,$D$1:$F$1,0)),"Not Found")
Now we just need to determine the row number. This is the most complex operation. We are going to basically make a bunch of logical checks and take the first row that matches all the logical checks. The premise here is that a logical check is either TRUE or FALSE. In excel 0 is false an every other integer is TRUE. So if we multiply a series of logical checks together, only the one that is true in all cases will be equal to 1. The first logical check is the loan type. it will be followed by the living status and then the vehicle age.
=(H3=$A$2:$A$9)*(I3=$B$2:$B$9)*(J3=C2:C9)
now if you put that into an array formula you will get a series of true false or 1/0. We are going to use it inside an AGGREGATE function with a special feature. The AGGREGATE function will perform array like calculation for some of its functions. We are going to use function 15 which will do this. We are also going to tell the aggregate function to ignore all errors, which is what the 6 does. So in the end what we wind up doing is dividing each row number by the logical check. If the logical check is false or 0, it will generate a Div/0! error which aggregate will choose to ignore. In the end we wind up with a list of row which match our logical check. We then tell the aggregate that we want the first result with the ,1. so we wind up with a formula that looks like:
=AGGREGATE(15,6,ROW($A$2:$A$9)/((H3=$A$2:$A$9)*(I3=$B$2:$B$9)*(J3=C2:C9)),1)
While this does provide us with the row number we want, we need to adjust it to make it an index number. In order to do this you need to subtract the number of header rows. In this case 1. So the index row number is given by this formula:
=AGGREGATE(15,6,ROW($A$2:$A$9)/((H3=$A$2:$A$9)*(I3=$B$2:$B$9)*(J3=C2:C9)),1)-1
And when we substitute that back into the earlier equation for the row number, we wind up with the final equation of:
=IFERROR(INDEX($D$2:$F$9,AGGREGATE(15,6,ROW($A$2:$A$9)/((H3=$A$2:$A$9)*(I3=$B$2:$B$9)*(J3=C2:C9)),1)-1,MATCH(K3,$D$1:$F$1,0)),"Not Found")
Part 1:
I was able to construct a formula that does exactly what I want (from some examples), but yet, I'm unable to figure out how exactly it works. I have, starting with cell A1:
Price $
table 20
chair 10
Invoice Quantity
table 17
chair 1
chair 2
table 3
What I want is the final total (430) for the invoice which is computed as Quantity*Price for each item (17*20 + 1*10 + 2*10 + 3*20). the following formula correctly does this:
=SUMPRODUCT(B6:B9,SUMIF(A2:A3,A6:A9,B2:B3))
I understand the basics of SUMPRODUCT and SUMIF. But here, my argument for SUMIF's range is A2:A3, which makes me think the SUMIF would iterate through A2 and A3, and not through A8:A11 (which is the criteria). What gives?
Edit: the unclear part is, what exactly does SUMIF do (what is its iteration pattern) when the first two arguments are of different dimensions (here, the range is 2 cells while the criteria is 4 cells). Also, what is the "output" of SUMIF? An array? Of what dimensions?
Part 2:
In addition, if I ignored the quantity and simply wanted to add 20 whenever I saw a table and 10 whenever I saw a chair, I figured I would do:
=SUMIF(A2:A3,A6:A9,B2:B3)
But that doesn't work, and I have to enclose it with a SUMPRODUCT() for it to work and correctly evaluate to 60. Enclosing it within a SUM doesn't work either (probably because the SUMIF doesn't return an array?) Why?
I've read a bunch of tutorials and still can't understand this, and would be most grateful for a clear, intuitive explanation for both these cases. Thank you.
SUMIF can produce an array of results. If you take my formula
=SUMIF(A6:A9,A2:A3,B6:B9)
it says
For the criteria in A2 (ie table)
- look at A6:A9
- where table is matched, sum the corresponding value in B6:B9
- returns 20 (ie 17 +0 +0 +3)
- this is stored in the first position of the array
Then for the criteria in A3 (ie chair)
- look at A6:A9
- where table is matched, sum the corresponding value in B6:B9
- returns 3 (ie 0 +1 +2 +0)
- this is stored in the second position of the array
So the end array from the SUMIF is {20:3}
You can see the array result by highlighting the SUMIF formula in Excel's formula bar and then pressing F9
Then use SUMPRODUCT to multiple the count in the SUMIF by the $ values in B2:B3 to get total dollars
={20;3}*{20:10}
=20*20 + 3*10
= 430
Part 1
Rather than
SUMIF(A2:A3,A6:A9,B2:B3)
which produces a four element array of
={20;10;10;20}
(corresponding to table;chair;chair;table)
You should use
SUMIF(A6:A9,A2:A3,B6:B9)
which sums the values in B6:B9 against your two criteria in A2:A3 giving the desired result
={20;3}
(corresponding to table;chair)
and then use SUMPRODUCT to weight your array, ie
=SUMPRODUCT(SUMIF(A6:A9,A2:A3,B6:B9),B2:B3)
={20;3}*{20:10}
=430
Part 2
Use COUNTIF to return an array of the number of chairs and tables and then multiply by the vales using SUMPRODUCT
=SUMPRODUCT(B2:B3,COUNTIF(A6:A9,A2:A3))
={20;10} * {2;2}
=60
Well you only have one minor mistake:
probably because the SUMIF doesn't return an array?
SUMIF can work with arrays, thats why you formula SUMPRODUCT( SUMIF() ) works in first place, to SUMIF show an array you have to select a group of cells (like C6:C9) input the formula and use CTRL+SHIFT+ENTER instead of ENTER only. this generate an "array fomula", identified by curly brackets {} (those can only be entered with CTRL+SHIFT+ENTER, no manualy) and show the array formula and results