Power BI Power Query 排名1-非连续排名和连续排名

时间:2024-03-08 21:07:46

如下图所示,我有100个分数的数值,现需要对其进行排名处理。很久之前我有写过一篇有关Access里排名处理方式的博文Access SQL实现连续及不连续Rank排名,这一次我将其转换为使用Power Query来进行类似的排名操作。

image

 

非连续排名

首先我们来实现非连续排名,非连续排名最终排出来的名次的数字是非连续的,假如第1名1人,第2名有2人,那么名次为3的人事不存在的,而只有从第4名开始。

这种模式的计算逻辑是:对于某一个得分而言,其名次为大于当前分数的所有人的个数+1

 

1、首先我们将Excel表数据导入到Power Query管理器中,选择表数据区域,然后依次点击“数据/从表格”,弹出的对话框直接点确认

image image

image

 

2、接下来依次点击“添加列/自定义列”,我们首先借助于这个自定义列来为每一行获取一个子表,该子表包含了所有比当前行的分值大的所有行。

在自定义列窗体中的配置如下图所示,其中的公式为:

=Table.SelectRows(更改的类型,(r)=>r[分数]>[分数])

image

说明下公式:

1、使用Table.SelectRows函数来挑选出表中的行

2、Table.SelectRows函数的第1个参数:指明从哪个表里挑选数据,这个表是上一个步骤得到的结果,上一个步骤就是右侧查询设置步骤清单中的“更改的类型”

3、Table.SelectRows函数的第2个参数:该参数是一个lambuda函数表达式,该函数表达式将会被逐行应用到Table.SelectRows函数的第1个参数表的每一行之上。

(r) :这部分是lambuda函数的参数部分,其中的r是参数的名称,你可以使用任何字母,它表示的就是遍历参数表的行,你需要区分它与整个公式计算所在的当前行之间的差异。

        拿计算列的第1行为例,当前自定义列的公式所在的行是第1行,而这个lambuda函数将会遍历表的所有行,每次都取一行的值与当前行(第1行)的分数比较,我这里的表有100行,所比较操作就有100次;

        后面计算列的所有行都是相同处理,所以需要运算的次数为100*100=10000次。

=>:箭头符号,用来分隔lambuda函数的参数部分和逻辑代码部分

r[分数]>[分数]:lambuda函数的逻辑代码部分,该部分需要返回一个逻辑值,以便于Table.SelectRows函数判定是否需要挑选(筛选)出表中的行,返回结果为真时,表示挑选出来,否则过滤掉改行

       其中的r[分数]表示的取当前遍历行中的分数列的值,而大于符号后面的[分数]表示的是自定义列公式所处行中的分数列的值

 

关于为何使用的是r[分数]来获取分数列的值,而不是使用r{[分数]}来访问这个值,是因为表(Table)中的行其数据类型是记录(Record),关于列表、表和记录数据类型及其访问子元素的方法我在Power BI Power Query 认识M语言中的结构性数据的博文里有说明,如果你不清楚,请先阅读下这篇文章。

 

下图是添加自定义列“子表”之后的运行结果,我们可以点击第1行,底部就会加载该子表的数据

image

注意:不要点在哪个Table文字上,而是点在右侧空白区域里,点在文字上,PQ将会认为你是要新加一个步骤查看该子表的数据了

 

接下来就需要将子表中的行统计一下,计算出总行数,并将该数字+1即可得出排名了,下面我们直接在前面的公式上修改

1、在右侧找到最后的操作步骤,右侧有一个齿轮图表,点击一下它,就可以重新弹出“自定义列”对话框

image

2、输入如下所示的公式,点击确定按钮后,会看到如下面右侧图片所示的排名结果。

=Table.RowCount(Table.SelectRows(更改的类型,(r)=>r[分数]>[分数]))+1

image image 

3、依次点击“主页/关闭并上载至”,依次选择“表/新建工作表”,点击加载按钮后,将我们的排名查询加载到Excel中,后续原始数据变动时,我们只需要刷新一下即可得到新的排名

image image

 

连续排名

连续排名最终排序得到排名的名次是连续的,假如第1名1人,第2名有2人,那么接下来的名次并非从第4名开始,而是还是第3名。

连续排名的逻辑:对于序列之中的某个分数而言,其名次是序列中大于该分数值的所有非重复分值的个数+1 

之前的示例数据我是通过随机数方式生成的,制作本示例时,数据发生了变化,示例数据如下所示:

image

 

先说明下思路:

借助于自定义列来为每一行获取一个子表,该子表包含了所有比当前行的分值大的所有分值的非重复记录。

1、首先从表中挑选出比当前行分数大的所有记录行(与非连续排名一样)

2、然后从上面第1步得到的表中再挑选出“分数”列

3、再在上面第2步得到的“分数”列中取一个非重复值

 

与前面进行非连续排名的操作类似,前面的导入数据操作步骤是一样的,所以这里我跳过这些步骤。直接演示上面所说的1-3步的实现

1、新建自定义列,录入公式如下:(与非连续排名的公式一样)

=Table.SelectRows(更改的类型,(r)=>r[分数]>[分数])

image

2、将公式修改为如下结果,公式输入完毕后,注意图中观察左下角子表的表现形式

=Table.SelectColumns(Table.SelectRows(更改的类型,(r)=>r[分数]>[分数]),"分数")

image

说明下公式:

1、首先我使用Table.SelectRows函数来过滤表中的行,得到分数大于当前分数的记录行,注意这些筛选后的记录行构成了一个新的表,它可以作为下一个Table.SelectColumns函数的参数

2、然后再使用了Table.SelectColumns函数来从上一步过滤后的表中挑选出“分数”列

3、Table.SelectColumns函数第1个参数:数据类型为表,函数将从该表中挑选出列来

4、Table.SelectColumns函数第2个参数:当是字符串时,从表中提取出单列,当是列表是,从表中提取出多了,例如{“索引”,”分数”},表示从表中提取2列

 

3、接下来继续改造公式,将公式修改为如下形式,其含义是在分数列上求一个非重复值,注意观察示意图左下角的分数列结果

=Table.Distinct(Table.SelectColumns(Table.SelectRows(更改的类型,(r)=>r[分数]>[分数]),"分数"))

image

4、最后再在最外面套一个求行数的函数,并将结果+1即可得到连续排名的名次值

=Table.RowCount(Table.Distinct(Table.SelectColumns(Table.SelectRows(更改的类型,(r)=>r[分数]>[分数]),"分数")))+1

image