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的初学者。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容