SQL 平均绝对偏差
Posted
技术标签:
【中文标题】SQL 平均绝对偏差【英文标题】:SQL Mean Absolute Deviation 【发布时间】:2019-08-06 15:33:16 【问题描述】:我正在尝试从以下 SQL 表中计算“平均绝对偏差”:
|ID | Typical | SMA | MAD
| 1 | 10 | |
| 2 | 20 | |
| 3 | 5 | 11.67 |
| 4 | 12 | 12.33 |
| 5 | 14 | 10.33 |
| 6 | 6 | 10.67 |
| 7 | 2 | 7.33 |
| 8 | 17 | 8.33 |
| 9 | 5 | 8.00 |
计算 MAD 需要: 总和(ABS(当前行 SMA - 典型))在前 2 行和当前。然后将其除以 3。因此对于 ID #3,它将是:
MAD = (ABS(11.67 - 5) + ABS(11.67 - 20) + ABS(11.67 - 10)) / 3
我首先使用 Dynamic SQL 执行此操作,循环并为前一行创建一个 LAG。这很有效,但是当它扩大到更高的回溯期时效率很低。然后我尝试了以下我真正认为可行的方法,但没有:
DECLARE @sma_current numeric(20,10)
UPDATE PY SET
@sma_current = [SMA(20)],
[MAD] = W.[MAD]
FROM (
SELECT [id],
((sum(abs(@sma_current - [Typical])) OVER (ORDER BY [id] ASC ROWS
BETWEEN 2 PRECEDING AND CURRENT ROW))/3) [MAD]
FROM PY ) W WHERE PY.[id] = W.[id] AND PY.[id] >= 3
任何帮助将不胜感激。
【问题讨论】:
用您正在使用的数据库标记您的问题。解释什么不适用于您建议的解决方案。你为什么在变量上使用update
?
我希望变量在每次传递时都会更新,从而更新 SELECT 中的 SMA。这只是引发了一个错误,后来才知道这不起作用,所以我同意不需要变量。我缺少的部分是如何从前几行的 [TYPICAL] 平均值中减去 [TYPICAL] 的值。该变量试图将 [SMA(20)] VALUE 带入 Window 函数,但惨遭失败:)
id 是连续的还是可能有间隙?
@JDG 。 . .这就是我的回答。不适合你吗?
@forpas 他们将永远是连续的
【参考方案1】:
由于 id 是连续的并且没有间隙,您可以使用双自连接进行更新:
update p
set p.mad = round(
(abs(p.sma - p.typical) + abs(p.sma - p1.typical) + abs(p.sma - p2.typical)) / 3.0
, 2)
from py p
inner join py p1 on p1.id + 1 = p.id
inner join py p2 on p2.id + 2 = p.id
见demo。
或者用lag()
窗口函数:
with cte as (
select *,
lag(typical, 1) over (order by id) typical1,
lag(typical, 2) over (order by id) typical2
from py
)
update cte
set mad = round(
(abs(sma - typical) + abs(sma - typical1) + abs(sma - typical2)) / 3.0
, 2)
from cte
请参阅demo。
结果:
> ID | Typical | SMA | MAD
> -: | ------: | ----: | ---:
> 1 | 10 | |
> 2 | 20 | |
> 3 | 5 | 11.67 | 5.56
> 4 | 12 | 12.33 | 5.11
> 5 | 14 | 10.33 | 3.56
> 6 | 6 | 10.67 | 3.11
> 7 | 2 | 7.33 | 4.44
> 8 | 17 | 8.33 | 5.78
> 9 | 5 | 8 | 6
【讨论】:
谢谢,但这与我之前所做的非常相似。不幸的是,当回溯期包含 200 多个值时,这不是非常可扩展的。这些行中的每一行本质上都会存在连接或滞后,性能会急剧下降。 这与我之前所做的非常相似您说您的代码不起作用,但确实如此。此代码与您发布的问题和要求有关。如果还有更多,那么您将不得不调整代码。【参考方案2】:我猜你正在使用 SQL Server。您可以使用可更新的 CTE/子查询,在此处进行计算,然后进行设置:
WITH toupdate as (
SELECT id,
(sum(abs(@sma_current - [Typical])) OVER (ORDER BY [id] ASC ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) / 3) as new_mad
FROM PY
)
UPDATE toupdate
SET mad = new_mad;
【讨论】:
我认为我对变量的错误使用让大家感到困惑。您示例中的 @sma_current 是静态的。根据我原来的例子,这对于每条记录应该是不同的。对于 id#3,结果应该如下所示。疯狂 = (ABS(11.67 - 5) + ABS(11.67 - 20) + ABS(11.67 - 10)) / 3以上是关于SQL 平均绝对偏差的主要内容,如果未能解决你的问题,请参考以下文章
2.13 描述性统计(平均数,中位数,中数,数据的离散度(极差,平均绝对偏差,方差标准差))