如何让帕累托分析积累占比的曲线是光滑的

共 2606字,需浏览 6分钟

 ·

2021-12-10 13:24

老板说希望看到帕累托分析的曲线是光滑的,虽然有的元素的确相等。

问题

在做帕累托分析的时候,默认的算法是没有问题的,例如:

但巧合的是这里的柱子都是不一样高的,那么如果遇到一样高的柱子就会在理论上出现另一种效果,如下:

这个效果在理论上的确是正确的,但问题是老板是非常希望看到平滑的曲线的。怎么办?

数据模型

为了方便,这里用 DAX 构建一个单表数据模型,如下:

Data = 
VAR vNumber = 20
RETURN
GENERATEALL(
SELECTCOLUMNS( GENERATESERIES( 1 , vNumber ) , "Index" , [Value] ) ,
SELECTCOLUMNS(
{ ( "P" & [Index] , RANDBETWEEN( 1 , 10 ) ) } ,
"Item" , [Value1] , "Value" , [Value2]
)
)

其中,修改 vNumber 可以修改生成元素的个数。效果如下:

这里有一个叫 Index 的列,但在实际中的模型可能更加复杂,且不带 Index 列,因此,文章的后续讨论是不带有 Index 列的,以确保通用性。

理想效果

老板希望看到的理想效果是平滑曲线,如下:

虽然图中的柱子有很多一样高度的,但应该仍然呈现积累的效果。

注意:

  • 柱子一样高时,排名先后可以随机。

另外有一个细节,就是图表的第一棵柱子的开始位置,如下:

左图的开始位置有一截高度,而右图是从最底部开始的。

老板说,他想要右图的效果,于是必须轻松秒杀。

积累占比的默认公式

积累占比的默认公式有不少写法,但这里给出最优写法(没有之一),如下:

积累% = 

VAR vTable =

CALCULATETABLE(

ADDCOLUMNS( VALUES( Data[Item] ) , "@Value" , CALCULATE( SUM( Data[Value] ) ) )

,

ALLSELECTED( )

)

VAR vValueCurrent = SUM( Data[Value] )

RETURN SUMX( FILTER( vTable , [@Value] >= vValueCurrent ) , [@Value] ) / SUMX( vTable , [@Value] )

由于 BI 佐罗 已经发布了【视图层计算通用设计模式】,因此,我们所有 DAX 公式都会据此重构,其中思想不再重复。

以上写法没有问题,但对于伪问题,如下:

没有得到益处。

积累占比的优化

将积累占比的公式优化一下,轻松秒杀这个问题,如下:

积累% 光滑 = 

VAR vTable =

CALCULATETABLE(

ADDCOLUMNS(
ADDCOLUMNS( VALUES( Data[Item] ) ,
"@Index" , RANKX( VALUES( Data[Item] ) , [Item] ) ,
"@Value" , CALCULATE( SUM( Data[Value] ) )
) ,
"@ValueIndex" , INT( [@Value] ) + ( COUNTROWS( VALUES( Data[Item] ) ) * 10 )
)

,

ALLSELECTED( )

)

VAR vValueIndex = SUMX( FILTER( vTable , [Item] = SELECTEDVALUE( Data[Item] ) ) , [@ValueIndex] )

RETURN SUMX( FILTER( vTable , [@ValueIndex] >= vValueIndex ) , [@Value] ) / SUMX( vTable , [@Value] )

下面来描述一下这个思想:

由于比对大小时会遇到大小相等的元素,所以需要进行一个额外对比,但额外进行的对比又必须不能影响主对比结果,所以我们构建一个用来对比的索引,将内容:

EVALUATE
ADDCOLUMNS(
ADDCOLUMNS( VALUES( Data[Item] ) , "@Index" , RANKX( VALUES( Data[Item] ) , [Item] ) , "@Value" , CALCULATE( SUM( Data[Value] ) ) ) ,
"@ValueIndex" , INT( [@Value] ) + [@Index] / 100
)

放入 DAX Studio 中,如下:

这里构建了一个用来对比的表,而且确保不会出现重复的值,其方法在于:

  • INT 对原值取整,作为对比索引值的整数部分。

  • Item 名称的排序除以一个大的基数,作为对比索引的小数部分。

其中的巧妙思想在于用排名的方法得到小数部分,如下:

"@Index" , RANKX( VALUES( Data[Item] ) , [Item] )

且如何设定一个合理的分母,如下:

( COUNTROWS( VALUES( Data[Item] ) ) * 10 )

在最终计算时便可以利用上述信息进行比对,如下:

SUMX( FILTER( vTable , [@ValueIndex] >= vValueIndex ) , [@Value] ) / SUMX( vTable , [@Value] )

这里充分体现了 SUMX 可以声东击西的特质,用 [@ValueIndex] 与 vValueIndex 比对大小,但求和的却是 [@Value]。

最终效果

通过上述优化,轻松秒杀了帕累托分析中无法平滑显示的问题,且轻松有效的显示。如下:

这样我们就得到了右边的效果。

且本文给出了构建平滑帕累托积累 % 的通用算法模板,可以直接套用。


扫码入社群,看视频讲解


浏览 101
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报