PowerBI 全网首发原生平滑曲线 - 原理及实现
仅以本文致敬本科的数学老师们,终于用上了一招。
大家都知道,Power BI 的折线图并没有平滑的曲线,这在很多时候非常不方便。
本文来探讨 Power BI 中原生平滑曲线的实现。这要借助一些成熟的数学算法,我们并不打算研究这些数学算法的具体细节,而是仅仅给出 DAX 实现以及对比。
效果
假设先有一个折线如下:
该折线的问题就是看着太生硬,我们希望它可以更加平滑。得到如下效果:
对于生硬的红色折线,我们希望它可以变得平滑,如蓝线所示。
那么问题来了:
如何从红色折线得到蓝色光滑曲线
如何确保蓝色线是连续光滑的
如何确保蓝色线的生成方式是通用的
为此,我们需要研究从独立散点到形成光滑曲线的方法。
插值算法
我们研究了数学中的几种插值算法,所谓插值,顾名思义,就是在已知的的点之间,插入一些新的值,在连线后,形成整条曲线。我们希望这条曲线满足:
连续性
最速接近
高性能
我们考察了数学中的几种算法,如下:
其中,紫色的 Cubic.Pro 和粉色的 Hermite 是重合的。
可以看出:粉色线是同时满足三个条件的最佳算法。
算法实现
由于 Cubic.Pro 和 Hermite 算法默认重合,这里仅仅使用 Cubic.Pro 算法。
对于某个维度 X ,其每个点可由度量值计算出相应的值。
所谓插值,就是将维度 X 的每两个点之间插入新的节点,可以插入 1 ~ 1000 个点都可以。
而不难猜测,插入的点越多,越平滑,但计算量也越大。
例如:
插入 3 个点时:
很明显,在弯折处是不够光滑的。
插入 10 个点时:
已经很光滑,但在细节处,我们放大看:
还是不够光滑。
插入 20 个点时:
此时已经非常光滑。
这样,我们就得到了从点图(折线图)到完美的光滑曲线的最佳实践,为:
采用 Cubic.Pro 插值算法
将原来的两个点中插入 20 个点进行插值计算
满足连续性以及光滑
性能没有问题
DAX实现
第一步,对已有坐标轴进行扩展,如下:
Axis.Ex =
VAR _n = 20 // 用于区间内分割的点数
RETURN
FILTER(
GENERATEALL(
VALUES( 'Axis.X'[X] ) ,
SELECTCOLUMNS( GENERATESERIES( 0 , _n - 1 ) , "X'" , [X] + [Value] / _n )
),
[X'] <= MAX( 'Axis.X'[X] ) // 去除超过原区间大小的点
)
第二步,实现 Cubic.Pro 插值算法,如下:
Axis.Y.Smooth.Cubic.Pro =
VAR _y_min = CALCULATE( [Axis.Y.Sample] , TREATAS( { MIN( 'Axis.X'[X] ) } , 'Axis.X'[X] ) )
VAR _y_max = CALCULATE( [Axis.Y.Sample] , TREATAS( { MAX( 'Axis.X'[X] ) } , 'Axis.X'[X] ) )
VAR _y0 = COALESCE( CALCULATE( [Axis.Y.Sample] , TREATAS( { VALUES( 'Axis.Ex'[X] ) - 1 } , 'Axis.X'[X] ) ) , _y_min )
VAR _y1 = CALCULATE( [Axis.Y.Sample] , TREATAS( { VALUES( 'Axis.Ex'[X] ) + 0 } , 'Axis.X'[X] ) )
VAR _y2 = CALCULATE( [Axis.Y.Sample] , TREATAS( { VALUES( 'Axis.Ex'[X] ) + 1 } , 'Axis.X'[X] ) )
VAR _y3 = COALESCE( CALCULATE( [Axis.Y.Sample] , TREATAS( { VALUES( 'Axis.Ex'[X] ) + 2 } , 'Axis.X'[X] ) ) , _y_max )
VAR _dx = SELECTEDVALUE( 'Axis.Ex'[X'] ) - SELECTEDVALUE( 'Axis.Ex'[X] )
RETURN
VAR _u1 = _dx
VAR _u2 = _dx * _dx
VAR _a0 = -0.5 * _y0 + 1.5 * _y1 - 1.5 * _y2 + 0.5 * _y3
VAR _a1 = _y0 - 2.5 * _y1 + 2 * _y2 - 0.5 * _y3
VAR _a2 = -0.5 * _y0 + 0.5 * _y2
VAR _a3 = _y1
RETURN _a0 * _u1 * _u2 + _a1 * _u2 + _a2 * _u1 + _a3
其中,
'Axis.X'[X] 为原有维度坐标轴
[Axis.Y.Sample] 为默认度量值
不要问这个算法的具体细节是什么意思,它需要应用数学专业大二水准,这就是数学的用处。只需要记住这么用就行。
来对比下不同版本的 DAX 实现效果,如下:
我们选择了 Cubic.Pro 算法以及 DAX 实现,并完美的解决了利用 Power BI 原生折线生成光滑曲线的问题。
总结
虽然我们完美地实现了 Power BI 的光滑曲线,但:
有人会说,他 3 秒就可以在 Excel 里实现。
那么,他很厉害,他会用 Excel 点按钮。
的确,Power BI 是不完美的,我们仅仅是在 Power BI 还不够完美的过程中在用自己的方式来弥补 Power BI 的缺陷,这个弥补的过程看似非常愚蠢,非常无意义,但反而体现了我们在选择一件工具最核心能力后的妥协和折衷。
如果这个世界存在完美,并让人可以 3 秒爽,那么,是不是有点快得没有意思了?
对于欠缺举一反三能力的伙伴会问以下两个问题:
我的坐标轴不是 1,2,3 啊,而是产品,或日期,或用户,如何做成平滑曲线呢?
如果元素非常多,例如,365 个日期,插值后会形成 3650 个点,运算量提升 20 倍,会不会有问题呢?
这个问题留作思考题。我们会在下篇文章来分享这两个问题的优化方法。
在 BI佐罗 出品的《BI真经》的《PBI高级》中发布的通用视图层算法将作为主要优化手段。极力推荐要学习 Power BI 的伙伴赶快订购这一顶级教程,超越所有没学该课程的 Power BI 用户(本文就是又一例证)。
在订阅了BI佐罗讲授的《BI真经》之《BI进行时》课程区,除了可以下载本文案例,还可以观看视频讲解。
让数据真正成为你的力量
Create value through simple and easy with fun by PowerBI
Excel BI | DAX Pro | DAX 权威指南 | 线下VIP学习
扫码与PBI精英一起学习,验证码:data2021