Advanced DAX calculation: doing a moving grouped average in PowerPivot

I got an excellent question last week on the ask my answers page that brought me new understanding of DAX. So finally a new interesting (I hope) blog post on DAX.

Let’s say I have a set of sales per week of a specific brand:

Now I want to have the average of sales per week (slicable by brand) and compare it to the average of the last 3 weekly totals. I prepare  the pivottable :

Now for the moving average of the last 3 weeks we are going to do some interesting DAX. First of all we want to use the current “Week No” as a base value, we need to check if our formula has one week in the current row context, otherwise we cannot get a moving average over a specific week. We check the number of values in the Sales[Week No] column using:

if(countrows(values(Sales[Week No])) = 1

Next we want to get the values of sales from this week and the previous two week to get a grouped average from. We can get a grouped average on Sales[Week No] of the Sales using the AVERAGEX function:

AVERAGEX(VALUES(Sales[Week No]), Sales[Sum of Sales])

Notice we use VALUES(Sales[Week No]) in function to group on the distinct values of Sales[Week No]. This function on its own will only return the average of the current Sales[Week No], we need to override the filter context to return the last current and previous two week. To override the current context with a broader set of values we can use the Calculate function.

This Calculate function will return a table of the current week plus the previous two:

CALCULATE(<grouped AVG function> , Sales[Week No] <= VALUES(Sales[Week No]) &&  Sales[Week No] > VALUES(Sales[Week No])-3)

If you combine the two we get the overall DAX function:

=if(countrows(values(Sales[Week No])) = 1,
	CALCULATE(
		 AVERAGEX(VALUES(Sales[Week No]), Sales[Sum of Sales])
		 ,Sales[Week No] <= VALUES(Sales[Week No]) &&  Sales[Week No] > VALUES(Sales[Week No])-3
		)
, blank())

This will give the following Pivottable:

The most interesting thing to notice here is that VALUES(Sales[Week No]) contains two different values in a single function. Let’s take a look at the DAX function again:

=if(countrows(values(Sales[Week No])) = 1,
	CALCULATE(
		 AVERAGEX(VALUES(Sales[Week No]), Sales[Sum of Sales])
		 ,Sales[Week No] <= VALUES(Sales[Week No]) &&  Sales[Week No] > VALUES(Sales[Week No])-3
		)
, blank())

The red function will return the actual row and filter context that we are in. To see what this row and filter context is all about check this link. The calculate function will change the context of the first argument, in this case we use AVERAGEX in the first argument to group on the distinct Sales[Week No] of the changed context. The blue function returns 3 Sales[Week No] to do the Average over.

It can look confusing but again shows the amazing capabilities of the CALCULATE and AVERAGEX functions. It took me some time to come up with CALCULATE in this particular scenario (thanks to my colleague Jeffrey who also made a in depth blog post about this subject. )

7 Replies to “Advanced DAX calculation: doing a moving grouped average in PowerPivot

  1. Are you trying to do an average of weekly totals?
    If so, I would reword this line
    “Now I want to have the average of sales per week (slicable by brand) and compare it to the average of the last 3 weeks. I prepare the pivottable :”
    to
    “Now I want to have the sum total of sales per week (slicable by brand) and compare it to the average of the last 3 weekly totals. I prepare the pivottable :”

  2. Hi, Kasper!

    I tried to do this moving average with power bi and it doesn’t work. Basically, I tried to do many time different commands from Internet for moving average in DAX and it doesn’t work. What could it be?

    My code is for example

    New Column = CALCULATE(AVERAGEX(VALUES(input[Index]); input[consumption]); input[Index] <= VALUES(input[Index]))

    and it says "A single value for column 'consumption' in table 'input' cannot be determined. This can happen when a measure formula refers to a column that contains many values without specifying an aggregation such as min, max, count, or sum to get a single result."

      1. I tried, but now this error. I need result as column

        “A single value for column ‘consumption’ in table ‘input’ cannot be determined. This can happen when a measure formula refers to a column that contains many values without specifying an aggregation such as min, max, count, or sum to get a single result.”

  3. Hey Kasper!

    So, I am using the formula for 4 WA and it works like a charm!
    But how could we derive a 4 WA previous year from it?
    I have tried:
    CALCULATE([4 WA];FILTER(
    all(‘Date’);
    ‘Date'[Year] = MAX(‘Date'[Year])-1
    && ‘Date'[Week Number] = MAX(‘Date'[Week Number])
    )
    )

    But for some reason it returns just the sales of the previous year, not the 4 WA…

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.