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

问题描述 投票:2回答:2

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

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
2个回答
2
投票

是,您的子查询是没有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子句移至外部仅查询。

您可以向聚合子查询中添加更多统计信息,但前提是所有统计信息都是在同一行集合上计算得出的,也可以通过单独的子查询将在不同行上计算出的其他统计信息合并在一起。确保确保所有统计信息子查询每个返回的行都完全相同,否则您将获得重复(或没有)结果。


0
投票

我创建的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`

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

    • (可选,要输出的小数位数。默认值为4。
© www.soinside.com 2019 - 2024. All rights reserved.