我无法计算值列表的中位数,而不是平均值。
我发现这篇文章 使用 MySQL 计算中位数的简单方法
它引用了我不正确理解的以下查询。
SELECT x.val from data x, data y
GROUP BY x.val
HAVING SUM(SIGN(1-SIGN(y.val-x.val))) = (COUNT(*)+1)/2
如果我有一time
列并且我想计算中值,那么x
和y
列指的是什么?
我无法计算值列表的中位数,而不是平均值。
我发现这篇文章 使用 MySQL 计算中位数的简单方法
它引用了我不正确理解的以下查询。
SELECT x.val from data x, data y
GROUP BY x.val
HAVING SUM(SIGN(1-SIGN(y.val-x.val))) = (COUNT(*)+1)/2
如果我有一time
列并且我想计算中值,那么x
和y
列指的是什么?
我提出一个更快的方法。
获取行数:
SELECT CEIL(COUNT(*)/2) FROM data;
然后在排序的子查询中取中间值:
SELECT max(val) FROM (SELECT val FROM data ORDER BY val limit @middlevalue) x;
我用一个 5x10e6 的随机数数据集对此进行了测试,它会在 10 秒内找到中位数。
COUNT(*)/2
这将通过将替换为百分位数(COUNT(*)*n
中n
位数为 0.5,第 75 个百分位数为 0.75 等)来找到任意百分位数。
val
是你的时间列,x
是y
对数据表的两个引用(你可以写data AS x, data AS y
)。
编辑:为避免计算两次总和,您可以存储中间结果。
CREATE TEMPORARY TABLE average_user_total_time
(SELECT SUM(time) AS time_taken
FROM scores
WHERE created_at >= '2010-10-10'
and created_at <= '2010-11-11'
GROUP BY user_id);
然后,您可以计算命名表中这些值的中位数。
编辑:临时表在这里不起作用。您可以尝试使用具有“MEMORY”表类型的常规表。或者只是让您的子查询在您的查询中计算两次中位数的值。除此之外,我没有看到其他解决方案。这并不意味着没有更好的方法,也许其他人会提出一个想法。
首先尝试了解中位数是什么:它是排序后的值列表中的中间值。
一旦你理解了这一点,方法就是两个步骤:
例子:
Median of 0 1 3 7 9 10: 5 (because (7+3)/2=5)
Median of 0 1 3 7 9 10 11: 7 (because 7 is the middle value)
因此,要对日期进行排序,您需要一个数值;您可以获得他们的时间戳(从纪元开始经过的秒数)并使用中位数的定义。
使用 group_concat 在 mysql 中查找中位数
询问:
SELECT
IF(count%2=1,
SUBSTRING_INDEX(substring_index(data_str,",",pos),",",-1),
(SUBSTRING_INDEX(substring_index(data_str,",",pos),",",-1)
+ SUBSTRING_INDEX(substring_index(data_str,",",pos+1),",",-1))/2)
as median
FROM (SELECT group_concat(val order by val) data_str,
CEILING(count(*)/2) pos,
count(*) as count from data)temp;
解释:
排序是使用 group_concat 函数内部的 order by
识别位置(pos)和元素总数(计数)。CEILING 识别位置有助于我们在以下步骤中使用 substring_index 函数。
根据计数,决定偶数或奇数个值。
最后计算中位数。
如果您有一个R
包含名为 的列的表A
,并且您想要A 的中位数,您可以执行以下操作:
SELECT A FROM R R1
WHERE ( SELECT COUNT(A) FROM R R2 WHERE R2.A < R1.A ) = ( SELECT COUNT(A) FROM R R3 WHERE R3.A > R1.A )
注意:这仅适用于 A 中没有重复值的情况。此外,不允许使用空值。
我和我的朋友发现的最简单的方法......享受吧!
SELECT count(*) INTO @c from station;
select ROUND((@c+1)/2) into @final;
SELECT round(lat_n,4) from station a where @final-1=(select count(lat_n) from station b where b.lat_n > a.lat_n);
这是一个易于理解的解决方案。只需根据您的要求替换Your_Column和Your_Table 。
SET @r = 0;
SELECT AVG(Your_Column)
FROM (SELECT (@r := @r + 1) AS r, Your_Column FROM Your_Table ORDER BY Your_Column) Temp
WHERE
r = (SELECT CEIL(COUNT(*) / 2) FROM Your_Table) OR
r = (SELECT FLOOR((COUNT(*) / 2) + 1) FROM Your_Table)
最初通过这个线程。