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

MySQL Select Results Excluding Outliers Using AVG and STD Conditions

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

是的,您的子查询是一个聚合查询,没有 GROUP BY 子句,因此它的结果是单行。当你从那里 select 时,你不能得到超过一行。此外,它是一个 MySQL 扩展,您可以在子查询的 selection 列表中包含 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

请注意,您需要注意统计数据是针对您 select 所在的同一组行计算的,因此 myField = myCondition 谓词重复,而且仅删除外部查询的 LIMIT 子句。

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

我创建了一个 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`

    • 列值 trim 和平均值。
  • `Percent`

    • 要从计算中排除的数据点的分数。例如,如果百分比 = 0.2,则 trim 从包含 20 个点 (20 x 0.2) 的数据集中提取 4 个点:2 个来自顶部,2 个来自底部。
  • `Decimals`

    • 可选,要输出的小数位数。默认为 4。