【DAX 系列】高清图解迭代原理并弃用 EARLIER

  • 2020 年 2 月 17 日
  • 筆記

到底什么是迭代?本文专为您准备。

首先,请死记:筛选和迭代是数据分析过程中的两大重要特性

  • 筛选,帮助我们从宏观到微观;
  • 迭代,帮助我们具体考察每一个微观元素。

这也是 DAX 中,筛选上下文和行上下文的设计学来由。本文会非常简单地让您搞清楚迭代的概念。

开始。

理解迭代

很多从事业务的小伙伴问:到底什么是迭代?

精确地讲,迭代,是对一个集合中元素的遍历

如下所示:

对于一个表的迭代,由于表是行的集合,每一行都表示同类事物的不同个体,如:不同的每一笔订单。很自然地可以将对表的迭代理解为对表中的行集合的迭代。

我们可以脑补一个箭头(例如:上图的右侧),这个箭头用来对表的行集合进行遍历,值得注意的是,我们不用关心它是怎么做到遍历的,不重要,只要知道表被遍历了。

在遍历的时候一般顺便可以做点坏事,例如,记住遍历过的每个值,这样就有了:

SUM.Value = SUM( SomeTable[Value] )    \ 本质上等价于:SUM.Value =  SUMX( SomeTable , SomeTable[Value] )

SUMX 的含义是:

  • 对 SUMX 的第一个参数(某个表),进行迭代;
  • 在迭代中,每次执行第二个参数,如: 取出值;
  • 加总它们。

如果你没什么感觉就对了。因为 SUMX 在这个例子中根本没干什么坏事。

在迭代中做坏事

SUMX 可以做很多坏事,例如:

Order.Sales =  SUMX( Order , Order[Volume] * RELATED( Product[Price] ) )

这个案例中 SUMX 就做了坏事了。

业务人员想算销售额,而订单中没保存单价,但可以从与订单关联的产品表中找到单价,那么销售额的计算就可以是:

  • 迭代订单;
  • 对每一笔订单,找到对应的单价,当前销售额=相关单价×当前数量;
  • 再加总它们。

这个坏事就很坏了,没有 SUMX 只有 SUM 就很难受。

此外,SUMX 还可以做很多坏事,例如:

【DAX 系列】总计行问题终极解决方案 中大量使用了 SUMX。

去 ↑ 挑战下脑力吧。

多层迭代

如果迭代一层没有让你晕菜,请看二层迭代:

左边每迭代一步,右边与之对应要迭代一轮。

典型应用就是 ABC 分析:

ABC分析 中有这样的累计度量值:

KPI % =  VAR vCurr = [KPI]  VAR vItems = FILTER( ALLSELECTED( Model_Product[子类别] ) , [KPI] >= vCurr )  RETURN CALCULATE( [KPI] , vItems ) / CALCULATE( [KPI] , ALLSELECTED( Model_Product ) )

出图如下:

其中,上面的折线就是一个积累占比,其逻辑如下:

  • 迭代产品[子分类],令 vCurr = 当前元素的[KPI]; (相当于上面的绿色箭头)
    • 对于每个 vCurr,重新迭代产品[子分类],(相当于上面的黄色箭头)
    • 如果黄色箭头指向元素的KPI大于当前绿色箭头指向元素的KPI则保留
    • 内圈迭代完成,剩下了 vItems 是在迭代中胜出的元素
  • 求这些 vItems 的 KPI 与整体 KPI 的比值 %。

这就是比当前元素大的积累元素的 KPI 占比%。

构成了 ABC 分析中的 % 折线。

用 VAR 彻底代替 EARLIER

很明显,我们有时候在多层迭代时,需要用内圈迭代的元素(黄色)来和外圈迭代的元素(绿色)进行对比,这就需要 EARLIER 了,其含义为更早的迭代,精确讲是更早的迭代中的行。

当我们脑子绕不过来的时候,我们永远可以这么做:

VAR vCurrKPI = [KPI] // 绿色元素  VAR vItems = FILETER ( SomeTable , [KPI] ? vCurrKPI )

其中,FILTER 会创建一个内圈迭代环境,那么 [KPI] 就是内圈的黄色值,而 vCurrKPI 就是外圈的绿色值。

迭代器

现在就应该可以充分理解什么是迭代器了,那么我们可以看得见它吗?看不见。

原因如下:

我们说到了迭代器是用来迭代的,迭代是用来干坏事的,如果光迭代不干坏事,那不是白迭代了。但是到底干什么坏事呢,有很多种坏事,例如:

  • SUMX,迭代时取出来计算后求和。 干得坏事是求和。
  • FILTER,迭代时按某个条件过滤。 干得坏事是过滤。
  • ADDCOLUMNS,迭代时,添加一列,并算出对应行中的元素。 干得坏事是加一列。

因此,我们可以发现:迭代 + 干坏事是不可分割的整体

  • 迭代是基础,没有迭代没法干坏事;
  • 干坏事是目的,不干坏事白迭代。

因此,在 DAX 中,所有带有需要处理集合中元素语义的功能都是干坏事,都内部包裹了一个看不见的迭代器。

总结

迭代,是很自然的。当你的业务逻辑涉及到对一堆元素(如:表行)进行遍历并在每一步都做点坏事的时候,一定会自然而然地用到某些函数,这些函数自然而然的都包裹了一个看不见的迭代器。

记得,在迭代的时候做坏事,不做坏事,DAX 不爱。

祝你玩得开心。