Greg_Deckler
Community Champion
6 years agoTRIMMEAN
When you think you pick an easy one...
In my recent quest to create or catalog as many DAX equivalents for Excel functions, I figured this one would be a cinch. Well, not so much. Between poor ...
CL2316
3 years agoFrequent Visitor
Hi there, thanks so much for posting this!
Would you be able to add some commentary on what each variable is doing/why and how? I'm a PowerBI newbie and would really like to understand each part of that measure and how it calculates the trimmed mean.
Thanks so much
- Greg_Deckler3 years ago
Community Champion
CL2316 Sure, see below. It may help to use the PBIX and to return each table variable as a table to see what is in the table at each stage of the calculation.
TRIMMEAN = // First, take the table and add a Rank column, 1 to however many values are in the table VAR __Table = ADDCOLUMNS( 'Table', "Rank",RANKX('Table',[Value]) ) // This is the percentage to trim off (20%) VAR __Percent = .2 // Count the number of rows in the table VAR __Count = COUNTROWS(__Table) // Figure out how many rows to trim off The fractional number of data points to exclude // from the calculation. For example, if percent = 0.2, 4 points are trimmed from a data // set of 20 points (20 x 0.2): 2 from the top and 2 from the bottom of the set. VAR __Trim = MROUND(__Count * __Percent,2) / 2 // Get the highest rank VAR __MaxRank = MAXX(__Table,[Rank]) // Get the lowest rank VAR __MinRank = MINX(__Table,[Rank]) // OK if I recall, it was necessary to account for having more than one row with the same // rank so some of this gets a little complicated. But, basically, take the virtual // __Table variable and and group by Rank column, adding a Count column for how many // rows have that rank and what the value of that rank is. Add cumulative counter columns // that simply count how many rows have a higher or lower rank than the current row. In // addition, add our while loop counters that take the __Trim variable and subtract our // cumulative counters. VAR __RanksTable = ADDCOLUMNS( ADDCOLUMNS( GROUPBY( __Table, [Rank], "Count",COUNTX(CURRENTGROUP(),[Value]), "Value",MAXX(CURRENTGROUP(),[Value]) ), "CumulativeBottomCount",COUNTROWS(FILTER(__Table,[Rank] >= EARLIER([Rank]))), "CumulativeTopCount",COUNTROWS(FILTER(__Table,[Rank] <= EARLIER([Rank]))) ), "BottomWhile",__Trim - [CumulativeBottomCount], "TopWhile",__Trim - [CumulativeTopCount] ) // The minimum bottom row (rank) that we want is the highest rank where the bottom while // loop counter is <= 0. So if __Trim is 2 then the bottom while counter goes to 0 at // three up from the lowest rank. VAR __MinBottom = MAXX(FILTER(__RanksTable,[BottomWhile]<=0),[BottomWhile]) VAR __MinTop = MAXX(FILTER(__RanksTable,[TopWhile]<=0),[TopWhile]) // This table is for the items that we want to exclude (bottom) VAR __FinalBottomRankTable = ADDCOLUMNS( FILTER(__RanksTable,[BottomWhile]>=__MinBottom), "Product",IF([BottomWhile]>=0,[Count]*[Value],([Count] + [BottomWhile]) * [Value]) ) // This table is for the items that we want to exclude (top) VAR __FinalTopRankTable = ADDCOLUMNS( FILTER(__RanksTable,[TopWhile]>=__MinTop), "Product",IF([TopWhile]>=0,[Count]*[Value],([Count] + [TopWhile]) * [Value]) ) // Add up the values to exclude VAR __Bottom = SUMX(__FinalBottomRankTable,[Product]) VAR __Top = SUMX(__FinalTopRankTable,[Product]) RETURN // Determine the average by summing the values in __Table, subtract the bottom and top // and then divide by the number of rows minus 2 * the number of rows to trim from top // and bottom. DIVIDE( SUMX(__Table,[Value]) - __Bottom - __Top, __Count - 2 * __Trim )- CL23163 years agoFrequent Visitor
Wow thank you so much for this, it is beyond helpful!
I'm struggling with calculating the trimmed mean whilst filtering a table:VAR __Order =ADDCOLUMNS(SUMMARIZE(CALCULATETABLE( '280CT_order', '280CT_order_detail'[product category] = "Donation"),'280CT_order'[supporterid],"giftperhead", CALCULATE( [£ Gross Income],'280CT_order_detail'[product category] = "Donation")) ,"Rank", ( RANKX('280CT_order', [giftperhead])))I'm trying to filter the Order table to people who have only given a donation and make sure it's 1 row per supporter if they have given multiple donations. Please can you help?