PowerBI 全网首发原生平滑曲线 - 原理及实现

PowerBI战友联盟

共 1090字,需浏览 3分钟

 ·

2021-01-29 12:44

仅以本文致敬本科的数学老师们,终于用上了一招。

大家都知道,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

浏览 77
点赞
评论
收藏
分享

手机扫一扫分享

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

手机扫一扫分享

分享
举报