[知识体系] 理解 RANKX

  [复制链接]
查看90455 | 回复108 | 2021-2-21 18:53:56 | 显示全部楼层 |阅读模式
RANKX 是计算排名的专用函数,它可以根据你指定的计算逻辑,返回当前成员在整个列表中的排名,RANKX 是非常灵活且强大的迭代函数,它的计值过程需要你仔细阅读和理解。如果你只需要根据模型已有的值计算排名,可以考虑使用它的简化版 RANK.EQ。
RANKX
  1. RANKX(<table>, <expression>, [ <value> ], [ <order> ], [ <ties> ])
复制代码

RANKX 为<table>的每一行计值表达式<expression>并得到一个值列表,<value>在当前筛选上下文中计值,将得到的结果与列表中的值进行比较,根据排名规则<order>和<ties>的设置,返回最终排名。

参数属性描述
Table表或返回表的表达式
Expression沿着 Table 每行计值的表达式
Value可选需要返回排名的 DAX 表达式,返回标量值。当<value>省略时,用<expression>代替
Order可选排名依据。0 或 False 代表降序;1 或 True 代表升序,默认使用降序
Ties可选处理相同排名时的依据,skip 代表稀疏排名,下一名的排序等于之前所有排序的数量+1;dense 代表稠密排名,只累加排序,不考虑数量。默认使用 skip

函数解析

<value>参数在根据<table>每行计值的<expression>返回的值中进行排序。如果省略<value>,则使用<expression>在调用 RANKX计值上下文中计算的结果用作排序依据。


<expression>和<value>在不同的上下文中计值,<expression>参数在<table>的行上下文中计值,同时考虑外部筛选上下文。<value>参数在调用 RANKX 的上下文环境中计值,可能包含行上下文(例如计算列)也可能只有筛选上下文(例如度量值)。可以使用 CALCULATE 将行上下文转换为筛选上下文(但请注意,第三参数可能不存在行上下文)。不要忘记,对度量值的引用总是隐式地执行上下文转换


排序参数<order>的值为 0 或 False(默认)时返回降序结果,为 1 或 True 时返回升序结果。字符串参数<ties>可以使用 DENSE 或 SKIP 来处理相同值的排名问题,DENSE(稠密排名)在平局后返回下一个名次,SKIP(稀疏排名)返回跳过所有相同值后的名次。例如,有四个值的排名都是 5,那么下一个值的排名可以返回 9(稀疏排名),也可以返回 6(稠密排名)。


如果 Value 为负数,排名可能会发生明显的变化,原因是空值在计算排名时自动转换为 0,原因是数据类型和运算符一文中介绍过的隐式转换。

示例

例如,你可以定义下面的度量值对产品品牌进行排序:
  1. [Rank by Brand A] := RANKX ( ALL ( Product[Brand] ), [Sales Amount] )
复制代码

结果是每个产品品牌的销售额排名,但我们发现包含了所有产品的总计行也返回了排名。你可以通过使用 HASONEVALUE 测试是否只选择了一个品牌来避免这种情况,这两个度量值的结果在图 8-1 中可见。
  1. [Rank by Brand B] :=
  2. IF (
  3.     HASONEVALUE ( Product[Brand] ),
  4.     RANKX ( ALL ( Product[Brand] ), [Sales Amount] )
  5. )
复制代码

7084211936381.jpeg

图 8-1 Rank by Brand B 隐藏了总计行的排名


这里重要的是要考虑将哪个表参数<table>传递给 RANKX 以获得所需的结果。在上面的公式中,需要使用 ALL (Product[Brand]),因为你希望获得每个品牌的排名。如果将颜色放在行上,而不是品牌,则会得到如图 8-2 所示的奇怪结果。


7084211936382.jpeg

图 8-2 度量值根据产品型号对销售额进行排名,但报告根据产品颜色对数据进行了划分


Rank by Brand A 总是返回 1,因为对于每种颜色,可能有一个或多个品牌,RANKX 计值第二参数[Sales Amount]的环境是 ALL ( Product[Brand] )的每一行和当前外部筛选上下文,结果受到品牌和颜色的共同约束,第三参数默认仍使用[Sales Amount],这一次[Sales Amount]在调用 RANKX 的外部上下文中计值,得到的是当前颜色的总销售额。这个值更大,总是大于或等于当前颜色下各个品牌的销售额(也就是第二参数的计值结果)。为什么 Rank by Brand B 的排名只有几行是 1 呢?原因是某个颜色的产品只属于一个品牌时(如 Azure 和 Transparent colors),才满足 HASONEVALUE 条件,否则该颜色的品牌不止一个,IF 条件判断使得结果为空。

只统计可见排名

按 Rank by Brand A 计算的排名是所有品牌的绝对排名。如果你在筛选器中只保留几个品牌,排名将总是考虑那些不可见的。例如,在图 8-3 中,你可以看到,如果你取消选择前三名的品牌,那么品牌排名将从第四名开始。


7084211936383.jpeg

图 8-3 第一个品牌的排名是第四名,因为这里的排名始终按所有品牌计算


如果你只想统计可见品牌的排名,需要使用 ALLSELECTED 代替 ALL,正如你在下面的度量值中看到的那样,它产生了图 8-4 所示的结果。


7084211936384.jpeg

图 8-4 第一个品牌排名第一,因为这一次排名只考虑可见的品牌
我们在 CALCULATE 调节器章节详细的介绍了 ALLSELECTED 函数,在这里,ALLSELECTED 移除了数据透视表的行和列成员引入的筛选上下文,保留了数据透视表的切片器和筛选器定义的上下文。
  1. [Rank by Brand C] :=
  2. IF (
  3.     HASONEVALUE ( Product[Brand] ),
  4.     RANKX ( ALLSELECTED ( Product[Brand] ), [Sales Amount] )
  5. )
复制代码
RANKX 中的陷阱

在度量值中使用 RANKX 可能会犯以下这些常见的错误。第一个陷阱是 RANKX 的第一参数通常对列或表使用 ALL 函数。当你使用表时,你可能会忘记使用 ALL,这种情况在指定单个列时不会发生,因为参数必须是表形式,如果简单的指定一个列名作为第一参数,你会收到错误提示。

忘记使用 ALL

例如,考虑以下按产品类别计算排名的度量值。错误写法将产品类别表指定为 RANKX 的第一参数,而正确的写法是使用 ALL 函数。这两个度量值的结果在图 8-5 中都可以看到。
  1. [Wrong Rank by Category] :=
  2. IF (
  3.     HASONEVALUE ( 'Product Category'[ProductCategoryKey] ),
  4.     RANKX ( 'Product Category', [Sales Amount] )
  5. )
复制代码
  1. [Rank by Category] :=
  2. IF (
  3.     HASONEVALUE ( 'Product Category'[ProductCategoryKey] ),
  4.     RANKX ( ALL ( 'Product Category' ), [Sales Amount] )
  5. )
复制代码

7084211936385.png

错误写法的结果始终为 1

忘记使用 CALCULATE



另一个常见的陷阱是使用 DAX 聚合行级数据时,没有将表达式嵌入 CALCULATE 函数里。在前面的例子中,我们一直使用销售额度量值作为计算排名的表达式。如果将度量值换成 SUM 这样的聚合函数,需要意识到表达式将在 RANKX 第一参数的每行计值。在这个迭代过程中,行上下文不会自动转换为筛选上下文,除非通过 CALCULATE 执行上下文转换,这是调用已有度量值时执行的隐式操作。因此,对于每一行,筛选上下文(即计算 RANKX 的单元格中现有的筛选器)总是相同的,以这种方式计算,所有类别的排名都是 1。正确的公式只需要在表达式外层调用 CALCULATE 函数,该函数为 RANKX 迭代的表的每一行执行上下文转换。你可以在图 8-6 中看到错误和正确公式的结果。
  1. [Wrong Rank by Quantity] :=
  2. IF (
  3.     HASONEVALUE ( 'Product Category'[ProductCategoryKey] ),
  4.     RANKX ( ALL ( 'Product Category' ), SUM ( Sales[Quantity] ) )
  5. )
复制代码
  1. [Rank by Quantity] :=
  2. IF (
  3.     HASONEVALUE ( 'Product Category'[ProductCategoryKey] ),
  4.     RANKX ( ALL ( 'Product Category' ), CALCULATE ( SUM ( Sales[Quantity] ) ) )
  5. )
复制代码

7084211936386.jpeg

图 8-6 错误写法每行总是返回 1




使用 RANKX 的第三参数

在前面的示例中,你已经看到只用两个参数的 RANKX。默认情况下,第三参数使用第二参数,无论你是按 DAX 度量值还是聚合表达式进行排名,通常这都是正确的选择。但是,如果要根据表本身某一列的值对表执行排序,则可能需要在第三参数中指定不同的表达式。

第二参数定义的表达式,在 RANKX 第一参数传递的表的每一行计值。这个表达式总是在行上下文中执行,因此它可以直接访问同一表的任何列的值。但是,如果将 RANKX 用作度量值,则第三参数没有行上下文,如你目前看到的示例所示。如果 RANKX 函数是计算列表达式的一部分,则第三参数将存在行上下文。

例如,下面的度量值会提示语法错误:


“无法确定表 Product 中列 Unit Price 的某一个值。当度量值公式引用了包含许多值的列,且未指定用于获取单一结果的 min、max、count 或 sum 等聚合时,可能会发生此情况”
  1. [Wrong Rank by Price] :=
  2. IF (
  3.     HASONEVALUE ( Product ),
  4.     RANKX ( ALLSELECTED ( Product ), Product[Unit Price] )
  5. )
复制代码

下面这个度量值与它等价,因为第三参数默认情况下使用第二参数的表达式:
  1. [Wrong Rank by Price] :=
  2. IF (
  3.     HASONEVALUE ( Product ),
  4.     RANKX (
  5.         ALLSELECTED ( Product ),
  6.         Product[Unit Price],
  7.         Product[Unit Price]
  8.     )
  9. )
复制代码

计算第三参数需要一个行上下文,当度量值在报表(前面看到的透视表)中计算时,行上下文不存在。因此,为了检索“当前”产品的价格,可以使用 VALUES,在选择了多个产品的情况下,HASONEVALUE 通过条件判断不会计算 RANKX。下面的度量值实现了上述过程,如图 8-7。
  1. [Rank by Price] :=
  2. IF (
  3.     HASONEVALUE ( Product ),
  4.     RANKX (
  5.         ALLSELECTED ( Product ),
  6.         Product[Unit Price],
  7.         VALUES ( Product[Unit Price] )
  8.     )
  9. )
复制代码


7084211936387.jpeg

图 8-7 该报告仅显示切片器选择的品牌的产品。Rank by Price 使用 VALUES 函数检索报告当前行(该行只有筛选上下文, 没有行上下文)的价格。该报告的另一个度量值计算的是平均价格,对应于产品表每行的产品单价 (该度量值使用聚合函数)。




理解 RANKX 计值流

在理解上下文转换一文的案例二中,我使用了一个 RANKX 计值的示例,通过这个案例可以加深你对 RANKX 计值流的理解。
虽然 RANKX 的计值过程比较繁琐,但这是个经过优化的函数,实际执行时的效率非常高
7084211936388.rar (5.54 MB, 下载次数: 0)
回复

使用道具 举报

阿熙 | 2021-4-24 13:57:06 来自手机 | 显示全部楼层
沙发~支持云发教育
回复

使用道具 举报

9189188 | 2021-6-11 12:12:52 来自手机 | 显示全部楼层
加油站加油
回复

使用道具 举报

hanny | 2021-6-17 19:00:52 来自手机 | 显示全部楼层
打酱油的人拉,回复下赚取积分
回复

使用道具 举报

weiye | 2021-9-3 12:58:00 | 显示全部楼层
LZ敢整点更有创意的不?兄弟们等着围观捏~
回复

使用道具 举报

hsy001 | 2021-9-3 17:51:37 | 显示全部楼层
我也是坐沙发的
回复

使用道具 举报

花朵儿 | 2021-10-3 18:37:07 | 显示全部楼层
努力~~各位。。。
回复

使用道具 举报

lubaby726 | 2021-10-19 16:08:22 | 显示全部楼层
专业抢沙发的!哈哈
回复

使用道具 举报

大个仔 | 2021-11-2 15:15:14 | 显示全部楼层
为毛老子总也抢不到沙发?!!
回复

使用道具 举报

铁忠 | 2021-11-2 18:40:26 | 显示全部楼层
前排支持下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则