【问题标题】:SQL: Show average and min/max within standard deviationsSQL:显示标准偏差内的平均值和最小值/最大值
【发布时间】:2010-03-05 02:07:26
【问题描述】:

我有以下 SQL 表 -

Date       StoreNo       Sales
23/4            34     4323.00
23/4            23      564.00
24/4            34     2345.00
etc

我正在运行一个查询,返回特定时期的平均销售额、最大销售额和最小销售额 -

select avg(Sales), max(sales), min(sales)
from tbl_sales
where date between etc

但是在最小值和最大值中出现了一些非常极端的值 - 可能是因为数据输入错误,也可能是因为该日期和存储发生了一些异常情况。

我想要的是一个返回平均值、最大值和最小值的查询,但以某种方式排除了极值。我对如何做到这一点持开放态度,但也许它会以某种方式使用标准偏差(例如,仅使用真实平均值的 x 标准差内的数据)。

非常感谢

【问题讨论】:

    标签: sql sql-server-2005


    【解决方案1】:

    为了计算标准差,您需要遍历所有元素,因此不可能在一个查询中完成此操作。懒惰的方法是分两次完成:

    DECLARE
        @Avg int,
        @StDev int
    
    SELECT @Avg = AVG(Sales), @StDev = STDEV(Sales)
    FROM tbl_sales
    WHERE ...
    
    SELECT AVG(Sales) AS AvgSales, MAX(Sales) AS MaxSales, MIN(Sales) AS MinSales
    FROM tbl_sales
    WHERE ...
    AND Sales >= @Avg - @StDev * 3
    AND Sales <= @Avg + @StDev * 3
    

    另一个可能可行的简单选项(在科学数据分析中相当常见)是只删除最小和最大 x 值,如果您有需要处理的大量数据。您可以使用ROW_NUMBER 在一个语句中执行此操作:

    WITH OrderedValues AS
    (
        SELECT
            Sales,
            ROW_NUMBER() OVER (ORDER BY Sales) AS RowNumAsc,
            ROW_NUMBER() OVER (ORDER BY Sales DESC) AS RowNumDesc
    )
    SELECT ...
    FROM tbl_sales
    WHERE ...
    AND Sales >
    (
        SELECT MAX(Sales)
        FROM OrderedValues
        WHERE RowNumAsc <= @ElementsToDiscard
    )
    AND Sales <
    (
        SELECT MIN(Sales)
        FROM OrderedValues
        WHERE RowNumDesc <= @ElementsToDiscard
    )
    

    如果您想丢弃一定数量的唯一值,请将ROW_NUMBER替换为RANKDENSE_RANK

    除了这些简单的技巧之外,您还开始掌握一些相当繁重的统计数据。我必须处理类似的验证,对于 SO 帖子来说,它的材料太多了。有一百种不同的算法,您可以通过十几种不同的方式对其进行调整。如果可能,我会尽量保持简单!

    【讨论】:

      【解决方案2】:

      扩展 DuffyMo 的帖子,你可以做类似的事情

      With SalesStats As
          (
          Select Sales, NTILE( 100 ) OVER ( Order By Sales ) As NtileNum
          From tbl_Sales
          )
      Select Avg( Sales ), Max( Sales ), Min( Sales )
      From SalesStats
      Where NtileNum Between 5 And 95
      

      这将排除最低的 5% 和最高的 95%。如果您的数字变化很大,您可能会发现平均值不是质量汇总统计数据,应考虑使用中位数。你可以这样做:

      With SalesStats As
          (
          Select NTILE( 100 ) OVER ( Order By Sales ) As NtileNum
              , ROW_NUMBER() OVER ( Order By Id ) As RowNum
          From tbl_Sales
          )
          , TotalSalesRows
              (
              Select COUNT(*) As Total
              From tbl_Sales
              )
          , Median As
              (
              Select Sales 
              From SalesStats
                  Cross Join TotalSalesRows
              Where RowNum In ( (TotalRows.Total + 1) / 2, (TotalRows.Total + 2) / 2 )
              )
      Select Avg( Sales ), Max( Sales ), Min( Sales ), Median.Sales
      From SalesStats
          Cross Join Median
      Where NtileNum Between 5 And 95
      

      【讨论】:

      • 更正关于使用中值与平均值的差异数据;请注意,中值查询可以通过将 COUNT(*)ROW_NUMBER 放在同一个 CTE 中来完成一次扫描,并且可能应该选择 AVG(Sales),除非您真的想要两个汇总行,当计数是偶数时。
      • 对于第一块代码,下面一行必须包含Sales才能取AVG(Sales):Select Sales, NTILE(100) OVER (Order By Sales) A​​s NtileNum
      【解决方案3】:

      也许您正在寻找的是percentiles

      标准差往往对异常值很敏感,因为它是使用值与平均值之差的平方计算的。

      在您的情况下,也许更稳健、更不敏感的度量(例如值与平均值之间的差值的绝对值)会更合适。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-16
        • 2022-01-11
        • 2014-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-14
        • 2019-12-11
        相关资源
        最近更新 更多