客户产品购买的交集(powerBI)

时间:2018-11-13 13:36:07

标签: powerbi dax powerbi-desktop

我需要帮助统计客户之间的交叉点以及他们购买了哪些商品。例如,如果有5种产品,则客户可以购买任何一种产品或5种产品的任何组合。客户还可以在任何日期重新购买产品-这是我遇到的问题,因为最终用户希望能够查看任何选定日期范围的相交。

我设法提出了一个使用参数的解决方案,但这并不理想,因为最终用户无权更改报告的任何参数。

我愿意接受任何不涉及参数的解决方案,理想情况下,带有日期的切片器将是最佳解决方案

我在表上的字段是customer_ID,date_ID和产品

示例数据

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

具有不同切片器选择的可能输出

output

任何帮助都将不胜感激

3 个答案:

答案 0 :(得分:0)

这很棘手,因为我想不出一种方法来将动态计算的表的值用作视觉中的字段。 (您可以创建计算表,但是这些表不对切片器做出响应。您还可以在度量内部创建动态计算表,但是度量不返回表,而仅返回单个值。)

我想到的唯一方法是为每种可能的产品组合创建一个表。但是,如果您有N个产品,则此表有2 N 行,并且会很快爆炸。

这是一个计算表,将输出所有组合:

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], ""), "")
)

然后添加计算列以获取列分隔版本:

Delimited = 
VAR Length = LEN(Table2[Combination])
RETURN
CONCATENATEX(
    GENERATESERIES(1,Length),
    MID(Table2[Combination], [Value], 1),
    ","
)

如果将Delimited的“行”部分放在矩阵视觉上,并将以下度量放在“值”部分:

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))

并过滤掉任何0个客户值,您应该得到类似这样的信息:

Slicer and Matrix


是的...不是一个很好的解决方案,特别是当N变大时,也许总比没有好?


编辑:

为了使用更长的产品名称,让我们在Combination串联中使用定界符:

 CONCATENATEX(Products, IF(MID([Binary],[Rank],1) = "1", [product], ""), ",")

(请注意,将""更改为","。)

然后重写Delimited计算列以删除多余的逗号。

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
    ), "")

最后,让我们对customers进行一些修改,使其小计。

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)

Total变量给出了总计的客户总数。请注意,我还设置了零以返回为空白,这样您就不必过滤掉零(它将自动隐藏这些行)。

Matrix and Slicer

答案 1 :(得分:0)

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
    )
)

答案 2 :(得分:0)

我认为我找到了一个更好的解决方案/解决方法,它不需要预先计算所有可能的组合。关键是要使用排名/索引作为基础列,然后以此作为基础。

由于customer_id已经很好地从1开始无索引的索引,在这种情况下,我将使用它,但是如果不是,那么您将要创建一个索引列来代替。请注意,由于每个客户只有一个组合,因此在给定的过滤器上下文中,没有比客户更多的独特产品组合。

对于每个索引/排名,我们要查找与其关联的产品组合以及该组合的客户数量。

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] )

首先要做的是创建一个汇总表,以计算每个客户的产品列表。

然后,您使用该表并汇总不同的产品列表,并计算具有每种特定组合的客户数量。

然后,我在前一张表中添加一个排名列,该列首先按客户数量排序,并使用产品列表的字典顺序来平局决胜。

最后,我从该表中提取产品列表,其排名与当前行的索引/排名匹配。


您可以对客户数量进行几乎相同的度量,但这是我使用的度量,它稍微简单一些,可以处理0个值和总计:

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] )
    )

结果看起来像这样

Example Output