BI技巧丨用户留存问题

老板:白茶,你说咱这行业咋就留不住人呢?
白茶:(黑人问号??)老板,你说的是没有回头客么?
老板:对对对,就是这个意思,能不能搞一个报表,让我知道顾客是在哪个阶段流失的?
白茶:唔…问题不大!

对于很多新兴行业来说,用户留存都是一个比较突出的问题。因为用户就代表着市场的占有率,也代表商业的大盘,盘子越大,能产生的价值也越高,因此越来越多的企业开始重视用户留存的问题。

本期咱们来聊一聊用户留存的问题,这个问题对于零售快销、电商行业、以及游戏行业都具有很高的参考价值。

先来看看本期的案例数据:

数据非常的简单,只有基础的日期列、用户ID、产品以及售卖金额。

解释一下什么叫留存:

简而言之,顾客今天在我这里买东西了,明天依然来我这里买,那么这两天对于此用户就产生了留存的概念;

玩家今天登录客户端选择了打游戏,明天依然登录打游戏,这个也是用户留存;

浏览者今天观看我直播,明天依然选择观看,这个还是留存。

对于大部分企业来说,这个概念习惯称之为用户留存,但是从互联网的角度来说,称之为流量也可以。

用户留存,我们需要对用户的数量进行统计,统计每个周期内的新客数量以及新客持续购买的数量。

编写基础的DAX函数:

C.CustomerNumber = 
DISTINCTCOUNTNOBLANK ( Fact_Sale[用户ID] )

有了基础的计算指标,我们的思路可以扩展一下,用户留存我们观测的不是某一个具体的时间点,而是一个阶段,比如我选择2021年8月1日,我更希望看到的是8月1日之前一段时间的数据。

因此我们的模型关系如下:

建立两张日期表,一张建立关系,一张不建立关系。

编写如下度量值:

阶段结束时间:

A.EndNode = 
SELECTEDVALUE ( Dim_Date_II[Date] )

建立参数:

注:也可以不建立参数, 这里是为了扩展性考虑,可以自由的筛选展示阶段。

阶段开始时间:

B.InitialNode = 
TOPN (
    1,
    FILTER ( ALL ( Dim_Date[Date] ), [Date] <= [A.EndNode] - [Period] ),
    'Dim_Date'[Date], DESC
)

阶段内用户数量:

D.CurrentCustomerNumber = 
VAR CurrentCustomerNumber =
    SUMMARIZE (
        'Fact_Sale',
        'Fact_Sale'[用户ID],
        Dim_Date[Date],
        "@CUSTOMER", [C.CustomerNumber]
    )
RETURN
    SUMX (
        FILTER (
            CurrentCustomerNumber,
            [Date] >= [B.InitialNode]
                && [Date] <= [A.EndNode]
        ),
        [@CUSTOMER]
    )

效果如下:

这样一个可以展示阶段的度量值就准备完毕了。

那么,我们现在需要考虑用户留存的问题,我们需要知道在当日购买的用户,次日或者第三日依然选择购买的用户有多少。

编写如下度量值:

E.FirstDateCustomerNumber = 
VAR FirstDateCustomerNumberTable =
    ADDCOLUMNS (
        SUMMARIZE ( 'Fact_Sale', 'Fact_Sale'[用户ID], Dim_Date[Date] ),
        "@FirstDateCustomerNumber",
            VAR FirstDateKey = [Date] + 1
            RETURN
                CALCULATE ( [C.CustomerNumber], 'Dim_Date'[Date] = FirstDateKey )
    )
VAR FirstDateCustomerNumber =
    SUMX (
        FirstDateCustomerNumberTable,
        IF (
            [Date] >= [B.InitialNode]
                && [Date] <= [A.EndNode] - 1,
            [@FirstDateCustomerNumber]
        )
    )
RETURN
    IF (
        [Period] >= 1,
        FirstDateCustomerNumber ,
        BLANK ()
    )

解释一下代码含义:

通过定义一张虚拟表,来减少性能的损耗;

添加“@FirstDateCustomerNumber”虚拟列,来计算次日依然购买的新客数量;

“@FirstDateCustomerNumber”虚拟列中使用VAR定义了一个来自虚拟表上下文的变量,通过内部上下文覆盖外部上下文的方式,实现次日人数的计算;

DAX中的部分数字是为了计算间隔天数,部分是为了阶梯式呈现;

最后结果输出,参照上面的逻辑,我们继续构建其他度量值。

F.SecondDateCustomerNumber = 
VAR SecondDateCustomerNumberTable =
    ADDCOLUMNS (
        SUMMARIZE ( 'Fact_Sale', 'Fact_Sale'[用户ID], Dim_Date[Date] ),
        "@SecondDateCustomerNumber",
            VAR SecondDateKey = [Date] + 2
            RETURN
                CALCULATE ( [C.CustomerNumber], 'Dim_Date'[Date] = SecondDateKey )
    )
VAR SecondDateCustomerNumber =
    SUMX (
        SecondDateCustomerNumberTable,
        IF (
            [Date] >= [B.InitialNode]
                && [Date] <= [A.EndNode] - 2,
            [@SecondDateCustomerNumber]
        )
    )
RETURN
    IF (
        [Period] >= 2,
        SecondDateCustomerNumber ,
        BLANK ()
    )

与上面度量值的差异就是数字参数不同。

这样的度量值,白茶一共构建了7个,假定留存周期7日为一个周期。

我们来看一下效果:

有一点小瑕疵,当某一天没有值的时候,该度量值白茶希望它消失。

添加一张展示使用的维度表:

编写如下度量值:

L.DisplayNumber = 
VAR DisplayIndex =
    SELECTEDVALUE ( Dim_Display[Index] )
RETURN
    SWITCH (
        TRUE (),
        DisplayIndex = 1, [D.CurrentCustomerNumber],
        DisplayIndex = 2, [E.FirstDateCustomerNumber],
        DisplayIndex = 3, [F.SecondDateCustomerNumber],
        DisplayIndex = 4, [G.ThirdDateCustomerNumber],
        DisplayIndex = 5, [H.FourthDateCustomerNumber],
        DisplayIndex = 6, [I.FifthDateCustomerNumber],
        DisplayIndex = 7, [J.SixthDateCustomerNumber],
        DisplayIndex = 8, [K.SeventhDateCustomerNumber],
        BLANK ()
    )

我们再来看一下效果:

这样的话我们就解决了度量值空值呈现的问题。

我们不光想知道每日留存的客户数量,我们还想知道留存率,继续编写度量值。

M.DisplayRetention = 
IF (
    [L.DisplayNumber] <> BLANK (),
    IF (
        SELECTEDVALUE ( Dim_Display[Index] ) = 1,
        FORMAT ( [L.DisplayNumber], "0" ),
        FORMAT ( [L.DisplayNumber] / [D.CurrentCustomerNumber], "0.00%" )
    ),
    BLANK ()
)

效果如下:

这样用户留存的核心模型就已经搭建出来了。

将这个故事完善一下,我们需要知道当前完整周期的时间段、完整周期的新客数量、周期结束用户留存的数量。

编写如下度量值:

完整周期的时间段:

O.FirstCycle = 
FORMAT (
    IF (
        MINX ( ALL ( Dim_Date[Date] ), [Date] ) >= [A.EndNode] - [Period],
        MINX ( ALL ( Dim_Date[Date] ), [Date] ),
        [A.EndNode] - [Period]
    ),
    "YYYY-MM-DD"
) & "~"
    & FORMAT ( [A.EndNode], "YYYY-MM-DD" )

完整周期的新客数量:

P.BeginCycleNumber = 
CALCULATE (
    [D.CurrentCustomerNumber],
    FILTER (
        ALLSELECTED ( 'Dim_Date' ),
        'Dim_Date'[Date]
            = IF (
                MINX ( ALL ( Dim_Date[Date] ), [Date] ) >= [A.EndNode] - [Period],
                MINX ( ALL ( Dim_Date[Date] ), [Date] ),
                [A.EndNode] - [Period]
            )
    )
)

周期结束用户留存的数量:

Q.EndCycleNumber = 
LASTNONBLANKVALUE ( ALLSELECTED ( Dim_Display[Index] ), [L.DisplayNumber] )

效果如下:

为了美观,白茶添加了一个配色的度量值:

N.DisplayRetentionColor = 
VAR CurrentValue =
    IF (
        SELECTEDVALUE ( Dim_Display[Index] ) = 1,
        [L.DisplayNumber],
        [L.DisplayNumber] / [D.CurrentCustomerNumber]
    )
VAR Color =
    IF (
        SELECTEDVALUE ( Dim_Display[Index] ) = 1,
        "#0D2248",
        IF (
            [M.DisplayRetention] <> BLANK (),
            SWITCH (
                TRUE (),
                CurrentValue >= 0.8, "#9C0A0D",
                CurrentValue >= 0.6, "#C91014",
                CurrentValue >= 0.4, "#E64B47",
                CurrentValue >= 0.2, "#FE8664",
                CurrentValue >= 0, "#FFD2A0"
            )
        )
    )
RETURN
    Color

对报表的整体进行调整,最终效果如下:

闲聊几句:

其实这个分析模型还是可以继续扩展的,如果我们可以拿到回访信息,那么搭配每个阶段的留存率,是可以直接分析出流失的主要原因;

针对游戏行业,此模型还可以计算连续活跃天数以及最终活跃,扩展度非常的高。

由于时间关系,本期就到这里了,喜欢的小伙伴可以自行模拟扩展。

小伙伴们❤GET了么?

(BOSS:哎,还是好难受。)

这里是白茶,一个PowerBI的初学者。

Fabric丨白茶 文章被收录于专栏

数据分析进阶之路,带你深入了解可视化技巧。

全部评论

相关推荐

11-09 11:01
济南大学 Java
Java抽象带篮子:外卖项目真得美化一下,可以看看我的详细的外卖话术帖子
点赞 评论 收藏
分享
寿命齿轮:实习就一段还拉了,项目一看就不是手搓,学历也拉了,技术栈看着倒是挺好,就是不知道面试表现能咋样。 不过现在才大三,争取搞两端大厂实习,或者一个纯个人项目+一段大厂,感觉秋招还是未来可期。
投递美团等公司10个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务