Power Query (M language) 50 day moving Average - powerquery

I have a list of products and would like to get a 50 day simple moving average of its volume using Power Query (M).
The table is sorted by product name and date. I add a custom column and applied the code below.
if [date] >= #date(2018,1,29)
then List.Average(List.Range(Source[Volume],[Volume]-1,-50))
else ""
Since it is already sorted by date and name, an if statement was applied with a date as criteria/filter. However, an error occurs that says
'Volume' column not found in the table.
I expect to have an added column in the power query with volume 50 day moving average per product. the calculation to be done if date is greater than or equal Jan 29, 2018.

We don't know what your columns are, but assuming you have [product], [date] and [volume] in Source, this would average the last 50 days of [volume] for the identical [product] based on each [date], and place in a new column
AvgAmountAdded = Table.AddColumn(Source, "AverageAmount", (i) => List.Average(Table.SelectRows(Source, each ([product] = i[product] and [date]<=i[date] and [date]>=Date.AddDays(i[date],-50)))[volume]), type number)

Finally! found a solution.
First, apply Index by product see this post for further details
Then index again without criteria (index all rows)
Then, apply below code
= Table.AddColumn(#"Previous Step", "Volume SMA(50)", each if [Index_byProduct] >= 50 then List.Average(List.Range(#"Previous Step"[Volume], ([Index_All]-50),50)) else 0),
For large dataset, Table.Buffer function is recommended after index-expand step to improve PQ calculation speed

Related

SSAS Tabular - how to aggregate differently at month grain?

In my cube, I have several measures at the day grain that I'd like to sum at the day grain but average (or take latest) at the month grain or year grain.
Example:
We have a Fact table with Date and number of active subscribers in that day (aka PMC). This is snapshotted per day.
dt
SubscriberCnt
1/1/22
50
1/2/22
55
This works great at the day level. At the month level, we don't want to sum these two values (count = 105) because it doesn't make sense and not accurate.
when someone is looking at month grain, it should look like this - take the latest for the month. (we may change this to do an average instead, management is still deciding)
option 1 - Take latest
Month-Dt
Subscribers
Jan-2022
55
Feb-2022
-
option 2 - Take aveage
Month-Dt
Subscribers
Jan-2022
52
Feb-2022
-
I've not been able to find the right search terms for this but this seems like a common problem.
I added some sample data at the end of a month for testing:
dt
SubscriberCnt
12/30/21
46
12/31/21
48
This formula uses LASTNONBLANKVALUE, which sorts by the first column and provides the latest value that is not blank:
Monthly Subscriber Count = LASTNONBLANKVALUE( 'Table'[dt], SUM('Table'[SubscriberCnt]) )
If you do an AVERAGE, a simple AVERAGE formula will work. If you want an average just for the current month, then try this:
Current Subscriber Count =
VAR _EOM = CLOSINGBALANCEMONTH( SUM('Table'[SubscriberCnt]), DateDim[Date] )
RETURN IF(_EOM <> 0, _EOM, AVERAGE('Table'[SubscriberCnt]) )
But the total row will be misleading, so I would add this so the total row is the latest number:
Current Subscriber Count =
VAR _EOM = CLOSINGBALANCEMONTH( SUM('Table'[SubscriberCnt]), DateDim[Date] ) //Get the number on the last day of the month
VAR _TOT = NOT HASONEVALUE(DateDim[MonthNo]) // Check if this is a total row (more than one month value)
RETURN IF(_TOT, [Monthly Subscriber Count], // For total rows, use the latest nonblank value
IF(_EOM <> 0, _EOM, AVERAGE('Table'[SubscriberCnt]) ) // For month rows, use final day if available, else use the average
)

Wrong sorting while using Query function

I've been trying to do a report about the quantity of breakdonws of products in our company. The problem is that the QUERY function is operating as normal, but the sorting order is well - a bit strange.
The data I'm trying to sort are as follows (quantities are blacked out since I cannot share those informations):
Raw data
First column - name of the product, second, it's EAN code, third, breakdown rate for last year, last column - average breakdown rate. "b/d" means "brak danych" or no data.
What I want to achieve is to get the end table with values sorted by average breakdown rate.
My query is as follows:
=query(Robocze!A2:D;"select A where A is not null and NOT D contains 'b/d' order by D desc")
Final result
As You can see, we have descending order, but there are strange artifacts - like the 33.33% after 4,00% and before 3,92%.
Why is that!?
try:
=INDEX(LAMBDA(x; SORT(x; INDEX(x;; 4)*1; 0))
(QUERY(Robocze!A2:D; "where A is not null and NOT D contains 'b/d'"; 0));; 4)

DAX formula to subtract columns

I am trying to calculate month over month difference but it makes data negative.
I created a measure, but it makes source data negative.
CALCULATE (
COUNTA ( SOURCE_DATA[COLUMN] ),
FILTER ( SOURCE_DATA, SOURCE_DATA[YYYYMM] = "201906" )
)
- (
CALCULATE (
COUNTA ( SOURCE_DATA[COLUMN] ),
FILTER ( SOURCE_DATA, SOURCE_DATA[YYYYMM] = "201905" )
)
)
The outcome is correct, but it changes data in previous month to negative.
This is due to the filter context and the way you've written the measure.
Look at the visual table. For the field corresponding to Column = 201905 and row = GA you get -16 813. This is because the context of the visual table tells CALCULATE to COUNTA(SOURCE_DATA[Column]) only when MtM = GA and Columns = 201905. However, adding the FILTER you also tell CALCULATE to keep these criteria AND also make sure that SOURCE_DATA[Column] = 201906 in the first calculate and 201905 in the second one.
This results in CALCULATE looking for rows where Column is both 201905 and 201906 at the same time. Or in other words you generate a venn diagram with no overlapping fields. Therefore the first calculate evaluates to 0 and the second to 16 813, so that the measure is actually evaluating 0-16813 = -16 813.
Since you didn't post any description of your data model I can inly guess what it looks like. However, since you're filtering on the SOURCE_DATA table I guess you don't use a Calendar table. This you should do! Have a calendar with a 1:* (1-to-many) relationship with the SOURCE_DATA and do filtering on the calendar. In addition you can have dynamically calculated day/week/month/year offsets so that you can create measures which don't have to be updated when there's a new month.
I think this video can be helpful: sqlbi videolecture
Also, have a look at this article: sqlbi filter in calculate

How to find the maximum value from a column satisfying two or more IF conditions in DAX

I am a newbie to Power BI and DAX.
I have a dataset as attached. I need to find the maximum value for each person for each week. I have written the formula in Excel.
=MAX(IF(A$2:A$32=A2,IF(D$2:D$32=D2,IF(B$2:B$32=1,C$2:C$32))))
How can I convert it to DAX or write the same formula in Power BI? I tried the DAX Code as below, But it did not work(ALLEXCEPT Function expects table).
Weekly Maximum =
CALCULATE ( MAX ( PT[Value] ), ALLEXCEPT ( PT, PT[person], PT[Week],
PT[category] ==1 ) )
Once I calculate this, then I need to calculate the Expected value for each week, that has the maximum value of the previous week * 2.85, as shown in the screenshot. How can I put the previous week's maximum value for this week?
Any corrections/solutions, please?
TIA
The Max Value for Category 1 can be written like this:
= CALCULATE(MAX(PT[Value]),
ALLEXCEPT(PT, PT[Person], PT[Week]),
PT[Category] = 1)
(The Category filter doesn't go inside ALLEXCEPT().)
For your Expected Value column, you can do something similar:
= CALCULATE(2.85 * MAX(PT[Value]),
ALLEXCEPT(PT, PT[Person]),
PT[Category] = 1,
PT[Week] = EARLIER(PT[Week]) - 1)
(The EARLIER function gives you the value for the row you are in. The name refers to the earlier row context.)

Displaying Max, Min, Avg across bar chart Tableau

I have a bar chart with X axis as discrete date value and Y axis as number of records.
eg: x axis (Filtered Date)- 1st Oct, 2nd Oct, 3rd Oct etc
y axis (Number of Records)- 30, 4, 3 etc
Now, I have to create a table to get Max, Min and Avg. Value of the 'Number of Record'.
I have written a Calculated Field as MAX([Number of Records]) to get the maximum of Number of Records in this case 30 but I always get a value of 1.
How do I define the values to get max, min and avg. ?
Thanks,
Number of Records is an automatically calculated field that tableau generates when importing a datasource. You can right click on it and see the definition of the calculation: 1.
As you currently have your field defined, tableau will look for the maximum value of the column. It will always be 1 because that is the only value in that field for every record.
It sounds like you are actually trying to calculate the maxiuum of the sum of the number of records for your aggregation level (in your case date). You should be able to easily accomplish this using Level of Detail (LOD) expressions, or table calculations. Something like the following:
WINDOW_MAX(SUM([Number of Records]))

Resources