Calculating Pareto Table for long-type data in Power BI

Viewed 64

Hello lovely people of SO,

I have a dataset that looks like so:

ID SALE PRODUCT REGION
SE_056 AAA NORTH
XT-558 XXX NORTH
8547Y CCC NORTH
TY856 XXX NORTH
D-895 BBB SOUTH
ER5H CCC SOUTH
5F6F-GD CCC SOUTH
65-FFD TTT SOUTH
56-YU XXX SOUTH

I would like to create a table that will show me the subtotal (COUNT) for each product as well as their indivudal percentage and cumulative percentage like so:

PRODUCT subtotal Percentage Cum Percentage
CCC 3 0,33333333 0,333333333
XXX 3 0,33333333 0,666666667
AAA 1 0,11111111 0,777777778
BBB 1 0,11111111 0,888888889
TTT 1 0,11111111 1

Please notice that I want this table to be sort by highest subtotal to lowest subtotal and that in that matter the the cumulative percentage be as well calculated, PBI is not easy and is really coming for my mental health and I cannot find a way to get my table to be sort by highest subtotal and have the cum % calculated in that same order so if you can help me out PLEASE KNOW that i will be forever thankful

if you guys can help me out I will be so thankful I will be very attentive to your responses.

3 Answers

You can do this in a report visualisation with a few measures, to calculate number of sales, percentage of sales, product rank by sales (then product name), and cumulative sales percentage:

# Sales:
# Sales = COUNT ( Sales[ID SALE] )
% Sales:
% Sales = 
    DIVIDE (
        [# Sales],
        CALCULATE ( 
            [# Sales],
            REMOVEFILTERS ( Sales[PRODUCT] )
        )
    )
% Sales (Cumulative):
% Sales (Cumulative) = 
VAR CurrentRank = 
    IF ( 
        ISINSCOPE ( Sales[PRODUCT] ),
        [Rank by Sales then Product],
        DISTINCTCOUNT ( Sales[PRODUCT] )
    )
RETURN
    SUMX ( 
        ALL ( Sales[PRODUCT] ),
        IF ( 
            [Rank by Sales then Product] <= CurrentRank,
            [% Sales],
            BLANK()
        )
    )
Rank by Product:
Rank by Product = 
    RANKX ( 
        ALL ( Sales[PRODUCT] ),
        FIRSTNONBLANK ( Sales[PRODUCT], 1 ),,
        ASC,
        Dense
    )
Rank by Sales then Product:
Rank by Sales then Product = 
    RANKX (
        ALL ( Sales[PRODUCT] ),
        [# Sales]  + ( 1 / [Rank by Product] ),,
        DESC,
        Dense
    )

Sample output:

Sample output

EDIT: You could do the % Sales (Cumulative) measure in on, and remove the 'Rank' measures, but it's significantly less legible:

% Sales (Cumulative) = 
VAR CurrentRank = 
    IF ( 
        ISINSCOPE ( Sales[PRODUCT] ),
        RANKX (
            ALL ( Sales[PRODUCT] ),
            [# Sales]  + 
            DIVIDE ( 
                1,
                CALCULATE (
                    RANKX ( 
                        ALL ( Sales[PRODUCT] ),
                        FIRSTNONBLANK ( Sales[PRODUCT], 1 ),,
                        ASC,
                        Dense
                    )
                )
            ),,
            DESC,
            Dense
        ),
        DISTINCTCOUNT ( Sales[PRODUCT] )
    )
RETURN
    SUMX ( 
        ALL ( Sales[PRODUCT] ),
        IF ( 
            RANKX (
                ALL ( Sales[PRODUCT] ),
                [# Sales]  + 
                DIVIDE ( 
                    1,
                    CALCULATE (
                        RANKX ( 
                            ALL ( Sales[PRODUCT] ),
                            FIRSTNONBLANK ( Sales[PRODUCT], 1 ),,
                            ASC,
                            Dense
                        )
                    )
                ),,
                DESC,
                Dense
            ) <= CurrentRank,
            [% Sales],
            BLANK()
        )
    )

You could also accomplish this in the Query editor (Home=>Transform Data).

In the Advanced Editor, paste the code below except for the first few lines that will be there reading in your existing data and perhaps setting the data type.

Then examine the code comments and explore the Applied Steps window (after closing the advanced editor) to understand the algorithm.

let

//Change next line to reflect your actual data source
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],

//set data type
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"ID SALE", type text}, {"PRODUCT", type text}, {"REGION", type text}}),

//Group by Product and Aggregate by Count
    #"Grouped Rows" = Table.Group(#"Changed Type", {"PRODUCT"}, {
        {"Subtotal", each Table.RowCount(_), Int64.Type}}),

//Sort subtotal row descending
    #"Sorted Rows" = Table.Sort(#"Grouped Rows",{{"Subtotal", Order.Descending}}),

//Add column with percentage for each subtotal
    #"Added Custom" = Table.AddColumn(#"Sorted Rows", "Percentage", 
            each [Subtotal] / List.Sum(#"Sorted Rows"[Subtotal]), Percentage.Type),

//Add Running total calculation for the cumulative percentage column
    #"Cumulative Percentage" = 
        Table.FromColumns(
            Table.ToColumns(#"Added Custom") &
                {List.Generate(
                    ()=>[cp=#"Added Custom"[Percentage]{0}, idx=0],
                    each [idx] < Table.RowCount(#"Added Custom"),
                    each [cp=List.Sum({[cp]}) + #"Added Custom"[Percentage]{[idx]+1}, idx=[idx]+1],
                    each [cp])},
            type table[PRODUCT=text,Subtotal=Int64.Type, Percentage = Percentage.Type, Cumulative Percentage = Percentage.Type] 
                    )

in
    #"Cumulative Percentage"

Results
enter image description here

A big, but simple measure that doesn't need to be commented. You can use it in your visual and as a base for your further calculations. The result is not sorted but you can do it as you like in the visual and it will not affect values.

VAR tbl =
    ADDCOLUMNS(
         VALUES('dataset'[PRODUCT])
        ,"subtotal",CALCULATE(CountRows('dataset'))
        ,"Percentage",CALCULATE(CountRows('dataset'))/CountRows('dataset')

    )


VAR withRankingValue1 = 
    ADDCOLUMNS(
        tbl
        ,"rowsWithLowerPercentage",VAR val=[subtotal] RETURN COUNTROWS(FILTER(tbl,[subtotal]>val))
    )
VAR withRankingValue2 = 
    ADDCOLUMNS(
        withRankingValue1
        ,"rankInGroup"
                ,
                VAR podVal=[PRODUCT]
                VAR rv1Val=[rowsWithLowerPercentage]
                RETURN 
                    COUNTROWS(
                            FILTER(
                                withRankingValue1
                                ,AND(
                                    [PRODUCT]<podVal
                                    ,[rowsWithLowerPercentage]=rv1Val
                                )
                            )
                    )+1
    )
VAR withFinalRanking = 
    ADDCOLUMNS(
        withRankingValue2
        ,"Rank",INT(CONCATENATE([rowsWithLowerPercentage],[rankInGroup]))
    )
VAR Result =
    ADDCOLUMNS(
        withFinalRanking
        ,"Cum Percentage",
                    VAR rankVal=[Rank]
                    VAR filtTbl = FILTER(withFinalRanking,[Rank]<=rankVal)
                    RETURN SUMX(filtTbl,[Percentage])         
    
    )
Return 
    SUMX(Result,[Cum Percentage])

enter image description here

Related