Intersection of Customer product purchase (powerBI) - powerbi

I need help with producing a count of the intersections between customers and which items they have purchased. For example, if there are 5 products, a customer can purchase any single product or any combination of the 5. Customers can also re-purchase a product at any date - this is where my problem arises as an end user wants to be able to see the intersections for any selected date range.
I have managed to come up with a solution which includes the use of parameters but this is not ideal as the end user does not have access to change any parameters of the report.
I'm open to any solution that does not involve parameters, ideally a slicer with dates would be the best solution
The fields I have on the table are customer_ID, date_ID, and product
Example Data
customer_id date_id product
1 9/11/2018 A
1 10/11/2018 A
1 10/11/2018 B
1 11/11/2018 C
1 11/11/2018 A
2 9/11/2018 C
2 10/11/2018 D
2 11/11/2018 E
2 11/11/2018 A
3 10/11/2018 A
3 10/11/2018 B
3 11/11/2018 A
3 11/11/2018 B
3 11/11/2018 B
4 10/11/2018 A
4 11/11/2018 A
5 9/11/2018 A
5 10/11/2018 B
5 10/11/2018 E
5 10/11/2018 D
5 11/11/2018 C
5 11/11/2018 A
6 9/11/2018 A
6 10/11/2018 A
6 11/11/2018 A
Possible output with different slicer selections
Any help at all would be greatly appreciated

This is pretty tricky since I can't think of a way to use the values of a dynamically calculated table as a field in a visual. (You can create calculated tables, but those aren't responsive to slicers. You can also create dynamically calculated tables inside of a measure, but measures don't return tables, just single values.)
The only way I can think of to do this requires creating a table for every possible product combination. However, if you have N products, then this table has 2N rows and that blows up fast.
Here's a calculated table that will output all the combinations:
Table2 =
VAR N = DISTINCTCOUNT(Table1[product])
VAR Products = SUMMARIZE(Table1,
Table1[product],
"Rank",
RANKX(ALL(Table1),
Table1[product],
MAX(Table1[product]),
ASC,
Dense
)
)
VAR Bits = SELECTCOLUMNS(GENERATESERIES(1, N), "Bit", [Value])
VAR BinaryString =
ADDCOLUMNS(
GENERATESERIES(1, 2^N),
"Binary",
CONCATENATEX(
Bits,
MOD( TRUNC( [Value] / POWER(2, [Bit]-1) ), 2)
,,[Bit]
,DESC
)
)
RETURN
ADDCOLUMNS(
BinaryString,
"Combination",
CONCATENATEX(Products, IF(MID([Binary],[Rank],1) = "1", [product], ""), "")
)
Then add a calculated column to get the column delimited version:
Delimited =
VAR Length = LEN(Table2[Combination])
RETURN
CONCATENATEX(
GENERATESERIES(1,Length),
MID(Table2[Combination], [Value], 1),
","
)
If you put Delimited the Rows section on a matrix visual and the following measure in the Values section:
customers =
VAR Summary = SUMMARIZE(Table1,
Table1[customer_id],
"ProductList",
CONCATENATEX(VALUES(Table1[product]), Table1[product], ","))
RETURN SUMX(Summary, IF([ProductList] = MAX(Table2[Delimited]), 1, 0))
And filter out any 0 customer values, you should get something like this:
So yeah... not a great solution, especially when N gets big, but maybe better than nothing?
Edit:
In order to work for longer product names, let's use a delimiter in the Combination concatenation:
CONCATENATEX(Products, IF(MID([Binary],[Rank],1) = "1", [product], ""), ",")
(Note the "" to "," change at the end.)
And then rewrite the Delimited calculated column to remove excess commas.
Delimited =
VAR RemoveMultipleCommas =
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(Table2[Combination], ",,", ","),
",,", ","),
",,", ","),
",,", ",")
VAR LeftComma = (LEFT(Table2[Combination]) = ",")
VAR RightComma = (RIGHT(Table2[Combination]) = ",")
RETURN
IF(RemoveMultipleCommas <> ",",
MID(RemoveMultipleCommas,
1 + LeftComma,
LEN(RemoveMultipleCommas) - RightComma - LeftComma
), "")
Finally, let's modify the customers measure a bit so it can subtotal.
customers =
VAR Summary = SUMMARIZE(Table1,
Table1[customer_id],
"ProductList",
CONCATENATEX(VALUES(Table1[product]), Table1[product], ","))
VAR CustomerCount = SUMX(Summary, IF([ProductList] = MAX(Table2[Delimited]), 1, 0))
VAR Total = IF(ISFILTERED(Table2[Delimited]), CustomerCount, COUNTROWS(Summary))
RETURN IF(Total = 0, BLANK(), Total)
The Total variable gives the total customer count for the total. Note that I've also set zeros to return as blank so that you don't need to filter out zeros (it will automatically hide those rows).

You can also try this measure to calculate the result.
[Count Of Customers] :=
VAR var_products_selection_count = DISTINCTCOUNT ( Sales[product] )
VAR var_customers = VALUES ( Sales[customer_id] )
VAR var_customers_products_count =
ADDCOLUMNS(
var_customers,
"products_count",
VAR var_products_count =
COUNTROWS (
FILTER (
CALCULATETABLE ( VALUES ( Sales[product] ) ),
CONTAINS (
Sales,
Sales[product],
Sales[product]
)
)
)
RETURN var_products_count
)
RETURN
COUNTROWS (
FILTER (
var_customers_products_count,
[products_count] = var_products_selection_count
)
)

I think I've found a better solution/workaround that doesn't require precomputing all possible combinations. The key is to use a rank/index as a base column and then built off of that.
Since the customer_id is already nicely indexed starting from 1 with no gaps, in this case, I will use that, but if it weren't, then you'd want to create an index column to use instead. Note that there cannot be more distinct product combinations within a given filter context than there are customers since each customer only has a single combination.
For each index/rank we want to find the product combination that is associated with it and the number of customers for that combination.
ProductCombo =
VAR PerCustomer =
SUMMARIZE (
ALLSELECTED ( Table1 ),
Table1[customer_id],
"ProductList",
CONCATENATEX ( VALUES ( Table1[product] ), Table1[product], "," )
)
VAR ProductSummary =
SUMMARIZE (
PerCustomer,
[ProductList],
"Customers",
DISTINCTCOUNT ( Table1[customer_id] )
)
VAR Ranked =
ADDCOLUMNS (
ProductSummary,
"Rank",
RANKX (
ProductSummary,
[Customers] + (1 - 1 / RANKX ( ProductSummary, [ProductList] ) )
)
)
VAR CurrID =
SELECTEDVALUE ( Table1[customer_id] )
RETURN
MAXX ( FILTER ( Ranked, [Rank] = CurrID ), [ProductList] )
What this does is first create a summary table that computes the product list for each customer.
Then you take that table and summarize over the distinct product lists and counting the number of customers that have each particular combination.
Then I add a ranking column to the previous table ordering first by the number of customers and tiebreaking using a dictionary order of the product list.
Finally, I extract the product list from this table where the rank matches the index/rank of the current row.
You could do a nearly identical measure for the customer count, but here's the measure I used that's a bit simpler and handles 0 values and the total:
Customers =
VAR PerCustomer =
SUMMARIZE (
ALLSELECTED ( Table1 ),
Table1[customer_id],
"ProductList",
CONCATENATEX ( VALUES ( Table1[product] ), Table1[product], "," )
)
VAR ProductCombo = [ProductCombo]
VAR CustomerCount =
SUMX ( PerCustomer, IF ( [ProductList] = ProductCombo, 1, 0 ) )
RETURN
IF (
ISFILTERED ( Table1[customer_id] ),
IF ( CustomerCount = 0, BLANK (), CustomerCount ),
DISTINCTCOUNT ( Table1[customer_id] )
)
The result looks like this

Related

Sum 5 lines of the max values in a column and get the % in power bi

I have a table with some contracts, like this:
Contract Num
Another header
Value
123456
Cleaning
123.541,00--
544311
Security
200.000,00--
254856
Cleaning
23.581,00--
048941
Security
80.000,00--
128546
Cleaning
300.500,00--
255311
Security
99.000,00--
130056
Cleaning
543.541,00--
859311
Security
10.000,00--
I want to get this in Power Bi:
The value of the 5 most expensive contracts
How much these 5 represents in % of the total sum.
I got the letter A in a card applying filters (N Superior), but I can't work with it in a measure. What expression can I use to get a number of line in a column? How can I solve this in a measure?
thanks
Hello Please test this DAX Code:
This gives you the TOP5 Total:
Top5_Total =
VAR TOP5Total =
SUMX ( TOPN ( 5, YourTable, [Value] ), [Value] )
RETURN
TOP5Total
And This gives you the ratio of Top5 To All Totals:
RatioOfTop5_To_Total =
VAR TOP5Total =
SUMX ( TOPN ( 5, YourTable, [Value] ), [Value] )
VAR Total =
CALCULATE ( SUM ( YourTable[Value] ), ALL ( YourTable ) )
VAR PercentOfTop5_To_Total =
DIVIDE ( 100 * TOP5Total, Total )
RETURN
PercentOfTop5_To_Total

DAX Measure to count Rows if relation may not exist

I am looking for a DAX measure to solve the following problem:
Count the number of rows in the dimension table where the Fact table either has no rows or the score is 0.
Table A (Dimension Table)
ID
name
1
a
2
b
3
c
Table B (Fact Table)
ID
score
1
0
1
1
1
2
2
5
Expected Result
In this example, I would expect 2, as ID=1 has one row with score=0 and ID=3 as no corresponding row in the Fact Table.
I came up with this measure which gives me the number of rows that have no corresponding row in the fact table, but I am not able to integrate the first condition:
CALCULATE(COUNTROWS('Dimension'), FILTER ('Dimension', ISBLANK ( CALCULATE ( COUNT ('Fact'[id]) ) )))
Probably much more straightforward methods, but try this measure for now:
MyMeasure =
VAR MyTable =
ADDCOLUMNS(
Table_A,
"Not in Table_B", NOT (
Table_A[ID]
IN DISTINCT( Table_B[ID] )
),
"Zero Score in Table_B",
CALCULATE(
COUNTROWS( Table_B ),
Table_B[score] = 0
) > 0
)
RETURN
SUMX(
MyTable,
[Not in Table_B] + [Zero Score in Table_B]
)
You can also try this
CountID =
VAR ScoreZero =
COUNTROWS ( FILTER ( TableB, [score] = 0 ) )
VAR NonExistentIDs =
COUNTROWS ( EXCEPT ( DISTINCT ( TableA[ID] ), DISTINCT ( TableB[ID] ) ) )
RETURN
ScoreZero + NonExistentIDs
This also works, not sure it's a good idea to nest CALCULATE:
CALCULATE(COUNTROWS('Table_A'), FILTER ('Table_A', ISBLANK ( CALCULATE ( COUNT ('Table_B '[id]) ) ) || CALCULATE(COUNTAX(Filter('Table_B ','Table_B '[score]=0),'Table_B '[id])>=1)))

How do I calculate how many distinct / unique products are available in multiple or all U.S. states?

I am trying to determine how many distinct products are available in multiple or all countries. (I am going to focus on 3 U.S. states, WA, OR and CA)
For an example, I have a table that looks like this:
Product
State
First
WA
First
CA
First
CA
Second
WA
Second
OR
Second
CA
Second
OR
Third
OR
Third
WA
Third
WA
Third
WA
Fourth
WA
Fourth
CA
Fourth
OR
Fourth
CA
From the table, I have 4 unique products, and 3 unique states. Using dax, I want to find the unique products that are available in all 3 states.
The output output should show 2, for product Second and Fourth since they have cover states WA, CA and OR.
I've attempted doing this with
dax = CALCULATE(DISTINCTCOUNT(table1[product],filter(table1,[state] IN {"WA","CA","OR"}))
but it returns a maximum number of distinct products for whichever state.
You can try this
Measure4 =
VAR _0 =
CONCATENATEX ( VALUES ( 'fct'[State] ), fct[State], ",", fct[State], DESC )
VAR _1 =
COUNTX ( VALUES ( 'fct'[State] ), fct[State] )
VAR _2 =
IF ( _1 > 2, _0, BLANK () )
RETURN
_2
Edit
You can create a following measure after the measure above to give you the desired result in a card
newMeasure =
COUNTX (
FILTER (
ADDCOLUMNS (
SUMMARIZE (
fct,
fct[Product],
"test", CONCATENATEX ( VALUES ( fct[State] ), fct[State], ",", fct[State], DESC )
),
"test2", [Measure4]
),
[test2] <> BLANK ()
),
[test2]
)
You can try with INTERSECT function (from your sample data measure return One, because product Fourth dont have 'OR'):
dax =
var __WA_product = CALCULATETABLE(VALUES(table1[product]), filter(table1,[state] = "WA"))
var __CA_product = CALCULATETABLE(VALUES(table1[product]), filter(table1,[state] = "CA"))
var __OR_product = CALCULATETABLE(VALUES(table1[product]), filter(table1,[state] = "OR"))
return
countrows( INTERSECT(INTERSECT(__WA_product, __CA_product ), __OR_product ))

ALLEXCEPT not working when filtering blanks

I have a simple problem. My DAX measure does not seem to be working correctly when I filter for non-existing values. Here are some details:
Table:
Column1: A,A,A,A,A,B,B,B,B
Column2: 1,2,3,4,5,1,2,3,5
Measure = calculate(countrows(table), allexcept(column1))
Card Visual returns correct row count when I filter by column1 (any value in filtering pane)
However it returns wrong row count when I filter by column2 = "4" and Column1 = "B" (in filtering pane). It seems that it should ingore filtering by column2 and it does except when I specifically filer for value = "4". It gives "blank" result value in a card visual then.
Any ideas why?
Here's the screen. I would like to populate that blank cell with "4" (in a singe-table data model.enter image description here
In your case you dont need to add allexcept in your measure. Below code would be fine.
TestMeasure = countrows(Test_Data)
PFB screenshot
I am hoping that you have a data model as following
table name _dim1
colA
A
B
C
table name _dim2
colB
1
2
3
4
5
table name _fact
colA
colB
A
1
A
2
A
3
A
4
A
5
B
1
B
2
B
3
B
5
C
2
C
3
If you have this you can reach where you need by using following measures
Measure3 =
CALCULATE ( COUNTROWS ( _fact ), ALL ( _dim2[colB] ), VALUES ( _fact[colA] ) )
Measure9 =
VAR _1 =
MAX ( _dim2[colB] )
VAR _2 =
CALCULATE (
MAXX (
FILTER ( _dim2, _dim2[colB] <= _1 ),
LASTNONBLANKVALUE ( _dim2[colB], [Measure3] )
),
ALL ( _dim2[colB] )
)
RETURN
_2
Measure10 =
VAR _1 =
MAX ( _dim2[colB] )
VAR _2 =
CALCULATE (
MAXX (
FILTER ( _dim2, _dim2[colB] > _1 ),
FIRSTNONBLANKVALUE ( _dim2[colB], [Measure3] )
),
ALL ( _dim2[colB] )
)
RETURN
IF ( ISBLANK ( [Measure9] ) = TRUE (), _2, [Measure9] )
I don't think you can reach here from a single table like following
colA
colB
A
1
A
2
A
3
A
4
A
5
B
1
B
2
B
3
B
5
C
2
C
3

DAX if else for measure

How to use if else for DAX in the measure. If row value =1 then take the var a calculated value else take the var b calculated value
x:=var a=[DATA1]
var b=[DATA2]
return(if([HOUR]=1),a,b)
I get error using above formula
It seems your problem is that you are not aggregating the columns while creating the measure. Measures only works aggregating data in a given context, generally if you want to perform calculations per row you should use a calculated column instead of a measure.
And the DAX expression for a calculated column should be:
MyColumn = IF([HOUR] = 1, [DATA1], [DATA2])
Otherwise if you want to use a measure you have to explicitely aggregate the column values in the given context, i.e:
MyMeasure =
VAR a =
FIRSTNONBLANK ( ExampleTable[Data1], 0 )
VAR b =
FIRSTNONBLANK ( ExampleTable[Data2], 0 )
RETURN
IF ( SUM ( ExampleTable[Hour] ) = 1, a, b )
Or simply:
MyMeasure =
IF (
SUM ( [Hour] ) = 1,
FIRSTNONBLANK ( ExampleTable[Data1], 0 ),
FIRSTNONBLANK ( ExampleTable[Data2], 0 )
)
Let me know if this helps.