This is something I have never attempted before
I want to calculate the weighted standard deviation and the weighted average for the dataset containing records for actual values measured against set values
The calculation is to be done using a DAX query in PowerBI
Set Value 1
Actual Value 1
Set Value 2
Actual Value 2
10
8
101
102
10
11
101
104
10
12
101
97
10
7
101
99
10
13
101
97
10
13
101
100
10
9
101
98
10
10
101
100
10
8
101
102
10
14
101
98
10
8
101
98
10
13
101
96
10
13
101
103
10
14
101
102
10
7
202
205
20
18
202
198
20
18
202
197
20
19
202
203
20
19
202
202
20
19
202
201
20
22
202
202
20
18
202
200
20
17
202
195
20
23
202
198
Edit 1:
Please use the data above.
Also, please note that although, set points are what we intend to use as weights but its the count of a particular set point. for eg: if the setpoint1 10 is repeating 15 times and set point1 20 is repeating 9 times then wieght to be used as 15 & 9 respectively
Weighted Average and Standard deviation can be implemented in DAX according to their mathematical definition.
Assuming we have a table with the columns Weight and Value the formula for the Weighted Average is
WAvg =
VAR Num = SUMX( Samples, Samples[Weight] * Samples[Value] )
VAR Den = SUM( Samples[Weight] )
RETURN DIVIDE( Num, Den )
and the formula for the Weighted Standard Deviation is
WStdDev =
VAR WAvg = [WAvg]
VAR Num = SUMX( Samples, Samples[Weight] * (Samples[Value] - Wavg)^2 )
VAR Den = SUM( Samples[Weight] )
VAR WVar = DIVIDE( Num, Den )
RETURN SQRT(WVar)
Edit:
if I understand your new request, the Weight is the number of rows with the same Set Value, that is to be used for each of the Actual Value. Then, since there are two pairs of columns, I assume that the requirement is to have a set of measures per each couple of columns.
The formula requires to add a count of the number of rows per each group of Set Value, to be used as weight. I imported the sample table as table "V"
Weighted average for Set Value 1 and Actual Value 1
WAvg1 =
VAR Num =
SUMX(
ALL( V ),
CALCULATE( COUNTROWS( V ), ALLEXCEPT( V, V[Set Value 1] ) ) * V[Actual Value 1]
)
VAR Den =
SUMX(
ALL( V ),
CALCULATE( COUNTROWS( V ), ALLEXCEPT( V, V[Set Value 1] ) )
)
RETURN
DIVIDE( Num, Den )
Weighted average for Set Value 2 and Actual Value 2
WAvg2 =
VAR Num =
SUMX(
ALL( V ),
CALCULATE( COUNTROWS( V ), ALLEXCEPT( V, V[Set Value 2] ) ) * V[Actual Value 2]
)
VAR Den =
SUMX(
ALL( V ),
CALCULATE( COUNTROWS( V ), ALLEXCEPT( V, V[Set Value 2] ) )
)
RETURN
DIVIDE( Num, Den )
Weighted standard deviation for Set Value 1 and Actual Value 1
WStdDev1 =
VAR Num =
SUMX(
ALL( V ),
VAR WAvg = [WAvg1]
RETURN
CALCULATE( COUNTROWS( V ), ALLEXCEPT( V, V[Set Value 1] ) ) * ( V[Actual Value 1] - WAvg ) ^ 2
)
VAR Den =
SUMX(
ALL( V ),
CALCULATE( COUNTROWS( V ), ALLEXCEPT( V, V[Set Value 1] ) )
)
VAR WVariance =
DIVIDE( Num, Den )
RETURN
SQRT( WVariance )
Weighted standard deviation for Set Value 2 and Actual Value 2
WStdDev2 =
VAR Num =
SUMX(
ALL( V ),
VAR WAvg = [WAvg2]
RETURN
CALCULATE( COUNTROWS( V ), ALLEXCEPT( V, V[Set Value 2] ) ) * ( V[Actual Value 2] - WAvg ) ^ 2
)
VAR Den =
SUMX(
ALL( V ),
CALCULATE( COUNTROWS( V ), ALLEXCEPT( V, V[Set Value 2] ) )
)
VAR WVariance =
DIVIDE( Num, Den )
RETURN
SQRT( WVariance )
Applying these formulas to the sample table we get these results
Related
I have the following data:
Country Sales
1 20
1 30
1 10
2 25
2 80
3 200
3 4
4 20
5 30
I want to have top 2 country sales summed up and the rest
Country Sales
2 105
3 204
Others 110
I want to display the summed up data in a pie chart.
Rank Sales =
RANKX(ALL(Table[Country]),CALCULATE(sum(Table[Sales])))
What should I do ahead? The if condition is giving an error:
Rank Display =
IF('DAX Measures'[Rank Sales]>2,"Other",'Table'[country])
Please create a new table, and paste this code:
CategorizationByRank =
VAR Summary_01 =
ADDCOLUMNS (
VALUES ( 'Table'[Country] ),
"Total", CALCULATE ( SUM ( 'Table'[Sales] ) )
)
VAR Summary_02 =
ADDCOLUMNS ( Summary_01, "Ranking", RANKX ( Summary_01, [Total] ) )
VAR TablesRankLess_And_Equal_To_2 =
FILTER ( Summary_02, [Ranking] <= 2 )
VAR TablesRankGreater_Than_2 =
ROW (
"Country", "Others",
"Total", SUMX ( FILTER ( Summary_02, [Ranking] > 2 ), [Total] ),
"Ranking", 3
)
VAR UnionAllRecords =
UNION ( TablesRankGreater_Than_2, TablesRankLess_And_Equal_To_2 )
RETURN
UnionAllRecords
And It produces this result:
Then you can put the fields directly into a pie chart, see the picture:
i have simple dataset like below where the delta is a measure (not a column) which is the diff of demand and supply.I wanted to calculated the running sum of measure "delta" as shown below.running sum needs to be at material-location-week level.
dax i tried:
Cum =
var mat = MAX('table'[Material])
var pla = MAX('table'[Plant])
var pw =MAX('table'[PWk])
return
CALCULATE(
table[delta],
FILTER(
ALL(table),
'table'[Material]= mat && 'table'[Plant] <= pla && 'table'[PWk]<=pw
)
))
<>
material location week demand supply delta(demand-supply) running_sum??
123 1000 wk1 100 40 60 60
123 1000 wk2 40 30 10 70
123 2000 wk1 30 20 10 10
123 2000 wk2 40 15 25 35
please help. I am stuck with this and dont know`enter code here` where i am going wrong.
Perhaps:
running_sum =
VAR Mat =
MAX ( 'Table'[material] )
VAR Loc =
MAX ( 'Table'[location] )
VAR Wk =
MAX ( 'Table'[week] )
RETURN
CALCULATE (
[delta],
FILTER (
ALL ( 'Table' ),
'Table'[material] = Mat
&& 'Table'[location] = Loc
&& 0 + SUBSTITUTE ( 'Table'[week], "wk", "" )
<= 0 + SUBSTITUTE ( Wk, "wk", "" )
)
)
My data:
week
sale
20
50
20
20
21
10
21
10
22
5
22
5
Desired result:
week
sale
change
20
50
any
20
20
any
21
10
-50
21
10
-50
22
5
-10
22
5
-10
Where:
Week 20 total = 70,
Week 21 total = 20,
Week 22 total = 10
Diff for week 21 = 20-70 = -50
Diff for week 22 = 10-20 = -10
Note: "any" = can be anything (i.e. 0 or null)
Calculated column
Column 2 =
VAR _1 =
CALCULATE ( MAX ( 'Table'[week] ) ) - 1
VAR _2 =
SUMX ( FILTER ( ALL ( 'Table' ), 'Table'[week] = _1 ), 'Table'[sale] )
VAR _3 =
CALCULATE ( SUM ( 'Table'[sale] ), ALLEXCEPT ( 'Table', 'Table'[week] ) )
VAR _4 =
IF ( ISBLANK ( _2 ) = TRUE (), BLANK (), _3 )
RETURN
_4
Measure
currentWeekTotal:= SUM('Table'[sale])
prevWeekTotal:=
VAR _1 = MAX('Table'[week])-1
VAR _2 = SUMX(FILTER(ALL('Table'),'Table'[week]=_1),'Table'[sale])
RETURN _2
change:= IF([prevWeekTotal]=BLANK(),BLANK(),[currentWeekTotal]-[prevWeekTotal])
Here is a simple code for a calculated column :
change =
VAR _firstweek = MIN ( 'Table'[week] )
VAR _thisweek = 'Table'[week]
VAR _thisweeksales = CALCULATE ( SUM ( 'Table'[sale] ) , ALLEXCEPT ( 'Table' , 'Table'[week] ) )
VAR _lastweeksales = CALCULATE ( SUM ( 'Table'[sale] ) , ALL ( 'Table' ) , 'Table'[week] = _thisweek - 1 )
VAR _diff = IF ( _thisweek <> _firstweek , _thisweeksales - _lastweeksales )
RETURN _diff
This also handles skipped weeks that are not the first week.
My data is as follows:
Factory ID
Week
CAPACITY
Request
1
21
1000
500
1
22
1000
1200
1
23
1500
1600
1
24
1500
1100
2
21
1000
500
2
22
2000
1900
2
23
2000
1000
2
24
2000
2500
3
21
1000
200
3
22
1000
900
3
23
1000
1300
3
24
1000
800
I want to calculate backlog in a measure or any other way to have backlog be dynamic based on the factories I select. Backlog is calculated as follows:
Backlog = Capacity - (Request + Previous week backlog); where we have backlog when requests + pre. week backlog exceeds capacity or else it is 0. I cannot move capacity from future weeks, so the backlog would always accumulate going forward
Eg. If I select Factory 1, my backlog should look as follows:
Factory Selected: 1
Week
Backlog
21
0
22
-200
23
-300
24
-100
Factory Selected: 1,2
Week
Backlog
21
0
22
-100
23
0
24
-400
Factory Selected: 1,3
Week
Backlog
21
0
22
-100
23
-500
24
0
I have been trying to find a solution since the last 2 days. Let me know if you need any additional details. Any help will be greatly appreciated.
In DAX there are no loops and no recursion, this means that we must write some very ugly loop unrolling dax code. This is a minimal implementation of a working measure, but to make it working in the general case the BacklogWeekNN variables must be added until reaching the maximum possible week depth in the model.
Backlog =
VAR MinWeek = CALCULATE(MIN( T[Week] ), REMOVEFILTERS( T ) )
VAR MaxWeek = MAX( T[Week] )
VAR TAggregated =
ADDCOLUMNS(
CALCULATETABLE( VALUES( T[Week] ), T[Week] <= MaxWeek, REMOVEFILTERS( T ) ),
"#Capacity", CALCULATE( SUM( T[CAPACITY] ), ALLEXCEPT( T, T[Week], T[Factory ID] ) ),
"#Request", CALCULATE( SUM( T[Request] ), ALLEXCEPT( T, T[Week], T[Factory ID] ) )
)
VAR BacklogWeek00 = SUMX( FILTER( TAggregated, T[Week] = MinWeek ), [#Capacity] - [#Request] ) + 0
VAR BacklogWeek01 = SUMX( FILTER( TAggregated, T[Week] = MinWeek + 1), [#Capacity] - [#Request] ) + IF(BacklogWeek00 > 0, 0, BacklogWeek00)
VAR BacklogWeek02 = SUMX( FILTER( TAggregated, T[Week] = MinWeek + 2), [#Capacity] - [#Request] ) + IF(BacklogWeek01 > 0, 0, BacklogWeek01)
VAR BacklogWeek03 = SUMX( FILTER( TAggregated, T[Week] = MinWeek + 3), [#Capacity] - [#Request] ) + IF(BacklogWeek02 > 0, 0, BacklogWeek02)
VAR Result = IF(BacklogWeek03 > 0, 0, BacklogWeek03)
RETURN Result
This way we can obtain the desired resulting matrix using a slicer to select the factories (I'm afraid there are a few errors in the expected result samples int the question)
Edit: I used 'FILTER( TAggregated, T[Week] = MinWeek )' instead of the equivalent CALCULATE/CALCULATTABLE DAX code to avoid context transition happening and because the weeks table has very few rows to be iterated (I can imagine a maximum of a few tens or at maximum hundreds of rows if keeping a few years history)
I have data like this,
App_Num Days Price
A1 10 100
A1 11 150
A2 11 200
A3 12 250
A3 12 300
A4 20 350
A4 21 400
The average of the days is displayed on a card visual as 13.857.
Now, there are two parameters that are set for user to adjust the values and see.
Total Value (Min and Max Range)
Days
For example, if the user selects 0-280- it is expected to list A1 (100 + 150 = 250 less than 280) and A2 (200 being less than 280).
I used a DAX like this and built a table like this,
Apps_in_scope =
Var min_amount = Min('Total Value'[Total Value])
Var max_amount = Max('Total Value'[Total Value])
var required_app_num = SELECTEDVALUE(Table1[App_Num])
Var required_amount = CALCULATE(sum(Table1[Price]),FILTER(Table1,Table1[App_Num] = required_app_num))
var in_scope = if(And(required_amount <= max_amount, required_amount >= min_amount),1,0)
return in_scope
And I was able to produce a Visual like this,
App_Num Apps_in_scope
A1 1
A2 1
A3 0
A4 0
Now after selecting the total price range, if the user selects the days parameter manually to be 15 then my average will shift as per this logic.
A1 has 2 transactions and with in the selected price range of 280 will become (15*2)
A2 has 1 transaction and with in the selected price range of 280 become (15*1)
A3 has 2 transaction and will remain unchanged (12+12)
A4 has 2 transactions and will remain unchanged (20+21)
So my new measure which I want to place on the card is expected to show now (15+15+15+12+12+20+21)/7 = 15.714
How can I write this measure. Kindly help me with this
I'd tweak your measure slightly so that it works better for taking the average:
Apps_in_scope_2 =
VAR min_amount = MIN ( 'Total Value'[Total Value] )
VAR max_amount = MAX ( 'Total Value'[Total Value] )
VAR required_amount =
CALCULATE ( SUM ( Table1[Price] ), ALLEXCEPT ( Table1, Table1[App_Num] ) )
VAR in_scope =
IF ( AND ( required_amount <= max_amount, required_amount >= min_amount ), 1, 0 )
RETURN
in_scope
With this tweak the average is fairly simple:
AvgMeasure =
VAR DaysParam = SELECTEDVALUE ( DaysSlicer[Days] )
RETURN
AVERAGEX( Table1, IF( [Apps_in_scope_2] = 1, DaysParam, Table1[Days] ) )
Edit:
Here's an alternative version that doesn't use the first measure but should scale better to large data tables.
AvgAlternate =
VAR min_amount = MIN ( 'Total Value'[Total Value] )
VAR max_amount = MAX ( 'Total Value'[Total Value] )
VAR DaysParam = SELECTEDVALUE ( DaysSlicer[Days] )
VAR apps =
ADDCOLUMNS (
SUMMARIZE (
Table1,
Table1[App_Num],
"#Price", SUM ( Table1[Price] ),
"#Rows", COUNT ( Table1[Price] )
),
"#Days",
IF (
AND ( [#Price] <= max_amount, [#Price] >= min_amount ),
DaysParam * [#Rows],
CALCULATE ( SUM ( Table1[Days] ) )
)
)
RETURN
DIVIDE ( SUMX ( apps, [#Days] ), SUMX ( apps, [#Rows] ) )
This is assuming that you have separate tables for your Price range and Days selection (as in what-if parameter tables).
My measure =
VAR apps =
SELECTCOLUMNS (
FILTER (
SUMMARIZE ( Table1, Table1[App_Num], "Total Price", SUM ( Table1[Price] ) ),
[Total Price] >= MIN ( 'Total Value'[Total Value] )
&& [Total Price] <= MAX ( 'Total Value'[Total Value] )
),
"App_Num", [App_Num]
)
RETURN
AVERAGEX (
Table1,
IF ( Table1[App_Num] IN apps, SELECTEDVALUE ( Days[Days] ), Table1[Days] )
)