我在计算一组数值的中位数时遇到了麻烦,而不是平均值。
我找到了这篇文章 用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
是百分位数(中位数为.5,第75个百分位数为.75等),这将找到任意百分位数。
SELECT avg(val) FROM (SELECT val FROM data ORDER BY val limit @middlevalue, @numvalues) x;
,其中@numvalues为(@middlevalue mod 2) +1
。 - Ella RyanCREATE 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);
time
) AS time_taken
FROM scores
WHERE created_at >= '2010-10-10' and created_at <= '2010-11-11'
GROUP BY user_id)
AS average_user_total_time" )用于计算用户分数的总平均值,但不确定如何将中位数公式应用于此查询。对于重新发布帖子超时的情况非常抱歉。 - TimSELECT
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)和元素总数(count)。使用 CEILING 确定位置可以帮助我们在下面的步骤中使用 substring_index 函数。
根据 count,决定值的数量是偶数还是奇数。
最后计算中位数。
A
的列的表格R
,并且您想要获得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 )
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)
因此,要对日期进行排序,您需要一个数字值;您可以获取它们的时间戳(作为从纪元开始经过的秒数),并使用中位数的定义。
我和我的朋友找到的最简单方法......尽情享受!
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)
最初采用自此线程。