Пересечение покупки продукта Клиента (powerBI) - PullRequest
0 голосов
/ 13 ноября 2018

Мне нужна помощь с подсчетом пересечений между покупателями и приобретенными ими товарами. Например, если имеется 5 продуктов, покупатель может приобрести любой отдельный продукт или любую комбинацию из 5. Покупатели также могут повторно приобрести продукт в любой момент - вот где у меня возникает проблема, поскольку конечный пользователь хочет иметь возможность см. пересечения для любого выбранного диапазона дат.

Мне удалось найти решение, которое включает использование параметров, но это не идеально, так как конечный пользователь не имеет доступа для изменения каких-либо параметров отчета.

Я открыт для любого решения, которое не включает параметры, в идеале лучшим решением будет срез с датами

У меня в таблице есть поля customer_ID, date_ID и product

Пример данных

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 голосов
/ 15 ноября 2018
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
    )
)
0 голосов
/ 28 декабря 2018

Я думаю, что нашел лучшее решение / обходной путь, который не требует предварительного вычисления всех возможных комбинаций.Ключ заключается в том, чтобы использовать ранг / индекс в качестве базового столбца, а затем строить его из этого.

Поскольку 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

0 голосов
/ 13 ноября 2018

Это довольно сложно, так как я не могу придумать, как использовать значения динамически вычисляемой таблицы в качестве поля в визуале. (Вы можете создавать вычисляемые таблицы, но они не реагируют на срезы. Вы также можете создавать динамически вычисляемые таблицы внутри меры, но меры не возвращают таблицы, только отдельные значения.)

Единственный способ сделать это - создать таблицу для каждой возможной комбинации продуктов. Однако, если у вас есть 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 становится большим, но, может быть, лучше, чем ничего?


Edit:

Чтобы работать с более длинными названиями продуктов, давайте использовать разделитель в конкатенации 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

...