专栏首页PowerBI战友联盟Thinking in DAX with PowerBI - 逻辑框架 - 数据结构

Thinking in DAX with PowerBI - 逻辑框架 - 数据结构

上接 逻辑框架 - 计算逻辑,接下来的问题是数据结构。

数据结构,顾名思义,就是数据摆放的状态。例如:数据按表,集合,列表等形式摆放。

另外,当数据结构是表的时候,还包括了表之间的关系。对于这点,我们再另外研究。

在 PowerBI DAX 中,为了简化,数据结构只有一种表面形态:表。那当需要按照不同逻辑结构思考问题的时候,如何从表的结构形态衍生出其他结构形态?

将表作为表

将表作为表,是很自然的。例如:

{1}

这就表示了一个表,在 PowerBI DAX 中创建后,得到:

这里并没有给定表的列名,系统会自动按Value给出,当涉及多列时,例如:

{
    (1,"Anna",23),
    (2,"Tom",27)
}

得到:

这里并没有给定表的列名,系统会自动按Value加上列序号给出。

表与值的转化

在参与运算时,若某个表中只有一行一列,则可以被作为值。

这里常用的一个 DAX 函数有:VALUES,这用来从一个表中提取一列(会自动非重复化),例如:

这里请注意两点:

1、度量值的定义是正确的;

2、度量值的使用结果也是符合预期的。

但如果使用多值的表列,会得到这样的结果:

这里也请注意两点:

1、度量值的定义是正确的;

2、度量值的使用结果是不符合预期的。

这是初学者常常出现的问题,从逻辑来看:

VALUES函数直接用于度量值时,DAX 引擎仅仅检查语法,是没有错误的;但只有在用户使用该度量值的运行时,才会真正计算,得到了含有多个值的结果(也是一个表),且提示用户:表中应该具有单个值。准确讲:只有当表中具有单个值的时候,才能转换成为值,进而显示。

说明 由于微软在界面设计上实在是,这种错误的提示,居然是大叉子,而且错误信息也让人心生恐惧,初学者往往认为自己犯了大错,或触发了软件的 BUG,而实际上,软件只是正确地运行用户的意图。用 VALUES 从表中取值,除非用户脑中想的就是这个。

初学者常常问到:那该怎么办?这个问题其实要问自己:当得到了一个列表后,要进一步做什么?是求和,还是显示出来,然后再用 DAX 函数来操作,确保度量值可以显示正确的结果。

将表作为列表

在某些场景,往往需要对一列元素进行操作,从逻辑结构上,这更符合将其看成是列表,例如:产品ID列表,客户ID列表,订单ID列表等,往往下一步就是对列表进行迭代,在迭代中做一些事情。在经典的 ABC 分析中,需要计算元素列表的积累 KPI 值,则有:

// 假设:

KPI = SUM( 'Order'[Sales] )

// 那么:

KPI.积累 = 
VAR _value = [KPI]                                             // 当前元素的 KPI
VAR _value_total = CALCULATE( [KPI], ALLSELECTED( ) )      // 全局元素的 KPI

// 构建视图层汇总表

VAR _v_table = CALCULATETABLE( 

    ADDCOLUMNS( VALUES( 'Product'[Product] ) , "@Value" , [KPI]),

    ALLSELECTED( )

)

// 视图层计算

RETURN SUMX( _v_table , ( [@Value] >= _value ) * [@Value] ) / _value_total

其中:ADDCOLUMNS( VALUES( 'Product'[Product] ) , "@Value" , [KPI值])就是将产品作为一个列表,再为列表中的每个产品分别计算[KPI]

注意 这里对于[KPI]的计算,会在迭代'Product'[Product]的时候,发生上下文转换。即:正在计算的当前的产品所在行,会转换为对某个产品的筛选作用于整个数据模型进行对[KPI]的计算。可以直观地想象成:在迭代每个产品时,在当前产品,向下捞取对应的订单计算。其中,“向下捞取对应的”这几个字就表现了上下文转换的逻辑动机,那就是:从宏观层面的某个元素,转换为对微观层面的整层筛选,实现了宏观迭代到微观筛选的转换。 因此,上下文转换的本质其实正是:宏观迭代到微观筛选的转换。在数据模型中,很多计算的确是要建立在不同层面之间的,那么这种宏观迭代到微观筛选的转换便是在不同层面取数的核心逻辑。

将表作为集合

下面以留存客户数的计算为例,来体会集合的逻辑结构:

User.流失留存.留存客户数 = 

// 
// --------- A : X period ------------|----- B : y period ------|
//                                                       ↑d1  d2↑
//                                                              ↑
//    

// 设置 x
VAR _month_number_x = 6

// 设置 y
VAR _month_number_y = 1

// 以下请勿修改

VAR _users_period_a = 
    CALCULATETABLE( 
        VALUES( 'Order'[CustomerID] ) , 
        DATESINPERIOD( 
            'Calendar'[Date] , 
            DATEADD( LASTDATE( 'Calendar'[Date] ) , - _month_number_y , MONTH ) ,
            - _month_number_x , 
            MONTH 
        )
    )

VAR _users_period_b =
    CALCULATETABLE( 
        VALUES( 'Order'[CustomerID] ) , 
        DATESINPERIOD( 
            'Calendar'[Date] , 
            LASTDATE( 'Calendar'[Date] ) , 
            - _month_number_y , 
            MONTH 
        )
    )

RETURN COUNTROWS( INTERSECT( _users_period_a , _users_period_b ) )

留存用户数,在 DAX 种,通常指的是,对于指定的区间 [d1,d2],所在区间为 B,那么区间 A 的访问用户,在该 B 区间仍然访问的视为留存,其人数为留存数。

这里,有一个自然的逻辑:A 区间的用户集合,B 区间的用户集合,而 A,B 的交集正是留存的用户集合,其行数则为用户数。

这样,我们就把复杂的问题转换求两个集合,在这个案例中是两个用户 ID 的集合,因为用户 ID 代表了用户本身。

注意 上述内容来自 DAX 模板工具:DAX Pro,可以通过拖拽鼠标,快速创建度量值。您也可以理解学习上述 DAX 中的逻辑后在自己的模型中实验。

总结

在 DAX 中,常见的数据结构有四种:

  • 作为表(Table)的表,常常与其他表通过关系构成更复杂的结构。(后续文章,我们进一步研究)
  • 作为值(Value)的表,分析师必须确保在运行时可以的确只返回一个值。
  • 作为列表(List)的表,通常会对一个列表进行迭代,而在迭代中往往要施加上下文转换来切换宏观和微观进行取数。
  • 作为集合(Set)的表,通常会对两个集合做交,并,补的集合操作以便得到所需元素。

这就指导我们在面对一个问题时,我们要考虑表示该问题的数据结构应该强调的是什么,然后想办法来构建这些的数据结构,再基于数据结构来进行计算。

结合算法结构,我们不难看出:

  • 计算方法,依赖于数据结构
  • 计算方法,构建出数据结构
  • 数据结构,为支撑计算方法
  • 数据结构,由计算方法给出

他们之间有紧密的共生关系,这希望大家可以在实践中加以体会理解。

另外,本文揭示了上下文转换的本质:宏观微观切换。即从相对宏观层面的元素迭代,再切换到微观去筛选,俗称:向下捞取相关数据

启发:DAX 是什么,并不是最重要的,重要的是如何设计简单的规则来完成数据建模中的必备逻辑,且规则最少,那么这些规则的本质应该是什么,这是穿透看似复杂的 DAX 回归简单的思路,故称:Thinking in DAX

本文分享自微信公众号 - PowerBI战友联盟(powerbichina),作者:BI佐罗

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-10-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

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

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

    BI佐罗
  • PowerBI DAX终极指南(圣经)第二版 来了

    今日您已经可以在微软书店或亚马逊正式购买到DAX终极指南第二版英文原版电子版。全称为:《Definitive Guide to DAX, The: Busine...

    BI佐罗
  • PowerBI 动态计算周内日权重指数

    在 PowerBI 中进行这类分析的显著好处之一就是:动态性。在用户选择切片器的不同值后,整个计算重算,并根据用户的选择完成重算,这个选择在实际应用中,可以是门...

    BI佐罗
  • Spark内核分析之Worker原理分析

            接着上篇的Schedule调度内容,本篇我们来看看Driver,Application向Worker发送launch以后到底发生了什么。先来看看...

    z小赵
  • Service Worker 缓存文件处理

    前段时间升级了一波Google Chrome,发现我的JulyNovel站点Ctrl+F5也刷新不了,后来发现是新的Chrome已经支持Service Work...

    从今若
  • spring学习遇到的问题汇总

     1.spring注解路由方面的误解 我一直以为在web.xml中配置拦截*.action后,在注解路由的时候必须要xxxx.action。 刚才发现,访问的时...

    Ryan-Miao
  • [inside hotspot] java方法调用的StubCode

    众所周知jvm有invokestatic,invokedynamic,invokestatic,invokespecial,invokevirtual几条方法调...

    racaljk
  • 连续存储数组的算法(包含数组倒置、冒泡排序……)

    爱学习的孙小白
  • struts2-笔记

    文件下载http://struts.apache.org/download.cgi 第一步导入jar 包 在lib中有jar 包,不能把这些都导入到项目中 在a...

    用户1197315
  • pushViewController自定义动画

    CATransition*transition = [CATransitionanimation];

    freesan44

扫码关注云+社区

领取腾讯云代金券