MySQL选择使用AVG和STD条件排除异常值的结果

时间:2015-02-17 16:57:09

标签: mysql statistics standard-deviation

我正在尝试编写一个查询,该值排除超出结果集均值的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子句是必要的,但是当我了解更多时,它似乎并不是我所追求的。我接近了吗?是否有一些时髦的方法来访问聚合函数的值以便在条件中使用(无需返回聚合值)?

2 个答案:

答案 0 :(得分: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谓词的重复,以及{{1}的删除只有外部查询的子句。

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

答案 1 :(得分:0)

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

引用的Excel函数

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

用法

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

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

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

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