# 时序计算

## 示例

read "/sample/Lokad_Items.tsv"

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 提供三个虚拟表，分别为 DayWeekMonth。之所以称这些表为“虚拟”表，是因为它们不具备相应的表格文件。换言之，这些表仅在执行脚本期间存在。上述脚本就是利用这些虚拟表来显示线形图的。我们来看一下重新复制到下面的相关代码行。 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"


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


## 显示滞后的时序

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 表时，滞后参数是一个以每周为单位的整数。同样，DayMonth 表的适用单位分别为“天”和“月”。 滞后算子得益于过滤算子 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.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]，其中 ab 为整数，且 a 小于或等于 bab 所使用的单位取决于赋值左边的表达式。在本例中，赋值左边为 Week 表，因此 -30 按周表示。 注意：索引为 -3 的周与索引为 0 的周之间有 4 周，而不是 3 周。因此，周数索引为 -3、-2、-1 和 0。 over 选项可用于所有聚合器。在使用此选项时，赋值左边通常为虚拟日历表，例如 DayWeekMonth。但这并非硬性要求，任何按 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"


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"


## 处理事件驱动的数据

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


Day.PurchasePrice = latest(O.Price)