Tableau15大详细级别表达式 · DAX复刻与解读(图文视频)

TOP 15 LOD expressions 案例,是 Tableau 9.0版本推出的LOD 功能经典案例,… 阅读更多 »Tableau15大详细级别表达式 · DAX复刻与解读(图文视频)

TOP 15 LOD expressions 案例,是 Tableau 9.0版本推出的LOD 功能经典案例,也可以作为评价 BI 工具优劣的标准之一。

【Tableau】15大详细级别表达式-思路解读版 (3) 2018/11

本文,尝试用详细级别和表逻辑,讲解 DAX 的实现,让读者更加坚信 Tableau 多么的易用!

📊 编号 | 难点 | 更新日期

编号

难点

更新日期

LOD1-Customer Order frequency 客户频次分析

聚合表的二次聚合;“上下文转换”

2024/10/06

LOD2- Cohort Analysis 客户阵列分析

聚合表和底表的世系;“上下文转换”

2024/10/07

LOD3- Daily profit KPI 每日的利润贡献及分类汇总

预先聚合的二次判断

2024/10/13

LOD15-4 Percent of total 不同层级的合计百分比

多个层次的预先聚合和计算优先级。

2024/10/26

⚠️ 未经授权,请勿将本文用于企业内部的培训、文档等商业活动。请各位国产 BI 同行尊重他人的劳动成果,要么付出你的金钱,要么表达你的尊重!二不相沾,非奸即盗。

LOD1 预先聚合作为维度:“不同订单频次的客户数量”

2024/10/05 调整次序,补充方法2 . 参考 https://dax.do/KSy9ReSx5rPtqm/

方法1:使用 Addcolumns 构建中间表

比如使用AddColumn函数创建一个table,如下:

这里包含了常见的字段。它会独立于原来的明细表创建一个聚合中间表,甚至可以在关系模型哪里看到。

AddColumns构建中间表示例
图:AddColumns函数构建中间表示例

之后在这种表的基础上,就可以创建分布了。

聚合中间表数据分布图
图:基于中间表的订单频次分布图

个人不建议使用“参数表”这样的复杂设置,参数表是“反分析”的,在需要交互的情况下才优先考虑。

方法2:使用 SummarizeColumns 创建聚合中间表

2024/10/05 更新

上面的 addcolumns 相当于构建了一个近乎物化的中间表,如果跳过这个阶段,仅仅在分析中创建临时中间表,可以如下:

而后,在 mid 聚合中间表基础上,再次使用 SummarizeColumns 完成二次聚合——以 mid 的聚合值"order_cnt"为最终问题的维度,以此前的CustomerKey 聚合成为度量。

SummarizeColumns聚合结果
图:两次SummarizeColumns聚合结果

两个数据表的结果预览

方法3:使用计算列和上下文转换

创建column(计算列),使用calculate计算订单频次,结合ALLexcept使聚合依据指定到客户ID字段,从而获得tableau中{ FIXED [客户ID]: COUNTD([ORDER ID])} 的效果。

DAX计算如下:

在视图中,分类是:客户订单频次,答案是“客户ID不同计数”,没有筛选范围。结果如下所示:

计算列上下文转换分类结果
图:计算列上下文转换客户分类结果

视频讲解与 DAX 代码

视频仅仅保留了 dax 的部分,完整部分查看《DAX 别裁新解》。

完整 CODE: 欢迎访问 https://dax.do/KSy9ReSx5rPtqm/

LOD2 预先聚合作为分类:“客户阵列分析 cohort analysis”

这就也需要“计算列”(calculated column)出场,计算列的性质等价于数据表字段,在数据表刷新时先于任意可视化视图而完成计算。典型的计算列字段有行级别的计算列和迭代计算列两种。

客户阵列分析获客日期计算
图:客户阵列分析获客日期计算示例

这个题目的难点是计算“每个客户的获客日期”,并与之前的数据表构建逻辑上的关系。如果单看获客日期,只需要如下即可:

世系错误导致分组失败示例
图:世系错误导致分组失败的示例截图

先说错误的方法:世系错误导致分组失败

这里介绍一种行不通的方法,即尝试构建一个中间表,而后从底表和中间表分别获得最终需要的维度。

如下所示,构建一个中间表,获得每个客户的首次订单日期:

完整要素中间表构建示例
图:包含所有要素的中间表构建方法

正确的方法1:创建一个包含所有要素的中间表

难点在于,如何把视图中所需要的所有字段(cohort_year、Order_year 以及聚合需要的 quantity——这里以 quantity 代替销售额,简化操作),都放在一个中间表中。如下所示:

以此为基础,就可以构建基于中间表的最终查询。

基于中间表的最终聚合查询
图:基于中间表完成的最终聚合查询

补充一个验证的图片:

逻辑字段上下文转换示例
图:使用逻辑字段上下文转换方法

基于上述的中间表(包含了最终需要的两个日期字段和一个聚合字段),就可以使用Summarizecolumns 完成最终的聚合了。

正确的方法2:使用逻辑字段和上下文转换

这个方法,相当于把上面临时表的字段逻辑,直接落在底表中,从而跳过了临时表阶段,所以更难以理解。

最终问题的两个年度字段都应该是明细中的 column:订单年度(order_year)、客户阵列年度(cohort_year),前者使用 year 函数计算,后者则需要 Calculate 表达式(包含聚合、指定详细级别,所谓的上下文转换)。

2.1 行级别的计算列:

为了理解方便,使用Year函数创建了 YEAR_ORDER 字段。

2.2 在明细行级别计算每个客户的阵列年度(cohort year)

特别注意,由于后续视图中会出现订单年度,它不能影响这里的MIN计算,因此使用ALL将其从external context中排除;又由于这里的min计算是以客户为依据的,但是这个context在外部不存在,因此通过allexcept将其加入计算的internal context。 这样,最终的计算,就是不受订单日期影响的、每个客户ID的首次订单日期。

(思考:这里是否可以删除 ALL(‘Global Superstore'[YEAR_ORDER]) 条件? 可以。)

计算列阵列年度计算结果
图:客户阵列年度计算列结果展示

2.3 基于上述两个计算列字段,完成最终计算

基于上述的 Order_year 和 Cohort_year 字段,再加上 Sales 表中已有的Quantity(这里替代销售额),就可以直接完成最终的视图聚合了。

计算结果如下:

基于计算列的最终聚合结果
图:基于计算列完成的最终聚合结果

相比于 LOD15-1,这个案例的难点是两个维度字段,都是计算而来,其中一个来自于明细,另一个来自于“预先聚合”,如何确保二者世系关系的一致性是难点。

视频讲解(DAX 部分):

视频讲解对应的 DAX 代码: 参见 https://dax.do/Fcx1S9EMmynQvN/

LOD15-3 Daily profit KPI

问题分析

How many days each month are highly profitable, profitable, or unprofitable?

标准问题结构:各年月、不同盈利状态(高盈利/盈利/非盈利)的天数?

1)维度*2:年月(计算可得)、不同盈利状态(预先聚合,作为维度)

度量*1:天数(可以直接聚合)

2)不同盈利状态:需要在指定详细级别聚合基础上判断

—— 基于 “每天的利润总和”的判断,即问题需要引用另一个详细级别的聚合计算

——只有fixed LOD能完成这个任务(引用其他层次的聚合,返回作为维度)

⚠️ 问题三个部分:分析范围、问题描述(维度)、问题答案(度量)

1、Tableau 的 LOD 方案

可以把 lod 理解为表,也可以理解为元组,甚至字段。

if { FIXED  [Order Date]: SUM([Profit])} >1000 
    then 'highly profitable'
elseif { FIXED  [Order Date]: SUM([Profit])} >0 
    then 'profitable'
else   'unprofitable'
END
LOD字段元组理解示意图
图:LOD作为表或元组理解示意

2、DAX 方案

DAX与SQL方案对比图
图:DAX方案与SQL方案对比展示

视频解说(简化版):

对应的代码 https://dax.do/SA9nu0P5h2AsAp/

3、SQL 方案

LOD5-4 Percent of total

问题描述:

For a given market (region), what is each country‘s percent of total global sales? 标准问题结构:在选定市场中,每个国家的销售额、在全球销售的占比?

四级详细级别分析图示
图:Percent of total四级详细级别

这个题目的关键是:识别问题中存在的四个详细级别,以及它们对应计算的优先级。

四个详细级别分别是:

  • L1:最高聚合度对应的详细级别,是 Percent of total 的 total,或者说百分比的“分母”部分。
  • L2:Market 详细级别,仅次于最高聚合度,是筛选条件对应的级别。
  • L3:Country 详细级别,是问题详细级别对应的级别,或者说主视图。
  • Lx:数据表记录对应的详细级别,是所有聚合最终的起点。

优先级 的关键是:total应该在筛选之前。

4.1 Tableau 的 FIXED LOD 方案

在 Tableau 中,只有 fixed LOD 的结果在“market= EU”这样的行级别筛选器之前,指定最高聚合度对应的详细级别,可以直接用如下的表达式:

{fixed :SUM (quantity)} 或者 { sum (quantity) }

4.2 DAX 的方案

code: https://dax.do/cuvj0u2Rb70mCC/

4.2.1 DAX 方案之 Measure

如果一个 measure 想要在筛选器之前完成,需要借助于 ALL 调节符。

4.2.2 DAX 的方案之 columns

4.3 SQL 逻辑

使用子查询获得筛选之前(where 之前)的聚合。聚合的值可以在最终的查询中作为分类,也可以作为度量——看如何被引用。这一点类似于 DAX 的 column和 measure。

下面,这里子查询的结果在最终被视为分类(dimension)。

而在下面,我们使用avg 聚合避免重复,只需要 group 1和2即可。

视频省略,参考 B 站课堂。

No comments yet