![c7d8b180cde3374c0e4afbb8cfd650ae.png](https://i-blog.csdnimg.cn/blog_migrate/0141be03d4bf312a5cc92267351506b7.jpeg)
喜乐君s Tableau传道士
前言:今天在Tableau的交流群参与了一个小讨论,回顾一下案例还不错,我想结合阐述一下“选择计算字段的基本方法”。时间仓促,简要阐述,欢迎留言。
![44c5130a9bee6b9ee8ff6ad13b48e946.png](https://i-blog.csdnimg.cn/blog_migrate/5d62ccc8010a3d427e9a0c32f83785c5.png)
问题背景:群里有人问“Tableau有什么办法把1min的数据聚合成15min的数据吗?”这个问题阐述有点模糊,详细说明一下:
- 比如数据是每分钟生成一个数值,每分钟的的数据生成的折线过于密集了,希望更改维度的颗粒度;
- 但是时间默认只有年、月、周、天、小时、分钟等固定颗粒度,小时太粗,分钟太细,希望把每小时再分为四等分,即以15min为间隔聚合度量。
截图如下,都是昵称,我也无暇隐藏了,见谅
![fdf19f144133b241bae464231170a618.png](https://i-blog.csdnimg.cn/blog_migrate/d2c579ec416462e8da5ff6c05e3a4ee4.jpeg)
看一下提问者的截图如下:
![747ccbcecacb17c891d3d80e56c2fbdc.png](https://i-blog.csdnimg.cn/blog_migrate/afa323b27f8bfda89cea13f5b20ee9b5.jpeg)
1、直觉的解决方法
既然是要把分钟标记为0,15,30,45四个部分,直觉的解决方法就是根据分钟的大小做判断(if else)。如下:
![3e58b5ef9d64f92b3e08ff34166d9ede.png](https://i-blog.csdnimg.cn/blog_migrate/61b885ee74f5cc938bd381cafd3cf5e6.jpeg)
虽然说直觉在大部分情况下是对的,但是对于新手而言,大部分情况下似乎是有瑕疵的。 2、我的思考方法正好我路上看到这里,脑海中想了一个图,我们是想把分钟切分为四个部分,相当于数据桶又不能用Tableau的“数据桶”,因为数据桶在Tableau是把连续的度量切分用的,而这里是时间——维度。
![92a6409b6e2d4f0a7fef71aa4bdfc9f2.png](https://i-blog.csdnimg.cn/blog_migrate/4350f452b15b08dfc923d54306455ac5.jpeg)
上面的使用if else嵌套的方法,虽然可行,但显然效率太低,会给服务器沉重的压力——每一行都要做非常多的类型提取、转化、组合和判断。
这个问题之前有人问过我,不过当时是把1小时切分为2份,所以可以直接用上面的判断——只有两份使用的布尔运算,性能是最好的。这里要切分四分就不能用布尔运算,但是逻辑判断性能又太低。有没有更好的办法,比如用一次算数运算解决这个问题?
我突然想起来前几天在学习python写期货数据遇到的一个问题:
我的某个tushare接口一分钟不能提取120次,超过就会中断,为了避免中断,我设置了一个变量i,每循环一次+1,然后做“取整数计算”,当i//120>0时,设置time.sleep(60)休息60秒然后i重置为0继续!
这里能否用类似的思路,取整数运算?
似乎可行,我只需要让每个区间的分钟数值,先变成0,1,2,3,然后再改为0,15,30,45即可。我如今习惯了可视化更好的表述,如下:
![b57dc88189d75d9bb83d648f79d30747.png](https://i-blog.csdnimg.cn/blog_migrate/42d45c50268834d95f70a8fbcc963377.jpeg)
思路既然清晰,我就在群里说明了我的想法,期待大家的验证:“大家好,数据很多,过多的if判断和嵌套会降低性能,不妨尝试用取整数计算。比如2//15=0,再*15,结果就是0/15/30/45四段。”喜乐君
于是大家简化了上面的计算方法,如下:
![110387606a986054266fb356da443ae0.png](https://i-blog.csdnimg.cn/blog_migrate/786c290c3ccf54eea3aa634dc6536d91.jpeg)
看上去还不错!3、对时间的处理
上面的结果虽然不错,但是很明显没有充分利用Tableau中的日期函数,所以我又提出了新的完善建议:
“可以使用datetrunc函数,一次性提取hour之前的日期,然后再加上后面的分钟计算,这样可以进一步提高计算效率。try~”喜乐君
于是又有了下面的更优雅的计算方法:
![5cfbad27a02a42ad1d69be51f6b3a61c.png](https://i-blog.csdnimg.cn/blog_migrate/2fd61bcd5db2e38bcb1d550759ff6770.jpeg)
不过,我发现我没有说清楚我的想法,这不是我想要的。虽然可行,但是这个表达式把日期转化为字符串(str计算),然后又做了相加。对于日期而言,这样的计算不安全,也有些冗长。所以,我进一步说明了我的想法:“外面的datetime函数可以尝试用dateadd来实现计算,datetrunc的日期结果add 日期的分段结果”喜乐君
有必要我说明一下我的意思:datetrunc是裁断,因此hour后面的部分都默认为0;而分钟已经通过“取整运算”返回为0/15/30/45四个结果,二者使用dateadd函数相加,就相当于一个日期加上了分钟部分。所以就有了下面的优雅表达式:
![4f9ee1819a260a4cf06297f17f4e8874.png](https://i-blog.csdnimg.cn/blog_migrate/26ceb6655191369ac289e357cb8ac279.jpeg)
至此,最早性能低下的if嵌套和字符串计算,就替换为了算数计算和日期计算,比较完美的解决了这个问题。
当然,这个表达式性能依然不高,因为每一行还是要做多次运算,才能返回一个结果,也许还有更好的办法,以后可以一起更新。4、选择运算的基本方法
我写这篇文章的重点是,面对此类问题,如何选择计算?Henry说程序员有几个境界:能实现、性能好、代码短、艺术性。四者兼之,自然是上等佳选。从性能的角度应该如何思考呢?
根据个人的经验,提几个角度:A、选择计算方法时,布尔判断优先于算数计算,算数计算优先于(嵌套)逻辑判断。因此,当我只是区分小于30分钟和大于30分钟时,我用一个判断来解决,但是当我要切分四阶段时,我选择用算数计算,只有二者都不能解决时,才考虑复杂逻辑判断。处理逻辑问题,“没有if解决不了的,如果有就用两个”;但是这是迫不得已的选择。即便使用if函数,也优先考虑iif、isnul、ifnull这样的简化函数,再使用完整逻辑函数。B、优先使用“原生性函数”。上面我们尽可能使用Tableau自带的日期函数,而非优先考虑字符串函数,原生函数一般都能更好的简化表达式,提高性能。
C、聚合函数优先于行级别函数。行级别计算往往会导致性能问题,特别是每一行的计算都还要非常多次时。不过,所有的字符串函数、日期函数都是行级别函数,这个地方是没有简化空间的;更多适用于算数计算等地方。
如果还有加上一句话的话,“条条大路通罗马,但总有最近的一条路。”
by 喜乐君 Tableau Partner (销售和技术)
Tableau博客:http://yupengwu.com/tableau