Averaging nonzero values from INDEX and MATCH - excel

I have a table of data in excel which has Time, Name, and Result columns.
My goal is to use formulas to generate a different, new table which shows the results for each Time (column) and Name (row) combination. This will later be used to generate a heatmap (the results are real numbers).
I am doing this by using a formula on each cell of the new table. An example from cell K5 in the new table is below:
=INDEX($AE$2:$AE$999, MATCH(1, INDEX(($A5=$X$2:$X$999)*(K$4=$V$2:$V$999),0,1),0))
Where $AE$2:$AE$999 is the Result column, $A5 is a name row in the new table, $X$2:$X$999 is the Name column, K$4 is a time column in the new table, and $V$2:$V$999 is the Time column.
The problem is that my table of data has multiple entries that have identical Name and Time combinations, but differing Result values. For these combinations, I would like for the formula to return the average of all nonzero results.
I think the current formula only returns the first match it runs into. I would like for this process to be autmated as possible as the original table of data will be changed frequently.
Screenshot showing the two tables.
The new table. The formula shown in G6 returns 0. I would like for it to return the average of 3.1 and 2.6.

One note: The text of your question is different from the images. I'm going to use the columns mentioned in the text of your message rather than the columns in the images.
It looks like what you're doing is calculating an average but only under certain conditions. Since you're working with multiple conditions, you would start by looking at the formula AVERAGEIFS().
In your case, for Cell G5, You want the average if any row in column X is India (A5) and that same row in column V is 6 (G4) and that same row in column AE is not zero.
So, at its base, the formula in G5 would look like this:
= AVERAGEIFS( $AE$2:$AE$999
, $X$2:$X999, "=India"
, $V$2:$V$999, "=6"
, $AE$2:$AE$999, "<>0" )
However, you want it to be both dynamic and flexible, to do that and keep Excel from messing with things as I move cells around, I make extensive use of the ROW() AND COLUMN() functions.
I think the final might look something like this
= AVERAGEIFS( $AE$2:$AE$999
, $X$2:$X$999, "=" & INDEX( $A:$A, ROW() )
, $V$2:$V$999, "=" & INDEX( $4:$4, 1, COLUMN() )
, $AE$2:$AE$999, "<>0" )
This can be pasted as is in any of the cells from B5 the the right and down, and should give you want you want in each cell. The formula will give you an error if the combination in the axes doesn't exist in the results table. So, you should wrap the whole thing in an error function and display what you want when that happens.
For reference
INDEX( $A:$A, ROW() ) Gives you the label in column A for the row in which the formula resides. So, for any cell in Row 5, this is "India".
INDEX( $4:$4, 1, COLUMN() ) gives you the label in row 4 for the column in which the formula resides. So, for any cell in column G, this will be "6".

If you hace Excel Version 365, the Dynamic Array functions make this simple
Times formula
=TRANSPOSE(SORT(UNIQUE(FILTER(U:U,(ROW(U:U)>1)*(U:U<>"")))))
Names Formula
=SORT(UNIQUE(FILTER(W:W,(ROW(W:W)>1)*(W:W<>""))))
Table formula
=IFERROR(AVERAGEIFS(AD:AD,AD:AD,">0",U:U,C4#,W:W,B5#),"")
If you don't have 365, then the table formula can be
=IFERROR(AVERAGEIFS($AD:$AD,$AD:$AD,">0",$U:$U,C$29,$W:$W,$B30),"")
and copied to the extents of the table. Create the header row/column by any means you choose

Related

SumIF Using Table/Named Range Instead of Single Cell Criteria

I have 2 sheets in a workbook (Sheet1, Sheet2).
Sheet 2 contains a table (Named Table1) with 5 columns:
Takeaways
Household
Clothing
Fuel
Groceries
On sheet one, I have 2 columns:
Expense Name
Expense Total
Now, what I am trying to do is:
Set the range for the Expense Name (Range 1)
Set the range for the Expense Total (Range 2)
Compare Range 1 with the respective column in the table and only add up the values for matches
For example, in Range 1 (B6:B16):
BP
Caltex
McDonalds
KFC
In Range 2 (C6:C16):
300
400
200
150
Now, all I want to do is add up the values for the Takeaways (McDonalds, KFC) and exclude anything that DOES NOT match the criteria.
So my sum total will be all occurrences of Takeaways - provided they are listed in my table - 350 in this case.
But I cannot seem to get the formula to work.
I used these sources:
https://exceljet.net/excel-functions/excel-sumifs-function
Selecting a Specific Column of a Named Range for the SUMIF Function
and ended up with this formula:
=SUMIF($B$6:$B$16;Table1[Takeaways];C6:C16)
This source:
https://excelchamps.com/blog/sumif-sumifs-or-logic/
and ended up with this formula:
=SUM(SUMIFS(C6:C16;B6:B16;Table1[Takeaways]))
Both formulae return 0.
BUT, with BOTH of them, if I change Table1[Takeaways] to "McDonalds", then it correctly identifies every occurrence of the word "McDonalds" in Range 1.
EDIT:
I have updated the formulae above to match the images below.
This is the table that contains the references:
This table contains the data:
Formula:
Cell C4 (Next to Takeaways): =SUMIF($B$6:B$16;Table1[Takeaways];C6:C16)
Cell C5 (Next to Fuel): =SUM(SUMIFS(C6:C16;B6:B16;Table1[Fuel]))
It appears that ONLY BP is being detected in the formula.
This is a an output table when I use the formulae with a single cell reference and not a table or used range:
Formula:
Cell F4 (Next to BP): =SUMIF($B$6:B$16;"BP";C6:C16)
Cell F5 (Next to Caltex): =SUM(SUMIFS(C6:C16;B6:B16;"Caltex"))
Cell F6 (Next to McDonalds): =SUMIF($B$6:B$16;"McDonalds";C6:C16)
Cell F7 (Next to KFC): =SUM(SUMIFS(C6:C16;B6:B16;"KFC"))
If I understand correctly what you're trying to achieve, I think your setup is not right conceptually.
It looks like you're trying to track expenses, and each expense (or payee) is allocated to a category ("Takeaways", "Household" etc.). From a relational-model point of view, your second table (which defines the category for each expense/payee) should only have two columns (or variables): Expense Name and Expense Category.
The table you set up ('Sheet 2') uses the categories (i.e., possible values) as different columns (i.e., variables). But there's only variable, namely the "Expense Category", and the categories themselves are the possible values.
If you set it up like that, the problem changes: you can add a dependent column to your first table that shows the category for each payee (or "Expense Name"), using a VLOOKUP() from the second table.
You can then sum the expenses for all payees matching that category.
Note: I've created the illustration using LibreOffice Calc, so there might be some small differences, but the logic is the same.
Without seeing the data in L and K I can't give you a full answer - but likely it's to do with the way you're pulling your Array
Try something similar to this
=SUMPRODUCT(SUMIFS($L$11:$L$43,$K$11:$K$43,CHOOSE({1,2},Takeaways,"anything else you wanted to sum")))
Remember SUMIFS is for multiple criteria, so if you're only calculating one, you'll need =SUMPRODUCT(SUMIF(
The way the above works is with vertical vectors only, but changing your named ranges so the table of 2 columns is 2 named ranges instead should be okay - unless it's part of your requirements
Table 2 would become expense_Name and expense_Total etc
I was about to close this as a duplicate of my own question here but there is a bit of a difference in using a named range I think. However the logic behind this follows more or less the same approach.
Working further on my partial solution below I derived the following formula:
=SUMPRODUCT(COUNTIF(Table1[Takeaways];Range1)*Range2)
The COUNTIF() part counts the number of occurrences of the cell value in your table. Therefore make sure there are no duplicates in your table. If the value is present in the table the result of COUNTIF() will be 0. This way we create a matrix of 1's and 0's. By multiplying and the use of SUMPRODUCT() we force excel to perform matrix calculations and return the correct result.
Partial solution
I used the following formula:
=SUMPRODUCT(ISNUMBER(MATCH(Range1;Table1[Takeaways]))*Range2)
The formula does the following:
The MATCH()checks if the value in Range1 is present in your table and returns the position of the matching value in your table.
The ISNUMBER() checks if a match is found by checking if the MATCH() fucntion returned a number
Multiplying this with Range2 forces matrix calculation, using the SUMPRODUCT() function
EDIT:
This worked for a really limited sample. As soon as I added the fourth row to my data the formula stopped working as intended. See screenshot:
It took the first two values into the sum correctly, the fourth is not taken into account.

Excel Index to look up multiple values

I have a small data set of 2 columns and several rows (columns A and B)
I want to return each instance of codeblk 3 in a formula that is elsewhere in my sheet, (so a vlookup is out as it only shows the first instance) if it does not appear then a message to say its not there should come up.
I have the formula partially working but i cant see the reason why its not displaying the values.
My formula is as below:
This is an array
{=IF(ISERROR(INDEX($A$55:$B$70,SMALL(IF($B$55:$B$70=3,ROW($B$55:$B$70)),ROW(1:1))-1,1)),"No value's produced",INDEX($A$2:$C$7,SMALL(IF($B$55:$B$70=3,ROW($B$55:$B$70)),ROW(1:1))-1,1))}
The result that shows up is only "No values produced" but it should reflect statement B, C and D in 3 separate cells (when changing ROW(1:1), ROW(2:2) etc)
{=SMALL(IF($B$56:$B$69=4,ROW($B$56:$B$69)),ROW(1:1))} - This produces the result 68 which is the correct row.
Any ideas?
Thanks,
This is an array formula - Validate the formula with Ctrl+Shift+Enter while still in the formula bar
=IFERROR(INDEX($A$55:$B$70,SMALL(IF($B$55:$B$70=3,ROW($B$55:$B$70)-54),ROW(1:1)),1),"No value's produced")
The issue you are facing is that your index starts it's first row on $B$55, you need to offset the row numbers in the array to reflect this. For example, the INDEX contains 16 rows but if you had a match on the first row you are asking for the 55th row from that INDEX(), it just can't fulfil that.
EDIT
The offset was out of sync as your original formula included another -1 outside of the IF(), I also left an additional bracket in play (the formula above has now been edited)
The ROW() function will essentially translate $B$55:$B$70 into ROW(55:70) which will produce the array {55;56;57;58;59;60;61;62;63;64;65;66;67;68;69;70} so the offset is needed to translate those row numbers in to the position they represent in the indexed data of INDEX().
The other IF() statement then produces and array of {FALSE;2;3;4;FALSE etc.
You can see these results by highlighting parts of the formula in the formula bar and hitting F9 to calculate.

Count of distinct values with several criteria

I want to be able to count distinct values with several criteria. As presented here below on the screenshot, I would like to know, how many POs do I have per month depending on the PO type (service or material).
Initial data:
Desired result:
All the data is in text format.The difficulty is that the initial data table will be updated every month (I will be adding lines), so the formula has to consider possible updates. Pivot table will not work for me.
The solution I'm offering involves one helper column, but you'll be able to use it quite flexibly. I make the following assumptions:
You can add columns to your original table
The table starts in cell A1
Steps:
Convert your data range into a dynamic excel table (select the range, press Ctrl+t, tick "Table Has Headers" - you get a blue table as a result). This way if you add more data, formulas will drag themselves down.
type "HELPER" into cell D1, and "Number of POs" into cell E1 - this will create 2 new columns (they should turn blue like the rest of table)
paste this formula into cell D2:
=[#[Month/Year]]&[#[Mate/Serv]]
Paste this formula into cell E2:
=SUMPRODUCT(
( [HELPER]=[#[Month/Year]] & [#[Mate/Serv]] ) /
COUNTIFS([Month/Year],[Month/Year],
[Mate/Serv],[Mate/Serv],
[PO No.],[PO No.]
)
)
Add a pivot table, put Number of POs into values area, it will sum values by default.
As in this picture:
Right-click inside the values area, select Summarise Values By.. => MAX (as in second picture below).
You will see that values in pivot have changed.
this way you won't have to manually maintain the header in your summary table as pivot table will pick up any new entries/months.
IF YOU WANT TO STICK TO YOUR ORIGINAL DESIGN:
The same formula can be used (with minor change to add table name to column names), but it still needs the table and helper - follow steps 1-3. Make sure you're set up is as in picture below:
=SUMPRODUCT(
( Table2[HELPER]=H$1&$G2 ) /
COUNTIFS(Table2[Month/Year],Table2[Month/Year],
Table2[Mate/Serv],Table2[Mate/Serv],
Table2[PO No.],Table2[PO No.]
)
)
If anyone would like to change my formula to avoid creating a helper, please do.
I created a dummy table so your results won't be like mine.
How to test:
Copy your data on a new sheet
Go to Data menu ribbon => Remove Duplicates
Pivot the remainder
Put met/serve into rows, month/year into columns, Helper into Values.
That will give you a count you should expect.
Assuming your data is in Columns J:L, you can add a helper column in M, entering this formula in M2 and dragging down:
=COUNTIF(J:J,J2)
Then, assuming your desired result table is in columns N:P enter this formula in O2:
=COUNTIFS($K:$K,O$1,$L:$L,$N2,$M:$M,">0")-MAX((COUNTIFS($K:$K,O$1,$L:$L,$N2,$M:$M,">1")-1),0)
You can then drag this cell over to column P and drag them both down.
This also assumes you Desired result table headers are formatted as text as well.

Is there a 2 Value Look up function in MS Excel that can perform the following?

I am going crazy over this. It seems so simple yet I can't figure this out. I have two worksheets. First worksheet is my data. Second is like an answer key. Upon checking checking, A1:B1 in Sheet 1 is a match with the conditions in Row 52 in SHEET 2, therefore, the value in Column C is "MGC". What is the formula that will perform this function? It's really hard to explain without the data so I pasted a link of the sample spreadsheet. Thank you so much in advance.
sample spreadsheet here. https://docs.google.com/spreadsheets/d/1_AjuNfCdGfEM-XkqPa6W4hSIxQg4NM2Vg4c2C1pQ_vQ/edit?usp=sharing
screenshot here. (wont let me post i have no reputation)
In Sheet2, insert a column in front of Column A and put the formula in A2 =C2&D2.
Then in Sheet1, Cell C2 the formula =vlookup(A2&B2,Sheet2!A:B,2,0).
the first make a concatenated key to lookup, then the second looks up that key.
How about a index(match())? If I've understood correctly you need to match across both the A and B column in sheet one, checking for the relevant values in B and C on sheet 2 to retrun worksheet 2 column a to worksheet 1 column c.
third version try:
=INDEX(Sheet2!$C$1:$C$360,MATCH(Sheet1!A1&Sheet1!B1,Sheet2!$B$1:$B$360&Sheet2!$C$1:$C$360,0))
Basically what this does is use concatenation, the & operator, to specify you are looking for "Criteria A" & "Criteria B" in sheet 1, which makes the string "Criteria A Criteria B", which is supplied in the first part of the match function.
In the second it then says match this against all of my variables in sheet 2 in the same way with concantenation.
The final part of match function (0) specifies you want an 'exact' match
It then supplied this as a reference to the index function, which then finds the row intersecting with the value you want, and returns that.
As noted here https://support.microsoft.com/en-us/kb/59482 this is an array formula, so it behaves differently, and must be input differently. https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7
There are (at least) 2 ways you could do this without VBA.
USING A SORTED LIST
The first relies on the assumption that your data can be re-sorted, so that everything "Unreported" is in the top, and everything "reported" is together below that (or vice versa). Assuming that this is the case (and it appears to already be sorted like this),we will use the function OFFSET to create a new range which shows only the values that align with either being "Unreported" or "Reported".
Offset takes a given reference to a point on a sheet, and then moves down/up & left/right to see what reference you want to return. Then, it returns a range of cells of a given height, and a given width. Here, we will want to start on Sheet2 at the top left, moving down until we find the term "Unreported" or "Reported". Once that term is found, we will want to move one column to the right (to pull column B from sheet 2), and then have a 'height' of as many rows as there are "unreported" or "reported" cells. This will look as follows in A1 on sheet 1, copied down:
=OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),1)
This says: First, start at cell A1 on sheet2. Then find the term in A1 (either "unreported" or "reported", on sheet2!A:A (we subtract 1 because OFFSET starts at A1 - so if your data starts at A1 we need to actually stay at "0". If you have headers on sheet2, you will not need this -1). Then, move 1 column to the right. Go down the rows for as many times as Sheet2 column A has the term found in Sheet1 A1. Stay 1 column wide. Together, this will leave you with a single range on sheet2, showing column B for the entire length that column A matches your term in sheet1 A1.
Now we need to take that OFFSET, and use it to find out when the term in Sheet1 B1 is matched in Sheet2 column B. This will work as follows:
=MATCH(B1,[FORMULA ABOVE],0)
This shows the number of rows down, starting at the special OFFSET array created above, that the term from B1 is matched in column B from sheet2. To use this information to pull the result from column C on sheet 2, we can use the INDEX function, like so:
=INDEX([FORMULA ABOVE],MATCH(B1,[FORMULA ABOVE],0))
Because this would be fairly convoluted to have in a single cell, we can simplify this by using VLOOKUP, which will only require the OFFSET function to be entered a single time. This will work as follows:
=VLOOKUP(B1,[FORMULA ABOVE],2,0)
This takes the OFFSET formula above, finds the matching term in B1, and moves to the 2nd column to get the value from column C in sheet2. Because we are going to use VLOOKUP, the offset formula above will need to be adjusted to provide 2 columns of data instead of 1. Together, this will look as follows:
FINAL FORMULA FOR SHEET1, C1 & COPIED DOWN
=VLOOKUP(B1,OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),2),2,0)
OPTION USING ARRAY FORMULAS
The above method will only work if your data is sorted so that the REPORTED and UNREPORTED rows are grouped together. If they cannot be sorted, you can use an ARRAY FORMULA, which essentially takes a formula which would normal apply to a single cell, and runs it over an entire range of cells. It returns an array of results, which must be reduced down to a single value. A basic array formula looks like this [assume for this example that A1 = 1, A2 = 2...A5 = 5]:
=IF(A1:A5>3,A1:A5,"")
Confirm this (and all array functions) by pressing CTRL + SHIFT + ENTER, instead of just ENTER. This looks at each cell from A1:A5, and if the value is bigger than 3, it gives the number from that cell - otherwise, it returns "". In this case, the result would be the array {"";"";"";4;5}. To get the single total of 9, wrap that in a SUM function:
=SUM(IF(A1:A5>3,A1:A5,""))
In your case, we will want to use an array formula to see what row in Sheet2 matches A1 from Sheet1, and B1 from Sheet1. This will look like this:
=IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW($B$1:$B$100),""),"")
This checks which rows in column A from sheet 2 match A1. For those that do, it then checks which rows in column B from sheet 2 match B1. For those, it pulls the row number from that match. Everything else returns "". Assuming no duplicates, there should only 1 row number which gets returned. To pull that number from the array of results, wrap the whole thing in a MATCH function. Now that you have the row number, you can use an INDEX function to pull the result in Column C with that row, like this:
FINAL ARRAY FORMULA METHOD
=INDEX($C$1:$C$100,MAX(IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW(Sheet2!$B$1:$B$100),""),"")))
Remember to confirm with CTRL + SHIFT + ENTER instead of just ENTER, when you type this formula. Note that I didn't refer to all of Sheet2!A:A, because array formulas run very slowly over large ranges.
The following formula should work without making any changes to the datasheets.
=INDEX(Sheet2!$A$1:$A$360,MATCH(Sheet1!A1,IF(Sheet2!$C$1:$C$360=Sheet1!B1,Sheet2!$B$1:$B$360),0))
Remember to save this formula as an array with CTRL+SHIFT+ENTER
Documentation on how to use INDEX and MATCH against multiple criteria can be found on Microsoft Support.
It's not clear what you want to do with the multiples that do not have corresponding matches. txed is listed as Unreported twice in Sheet1; kntyctap is listed as Unreported three times. There are only one corresponding match on Sheet2 for each of these.
Non-array Standard Formulas for multiple criteria matches
For Excel 2010 and above use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999,AGGREGATE(15,6,ROW(1:999)/((Sheet2!$B$1:$B$999=A2)*(Sheet2!$C$1:$C$999=B1)), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
For version of Excel prior to 2010 use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999, SMALL(INDEX(ROW($1:$999)+((Sheet2!$B$1:$B$999<>A1)+(Sheet2!$C$1:$C$999<>B1))*1E+99, , ), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
I've handled error with the IFERROR function in that latter formula. Excel 2003 and previous may have to use an IF(ISERROR(..., ...)) combination.

Microsoft Excel - How do you auto-populate a formula in a column?

Longevity, EmployeeID, StartDate, EndDate
I paste a bunch of data into the worksheet (cells B1-Dn), and I need the formula for A1-An (longevity) to automatically calculate the result for each employee that is entered.
I am using Microsoft Excel 2010.
Currently, the formula that I am using is:
=IF ( C1 , IF ( D1 , D1-C1 , TODAY()-C1 ) , "")
This works great, except that I have to manually add/remove cells with this formula in the A column to match the number of rows that are entered at any given time. This is very time-consuming, and difficult for Management to get their heads around when using this report. :)
Is there a way to say "Every row with data in it, gets THIS formula in column A"?
I've been researching this online, and found various answers. The most prominent answer was to use a drop-down-list with a default value, but I don't think that will work for a default formula.
Using Data tables should help you out with ensuring that your formulas cover the entire range.
Step one:
Paste your data (no formulas)
Step two: Go to insert -> table you should get a dialog that looks something like
Now put your formula in the adjacent column. You will notice that the table formatting will automatically expand into where your formula is, and that the formula will auto copy to the bottom of your data set.
Step three:
Copy a larger dataset into the table.... you will notice that the formula copies down with your new extended data set.
Note that the table won't be resized if you paste a smaller dataset.
If I understand correctly what you need, then maybe you should try this.
In the every cell of column A (where you need the formula to be present if other columns contain data) add this formula :
=IF( AND( NOT(ISBLANK(B:B)),NOT(ISBLANK(C:C)),NOT(ISBLANK(D:D)) ),
IF ( $C1 , IF ( $D1 , $D1-$C1 , TODAY()-$C1 ) , ""),"" )
To be more exact, you should add this formula in the A1 cell, and then auto fill all the A column.
Alternatively you could try setting the formula below in A1 cell and then auto fill the rest of the A column.
=IF( AND( NOT(ISBLANK(B1)),NOT(ISBLANK(C1)),NOT(ISBLANK(D1)) ),
IF ( $C1 , IF ( $D1 , $D1-$C1 , TODAY()-$C1 ) , ""),"" )

Resources