首页 »
资源 » 此处
任何一种商业贸易的大部分业务运作都可以通过时序准确呈现: 历史销售额 、历史采购订单、历史价格等等。鉴于时序处理对于公司至关重要,Envision 针对此类应用方案提供广泛的原生支持。具体而言,Envision 支持根据每天、每周和每月聚合数据。此外还支持更复杂的时序分析,例如滞后数据或计算不断变化的平均值。本页将对这些功能加以说明。
示例
我们将再一次使用
样本数据集来说明 Envision 的功能。考虑到本节介绍的是 Envision 较为高级的用法,因此建议您先阅读
执行计算和
聚合数据,然后再继续浏览本节。
read "/sample/Lokad_Items.tsv"
read "/sample/Lokad_Orders.tsv" as O
read "/sample/Lokad_PurchaseOrders.tsv" as PO
show label "Time-series calculations" a1f1 tomato
end := max(date)
lastMon := monday(end)
Week.sold := sum(O.NetAmount)
when date >= end - 52 * 7
show linechart "Weekly sales" a2f4 tomato unit:"$" with
Week.sold as "This year"
Week.sold[-52] as "Last year"
Week.ma := sum(O.NetAmount / 4) over [-3 .. 0]
when date >= end - 52 * 7
show linechart "Weekly sales with 4 weeks moving average" a5f7 tomato unit:"$" with
Week.ma as "This year"
Week.ma[-52] as "Last year"
Day.cashFlow := sum(O.NetAmount) - sum(PO.NetAmount)
Day.balance := avg(Day.cashFlow) over [-13 .. 0]
when date >= lastMon - 6 * 7 & date < lastMon
show linechart "Cash flow over the last 6 weeks" a8f10 tomato unit:"$" with
Day.balance as "Balance"
PO.Price = PO.NetAmount / PO.Quantity
O.PurchasePrice = latest(PO.Price)
O.Cost = O.PurchasePrice * O.Quantity
O.Profit = O.NetAmount - O.Cost
Week.profitblty := sum(O.Profit) / sum(O.Cost) or 1
when date >= lastMon - 13 * 7 & date < lastMon
show linechart "Profitability over the last 13 weeks" a11f13 tomato unit:"%" with
Week.profitblty
使用样本数据集运行这段脚本后,将生成以下仪表板。
虚拟日历表
由于每日、每周和每月聚合非常普遍,因此 Envision 被设计为针对这些周期日历模式提供原生支持。具体地说,Envision 提供三个虚拟表,分别为
Day
、
Week
和
Month
。之所以称这些表为“虚拟”表,是因为它们不具备相应的表格文件。换言之,这些表仅在执行脚本期间存在。上述脚本就是利用这些虚拟表来显示线形图的。我们来看一下重新复制到下面的相关代码行。
Week.sold := sum(O.NetAmount)
end := max(date)
when date >= end - 52 * 7
show linechart "Weekly sales" a2f4 tomato unit:"$" with
Week.sold as "This year"
Week.sold[-52] as "Last year"
在第 1 行,
O
表的内容求和为
Week
表。由于这里使用了标量赋值
:=
,因此每周计算一个单一值。第 3 行定义了一个过滤器用于排除时间超过 52 周的数据。最后在第 4 - 6 行,定义了一个具有两个时序的线形图。第二个时序
Week.sold[-52]
附带有一个滞后算子,下一节将对此进行说明。
这段脚本可以很容易地修改为按每天或每月聚合。例如,可以在脚本末尾添加以下代码行:
Day.sold := sum(O.NetAmount)
show linechart "Daily sales" a14f16 tomato unit:"$" with
Day.sold
Month.sold := sum(O.NetAmount)
show linechart "Monthly sales" a17f19 tomato unit:"$" with
Month.sold
该代码块显示另外两个线形图,这两个线形图分别按每天和每月进行时序聚合。
变量
Day.sold
可解读为
Day
表中
sold
列的内容,也可解读为 “1天”的周期内等距的时序,这与包含
Date
列的常规 Envision 表(例如
O
表,可解读为
非等距时序)相反。
显示滞后的时序
在时序分析中,“滞后” 是指涉及按时序元素移动时间的操作。时序滞后的基本用途之一便是比较两个不同的时间周期。Envision 支持专门用于处理这种情形的
滞后算子。
Week.sold := sum(O.NetAmount)
when date >= end - 52 * 7
show linechart "Weekly sales" a2f4 tomato unit:"$" with
Week.sold as "This year"
Week.sold[-52] as "Last year"
第 4、5 行有两个时序。第一个时序
Week.sold
是按每周聚合的原始销售额。第二个时序包含一个额外后缀
[-52]
。这个后缀就是滞后算子。它表示过去 52 周的数据将向前移动并最终显示在线形图中。在将滞后算子应用于
Week
表时,滞后参数是一个以每周为单位的整数。同样,
Day
和
Month
表的适用单位分别为“天”和“月”。
滞后算子得益于过滤算子
when
的智能协作行为。实际上,如果没有这种协作行为,过滤器
when
将排除所有 52 周之前的数据,因此滞后 52 周的时序将导致零移动。然而,从之前仪表板的屏幕截图可以看出,滞后算子正确前移了具有一年之久的数据,而不只是移动零值。这种行为是通过
when
过滤器和滞后算子之间的内置协作来实现的。
如果将鼠标放在仪表板中的线形图上,您将发现会显示日期和值。具体地说,运行本节开头的脚本后,与名称为“今年”的时序所报告的日期相比,针对名称为“去年”的时序所报告的日期不到一年。值得一提的是,滞后算子实际上并不保留时序的初始日期。相反,Envision 只是使用一种约定来实现这一点:只有在线形图的声明中定义了滞后算子时,才仍会保留初始日期。
我们对这段脚本加以修改,从而在线形图外部应用滞后算子。通过引入变量
Week.lastYear
可以实现这一点。
Week.sold := sum(O.NetAmount)
Week.lastYear := Week.sold[-52]
when date >= end - 52 * 7
show linechart "Weekly sales" a2f4 tomato unit:"$" with
Week.sold as "This year"
Week.lastYear as "Last year"//date display issue
如果运行这段修改后的脚本,并将鼠标放在时序点上,会发现这两个时序都报告相同的日期。在本例中,对于所要显示的日期不存在模糊不清的语义。例如,
Week.lastYear
时序实际上可以解读为逐年预测;因此针对本例中我们所考察的这两个时序生成了相同的日期。总而言之,如果要保留线形图中的初始日期以便并排比较滞后的时序,则应在
show
语句中定义滞后算子。
聚合时间窗口内的数据
在之前的说明中,我们了解了
如何通过 Envision聚合数据。对于时序,还有另外一种类型的聚合非常合乎需要:对时间窗口聚合。本节开头的脚本说明了如何计算 4 周内关于销售额的
不断变化的平均值。为了清楚起见,我们将脚本的相关代码行重新复制到下面。
Week.ma := sum(O.NetAmount / 4) over [-3 .. 0]
when date >= end - 52 * 7
show linechart "Weekly sales with 4 weeks moving average" a5f7 tomato unit:"$" with
Week.ma as "This year"
Week.ma[-52] as "Last year"
第 1 行使用了
sum()
聚合器执行聚合,该聚合附带一个语句,它以末尾的
over
关键字开始。在第 2 行,专门针对过去 52 周的数据进行了过滤。最后来看第 3 - 5 行,线形图中显示有两个时序。这两个时序很“平滑”,因为二者为 4 周的平均值。
算子
over
用于定义适用的时间窗口,其编写格式应为
[a .. b]
,其中
a
和
b
为整数,且
a
小于或等于
b
。
a
和
b
所使用的单位取决于赋值左边的表达式。在本例中,赋值左边为
Week
表,因此
-3
和
0
按周表示。
注意:索引为 -3 的周与索引为 0 的周之间有 4 周,而不是 3 周。因此,周数索引为 -3、-2、-1 和 0。
over
选项可用于所有聚合器。在使用此选项时,赋值左边通常为虚拟日历表,例如
Day
、
Week
和
Month
。但这并非硬性要求,任何按
Date
索引的表都可以使用。此外根据定义,在使用日历表的情况下,通过使用
over [0 .. 0]
选项可以获得与默认聚合相同的结果:
Week.sold := sum(O.NetAmount)
// same result!
Week.same := sum(O.NetAmount) over [0 .. 0]
更为复杂的时序聚合
Envision 的语法为执行更精细的时序计算提供了可能。例如,可以计算时序,然后根据这些初始时序执行进一步计算。本页顶部脚本中的第三个代码块说明了这一点。脚本的相关代码行复制在下面。
Day.cashFlow := sum(O.NetAmount) - sum(PO.NetAmount)
Day.balance := avg(Day.cashFlow) over [-13 .. 0]
when date >= monday(end) - 42 & date < monday(end)
show linechart "Cash flow over the last 6 weeks" a8f10 tomato unit:"$" with
Day.balance as "Balance"
在第 1 行,时序
Day.cashFlow
定义为总销售额和总采购额之差。在第 2 行,时序
Day.balance
被作为
Day.cashFlow
在 14 天内不断变化的平均值进行计算。在第 3 行,定义了一个具有两个特定条件的过滤器:数据存在的时间不得超过 6 周 – 从最后一个星期一开始算起,且数据不得“晚于”最后一个星期一。在这里使用了
monday()
函数,来确保范围刚好涵盖 7 个星期。最后,时序
Day.balance
作为第 4、5 行定义的线形图的唯一时序来显示。
在第 2 行中执行的聚合运用了上一节中详述的
over
选项。在这里,时序在 14 天的时间窗口中执行求平均值 –从索引 -13 到索引 0 刚好有 14 个不同的索引。这种聚合与我们到目前为止所了解的其他聚合略有不同,因为表
Day
同时显示在赋值的左边和右边,而较为常用的不含
over
后缀的聚合通常是将从一个表的数据聚合到另一个表。
每天的时序也可以聚合成每周的时序。下面的脚本说明了计算每周现金流而非每天现金流的过程。
Day.cashFlow := sum(O.NetAmount) - sum(PO.NetAmount)
Week.balance := sum(Day.cashFlow / 2) over [-1 .. 0]
when date >= monday(end) - 42 & date < monday(end)
show linechart "Cash flow over the last 6 weeks" a8f10 tomato unit:"$" with
Week.balance as "Balance"
处理事件驱动的数据
事件驱动的数据是指侧重于“变化” 的历史数据的特定呈现。例如,相比收集数据历史记录中每一天的所有历史价格,只收集历史价格变化列表更实用:每次价格变化产生新的价格和日期,且假定在观察到新价格变化前保持新价格不变。Envision 支持将历史数据作为变化列表来呈现的应用方案。
尽管样本数据集不包含有关历史价格的表,但查看过去的采购交易,并假定在观察到下次交易前价格保持不变,可以大概推断出此类数据。本节开头示例中的最后一个脚本块正是这样的。我们来更详细地看一下复制到下面的相关代码行。
PO.Price = PO.NetAmount / PO.Quantity
O.PurchasePrice = latest(PO.Price)
O.Cost = O.PurchasePrice * O.Quantity
O.Profit = O.NetAmount - O.Cost
Week.profitblty := sum(O.Profit) / sum(O.Cost) or 1
when date >= lastMon - 13 * 7 & date < lastMon
show linechart "Profitability over the last 13 weeks" a11f13 tomato unit:"%" with
Week.profitblty
在第 1 行,通过 Envision 中普通的矢量运算针对
O
表中的每一行计算了采购单价。第 2 行使用了
latest
函数,该函数具有十分具体的行为:针对被赋给
latest
函数的
O
表的每一行,查找最近的
O.Price
(不晚于所考量的
O
行),并将此值复制到赋值的左边。第 3 行和第 4 行为更多涉及矢量与聚合的计算。第 5 行定义了一个过滤器,用于将运算范围限制为过去 13 周,在该过滤器块中显示了一个线形图,该线形图使用了之前在第 4 行计算的
Week.profitability
时序。
支持此处计算的要素正是
latest
函数。该函数专门用于捕捉事件流的语义,其中一个值假定为常量,除非它被新事件覆盖。具体地说,使用以下脚本还可以“密化”采购价格,来计算历史记录中每一天的价格:
Day.PurchasePrice = latest(O.Price)
在实践中,
latest
函数可用于处理许多情形,例如缺货、促销、产品生命周期等。