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。
我正在尝试编写一个查询,以排除超出结果集平均值 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。