I have a bunch of sequential rows and I'm trying to average the last 90 based on a criteria. The average needs to be in a single cell, rather than a column that calculates a running average. I figured out how to calculate an average for the last 90 rows, but I am not able to correctly add the if function to meet the criteria prior to averaging.
Data:
sale type (b) Data(c) Rownumber (E)
a 45 1
b 35 2
c 36 3
c 56 93
Here is the average function that's working correctly AVERAGE(OFFSET(E2,COUNTA(E:E)-1,-2,-90)).
Here is the AVERAGEIF function that I'm trying to run that is giving incorrect data:
=AVERAGEIF(B:B,I15,OFFSET(E2,COUNTA(E:E)-1,-2,-90))
I15 cell in this case, is the sale type that I am trying to match.
Thanks in advance for the help!
=AVERAGEIF(OFFSET(B2,COUNTA(E:E)-2,0,-90),$I$15,OFFSET(C2,COUNTA(E:E)-2,0,-90))
first: you need to "-2", not "-1" from your row, you're not getting the last 90 with -1 .. (test it by changing a record in data to "999" at the outskirts. You'll see it pick up that value when the AVG changes dramatically.)
second: your and range have to match .. heights anyway. So use the same offset formula in both.
To slightly optimize this, you could calc that "COUNTA(E:E)-2" in another column, name it, then just reference it in both cases (that way Excel only calcs it once, not twice). ;)
Also, if the I15 cell is a single cell, you might want to $I$15 it to be safe. I don't think this matters in this case, just a habit of doing that to single, isolated cells that aren't part of a range :)
If you actually have row numbers (of the data) in column E you could use AVERAGEIFS and just use another criteria based on column E, like this:
=AVERAGEIFS(C:C,B:B,I15,E:E,">"&MAX(E:E)-90)
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 a large column of data where every 10 rows is a different set.
What I would like to do is get the average of those 10 rows, and then subtract that from every individual measured value.
Then it moves to the next 10, takes the average of those, and subtracts it from the 10 data points that yielded the new average.
I've tried using MOD and plenty of formulas and dragging out some kind of formula but Excel's pattern recognition is not working at all in this case.
Example of what I'm trying to do using 3 values instead of 10
The output I want takes the average of the first 3 values ((1+2+3)/3=2), then subtracts it from those 3 values and outputs it as the result. (1-2=-1, 2-2=0, 3-2=1). Then it repeats the same thing with the next 3 and the results from the previous 3 do not affect it.
Values________Average_______Result
1|__________________________-1
2|______________2 __________ 0
3|__________________________1
2|__________________________-2
5|______________4 __________ 1
5|___________________________1
2|___________________________-1
5|_____________3_____________2
2|___________________________-1
(I'm so sorry about the awful table)
Any help would be greatly appreciated! Thank you.
Using your data and doing every three:
=A2-AVERAGE(INDEX(A:A,INT((ROW(1:1)-1)/3)*3+2):INDEX(A:A,INT((ROW(1:1)-1)/3)*3+4))
To change to 10 change the each /3 to /10 and *3 to *10 this is the interval. You will also need to change the +2 to the first row of data and the +4 to +11 or +[the interval]-1
I like Scott's answer better, but since I had worked it out while he was typing, I'll add my solution as well.
I'm using the INDIRECT function to build the range reference and calculating the range for the AVERAGE by using MOD on the ROW function.
Basically you're looking to average over the first ten rows, so you need the range A1:A10, then A11:20, and so on. In order to calculate the beginning row, take your current ROW() and subtract the MOD 10 of its previous row: ROW()-MOD(ROW()-1,10). The last row of the group just adds 9 rows: ROW()-MOD(ROW()-1,10)+9.
Everything in Column B uses the formula:
=AVERAGE(INDIRECT("A"&ROW()-MOD(ROW()-1,10)&":A"&ROW()-MOD(ROW()-1,10)+9))
I need to create a dynamic sum of data chunks out of a large data set contained in a csv file (>100k rows). The data is planned to be displayed in PowerBI but I have literately no idea of the DAX coding language or VBA. So I hope I can preformat the data in excel.
The way to distinguish the data sub-sets I want to sum up is a counting row. The rows starts with every new subset from 1 but the final number >= 1 is totally ‘random’.
The first row is the countingRow the second row is the dataRow.
> 1 45
2 20
3 20
4 10 -> SUM 95
> 1 30
2 5 -> SUM 35
> 1 X -> new SUM
I think it is possible to work with the SUM, IF and OFFSET function.
My plan was to check whether a cell contains a 1 or not. Check the range between two true values minus one cell, then calculate the offset sum in the other column.
But when I thought I found the solution I realized that I have no way to bring my pointer to a new data subset.
Which function do I need to move my calculation threw the column?
Is it even possible to do an calculation of this scale in excel?
PS: I'm although thankful for a DAX or VBA tutorial which could bring me to a solution.
In the following sample data image, use the following formula in D2.
=IF(OR(A3={1,""}), SUM(INDEX(B:B, AGGREGATE(14, 6, ROW($1:2)/(A$1:A2=1), 1)):INDEX(B:B, ROW())), TEXT(,))
Fill down.
A slightly shorter formula without array type formula:
=IF(OR(A3={1,""}),SUM($B$2:B2)-SUM($C$1:C1),"")
I would like to find the row at which running summed value has reached a specified amount and several criteria have been met (similar to sumifs).
I can't just add a cumulative row, as suggested here:
Count rows until the sum value of the rows is greater than a value
....because I have other criteria to meet in the data, and therefore can't have a running total.
In the following dummy example, I'd like to find the date at which the "Design" project has spent or exceeded $30,000
A late answer, but one that doesn't use a Helper Column.
By using Matrix Multiplication (MMULT) on a TRANSPOSEd array of whether the Row is larger than itself and the list itself, we can produce an array of the Running Total.
MMULT(--(TRANSPOSE(ROW(D2:D21))<=ROW(D2:D21)), D2:D21)
If we shrink this to just the first 3 rows, to demonstrate, then you are making this calculation:
[[--(2<=2)][--(3<=2)][--(4<=2] [[10,000]
[--(2<=3)][--(3<=3)][--(4<=3] ∙ [ 8,000]
[--(2<=4)][--(3<=4)][--(4<=4]] [ 6,000]]
Which gives us this:
[[1][0][0] [[10,000] [[10,000]
[1][1][0] ∙ [ 8,000] = [18,000]
[1][1][1]] [ 6,000]] [24,000]]
We can then compare that against the target value as a condition and divide by the result to eliminate values with #DIV0! errors, and use AGGREGATE to get the smallest non-error value
=AGGREGATE(15, 6, Row(D2:D21) / (MMULT(--(TRANSPOSE(ROW(D2:D21))<=ROW(D2:D21)), D2:D21)<30000), 1)
This will give us the first row where the Running Total is >= $30,000
make a cumulative row, only adding up if column B equals 'Design'
If you want to be able to do a vlookup, you should make an extra column that checks if amount exceeded 30k, and then output anything that will be your key for the vlookup.
Ok, for anyone who is interested, here is what I ended up doing. I created a separate table that had all of my possible weeks (10/17, 10/24, 10/31, etc.) in one column, and corresponding sequential numbers in the next column. I ended up with 54 in my actual project.
Then, I ended up having to insert one column into my dataset for the purposes of looking up that "Week No", for each "Week" in all rows. Then on my other sheet where I was solving, I had a cell be my decision variable for the week #. I had another be my target $. I created a formula that took my target amount minus the SUMIFS for all of my criteria (Project, Name, etc.) with the last criteria being that the week number had to be "<=" & (decision cell). I then used Solver to minimize the output by changing the target week with constraints that the target week had to be integer, >=1, <=54, and that the output had to be >=0. That got me to the week prior to where the funding went negative. I then had a cell lookup that week number +1 on my weeks table to find the week at which my target amount would be met.
Sorry, had to explain it that way, vs. the actual formula, as my actual formula has a lot of SUMIFS criteria and cell references that wouldn't make any sense here.
I'm trying to get an Average If function to work, the basis is this.
Sheet 1
TIME Duration (sec)
4/24/2013 5:04 57
4/24/2013 5:09 122
4/25/2013 12:22 341
Sheet 2
Date Average Duration
4/24/2013
4/25/2013
My question I have right now is what should the function for average duration be?
I have something like this:
=AVERAGEIF('Sheet1'!C:C,SEARCH("4/24/2013", 'Sheet1'!C:C))
Column C in sheet 1 is the date, Column D is the duration
This will give you exactly what you are looking for and it will disregard the times so that you can search by an entire day regardless of time. Please remember to press Ctrl+Shift+Enter when putting this equation in as it is an array equation.
=SUM(IF(TEXT(DateSearchRange,"m/dd/yy")=TEXT(DateSearchingCell,"m/dd/yy"),DurationRange,0))/SUM(IF(TEXT(DateSearchRange,"m/dd/yy")=TEXT(DateSearchingCell,"m/dd/yy"),1,0))
If you are prepared to insert a helper column, between the present C and D, with =LEFT(C2,5) copied down (assuming 57 is in Row2 and Date is in ColumnA) the formula you tried should work as adapted:
=AVERAGEIF(Sheet1!D:D,A2,Sheet1!E:E)
=SEARCH is not suitable for the condition because it returns the position of one string within another and the second C:C pair would be trying to average TIME, rather than Duration.