在 oracle 中计算滚动加权平均值

Posted

技术标签:

【中文标题】在 oracle 中计算滚动加权平均值【英文标题】:Calculate a rolling weighted average in oracle 【发布时间】:2018-10-08 14:59:29 【问题描述】:

我的数据子集如下所示:

create table tbl_1 as (
    select * from (
        select trunc(sysdate - (rownum - 1)) as call_dt,
               rownum as calls,
               to_char(trunc(sysdate - (rownum - 1)), 'DAY') as dow
        from dual connect by rownum <= 22
    )
    where dow like '%MONDAY%'
    order by call_dt
)
;

 call_dt  | calls | dow
-------------------------
17-SEP-18    22    MONDAY   
24-SEP-18    15    MONDAY   
01-OCT-18    8     MONDAY   
08-OCT-18    1     MONDAY 

然后我有另一个表格,其中包含如下所示的未来日期:

create table tbl_2 as (
    select * from (
        select  trunc(sysdate + (rownum - 1)) as call_dt, 
                0 as calls,
                to_char(trunc(sysdate + (rownum - 1)), 'DAY') as dow
        from dual
        connect by rownum <= 15
    )
    where dow like '%MONDAY%'
)
;

 call_dt  | calls | dow
-------------------------
15-OCT-18     0    MONDAY   
22-OCT-18     0    MONDAY

我正在尝试获取我未来的日期,将它们附加到我的历史数据中,然后计算滚动加权平均值。我目前正在使用以下查询进行此操作。

select  call_dt,
        case when calls = 0 then (
            (1 * lag1) + (0.8 * lag2) + (0.5 * lag3) + (0.3 * lag4))
             else calls 
             end as calls,
        dow
from (
    select  call_dt, calls, dow,
            lag(calls, 4) OVER (partition by dow order by call_dt) as lag4,
            lag(calls, 3) OVER (partition by dow order by call_dt) as lag3,
            lag(calls, 2) OVER (partition by dow order by call_dt) as lag2,
            lag(calls, 1) OVER (partition by dow order by call_dt) as lag1
    from (
        select * from tbl_1
        union
        select * from tbl_2
    )
    order by dow, call_dt
)
;

这会导致以下结果:

 call_dt  | calls | dow
-------------------------
17-SEP-18    22    MONDAY   
24-SEP-18    15    MONDAY   
01-OCT-18    8     MONDAY   
08-OCT-18    1     MONDAY 
15-OCT-18    46    MONDAY   
22-OCT-18    24    MONDAY

这适用于一周中每一天的第一个未来日期。但是,对于后续日期,lag* 变量等于 0,因此值为 off。这是我希望实现的目标:

 call_dt  | calls | dow
-------------------------
17-SEP-18    22    MONDAY   
24-SEP-18    15    MONDAY   
01-OCT-18    8     MONDAY   
08-OCT-18    1     MONDAY 
15-OCT-18    46    MONDAY   
22-OCT-18    70    MONDAY

我看了this question,好像它可以给我想要的东西?但是使用的窗口函数关键字对我来说是陌生的。我还查看了this tutorial,但这些滚动平均函数似乎假设非零条目。有没有可能达到这些结果?

【问题讨论】:

您使用的是什么版本的 Oracle?最简单的方法可能是递归 CTE。 你知道windowing_clause吗?也许像RANGE BETWEEN INTERVAL '4' DAY PRECEDING AND INTERVAL '4' DAY FOLLOWING @GordonLinoff 我正在使用这个版本:Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production @WernfriedDomscheit 我不熟悉 windowing_clause。您能否详细说明BETWEEN INTERVAL '4' DAY PRECEDING AND INTERVAL '4' DAY FOLLOWING 的工作原理?这是否会在 Oracle 正在运行的当前行的日期前后创建一个 +/- 4 天的窗口? 是的,它就是这样工作的。 Oracle 在此示例中采用 +/- 4 天,无论此范围涵盖多少行。 【参考方案1】:

使用递归查询,它将最后一个calls 当作lag1 并将所有其他lags 移到过去:

with 
  s as (
    select  rn, call_dt, calls, 
            lag(calls, 4) OVER (partition by dow order by call_dt) as lag4,
            lag(calls, 3) OVER (partition by dow order by call_dt) as lag3,
            lag(calls, 2) OVER (partition by dow order by call_dt) as lag2,
            lag(calls, 1) OVER (partition by dow order by call_dt) as lag1
    from (
        select 0 rn, tbl_1.* from tbl_1 union all
        select row_number() over (order by call_dt), tbl_2.* from tbl_2)),
  c(rn, call_dt, calls, lag1, lag2, lag3, lag4) as (
    select rn, call_dt, (1 * lag1) + (0.8 * lag2) + (0.5 * lag3) + (0.3 * lag4), 
           lag1, lag2, lag3, lag4 
      from s where rn = 1
    union all
    select s.rn, s.call_dt, (1 * c.calls) + (0.8 * c.lag1) + (0.5 * c.lag2) + (0.3 * c.lag3), 
           c.calls, c.lag1, c.lag2, c.lag3
      from s join c on c.rn+1 = s.rn)
select * from c

s - 基本上是您的查询,我在其中添加了行编号。 c 是 CTE,rn = 1 是我们的锚点,第一步。然后我们逐行添加下一步, 将之前的值向右移动。我认为我们应该将结果除以 4,但你没有这样做?希望这会有所帮助。

结果:

    RN CALL_DT          CALLS       LAG1       LAG2       LAG3       LAG4
------ ----------- ---------- ---------- ---------- ---------- ----------
     1 2018-10-15        21,5          1          8         15         22
     2 2018-10-22        30,8       21,5          1          8         15

【讨论】:

是的,结果应该除以 4 以获得平均值,但我忘记包含它并且不想通过更改它来引起混淆。您的结果看起来不错,但我需要花一些时间来研究解决方案。正如我正在审查的那样,您能否澄清此解决方案在其处理的未来日期范围内是否是动态的,或者该解决方案是否假设只有两周可以预测?提前感谢您! 刚刚测试了所有东西,效果很好!非常感谢!

以上是关于在 oracle 中计算滚动加权平均值的主要内容,如果未能解决你的问题,请参考以下文章

在 Reporting Services 2008 中计算加权平均值

R语言计算加权平均值:weighted.mean函数计算加权平均值matrixStats包的weightedMean函数计算加权平均值SDMTools包的wt.mean函数计算加权平均值

计算每个产品的加权平均值 [关闭]

如何在单列PowerBI中使用值和权重计算加权平均值

使用熊猫/数据框计算加权平均值

如何计算 PyTorch 中注意力分数和编码器输出的加权平均值?