【问题标题】:MySQL Select Results Excluding Outliers Using AVG and STD ConditionsMySQL 使用 AVG 和 STD 条件选择排除异常值的结果
【发布时间】:2015-02-17 16:57:08
【问题描述】:

我正在尝试编写一个查询,该查询从结果集的平均值中排除超过 6 个标准差的值。我希望这可以通过子查询优雅地完成,但我无处可去,在我读过的每一个类似情况下,目标似乎只是一点不同。我的结果集似乎仅限于一行,我猜是由于调用了聚合函数。从概念上讲,这就是我所追求的:

SELECT t.Result FROM
  (SELECT Result, AVG(Result) avgr, STD(Result) stdr
   FROM myTable WHERE myField=myCondition limit=75) as t
WHERE t.Result BETWEEN (t.avgr-6*t.stdr) AND (t.avgr+6*t.stdr)

我可以通过将 STD 或 AVG 值(即 t.avgr)的每次使用替换为它自己的 select 语句来使其工作:

(SELECT AVG(Result) FROM myTable WHERE myField=myCondition limit=75) 

但这似乎比我预期的要混乱得多(我有几个条件)。起初我认为指定 HAVING 子句是必要的,但随着我了解的更多,它似乎并不是我所追求的。我接近了吗?是否有一些时髦的方法可以访问聚合函数的值以在条件中使用(无需返回聚合值)?

【问题讨论】:

    标签: mysql statistics standard-deviation


    【解决方案1】:

    是的,您的子查询是没有GROUP BY 子句的聚合查询,因此其结果是单行。当您从中选择时,您不能获得超过一排。此外,它是一个 MySQL 扩展,您可以在子查询的选择列表中包含 Result 字段,因为它既不是分组列也不是组的聚合函数(所以它在这种情况下甚至意味着什么,除非,可能所有相关的列值都相同?)。

    你应该能够做这样的事情来计算一次平均值和标准偏差,而不是每个结果:

    SELECT t.Result FROM
      myTable AS t
      CROSS JOIN (
        SELECT AVG(Result) avgr, STD(Result) stdr
        FROM myTable
        WHERE myField = myCondition
      ) AS stats
    WHERE 
      t.myField = myCondition
      AND t.Result BETWEEN (stats.avgr-6*stats.stdr) AND (stats.avgr+6*stats.stdr)
    LIMIT 75
    

    请注意,您需要注意统计信息是在您从中选择的同一组行上计算的,因此myField = myCondition 谓词的重复,但也将LIMIT 子句删除到仅限外部查询。

    您可以向聚合子查询添加更多统计信息,前提是它们都是针对同一组行计算的,或者您可以通过单独的子查询加入针对不同行计算的其他统计信息。请确保您的所有统计信息子查询每个都准确返回一行,否则您将得到重复(或没有)结果。

    【讨论】:

    • 做到了 puuuuurfect。谢谢!!以前从未使用过 CROSS JOIN。非常感谢你把它淘汰了。更优雅。
    【解决方案2】:

    我创建了一个不完全按照您要求的方式计算的 UDF(它丢弃了顶部和底部结果的百分比,而不是使用 std),但它可能对您有用 (或其他人)无论如何,匹配此处引用的 Excel 函数https://support.office.com/en-us/article/trimmean-function-d90c9878-a119-4746-88fa-63d988f511d3

    https://github.com/StirlingMarketingGroup/mysql-trimmean

    用法

    `trimmean` ( `NumberColumn`, double `Percent` [, integer `Decimals` = 4 ] )
    
    • `NumberColumn`

      • 要修剪和平均的值列。
    • `Percent`

      • 要从计算中排除的小数数据点。例如,如果百分比 = 0.2,则从 20 个点 (20 x 0.2) 的数据集中修剪 4 个点:从顶部剪掉 2 个点,从底部剪掉 2 个。
    • `Decimals`

      • (可选)要输出的小数位数。默认值为 4。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-16
      相关资源
      最近更新 更多