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 平均绝对偏差的主要内容,如果未能解决你的问题,请参考以下文章

计算 MAD(平均绝对偏差) GroupBy Pandas

2.13 描述性统计(平均数,中位数,中数,数据的离散度(极差,平均绝对偏差,方差标准差))

均方误差(MSE)和均方根误差(RMSE)和平均绝对误差(MAE)

怎么用sql语句编写求平均值的问题

时间序列之二次移动平均

PML之平均 中值 众数标准偏差方差