MySQL:计算按列分组的值的中位数
Posted
技术标签:
【中文标题】MySQL:计算按列分组的值的中位数【英文标题】:MySQL: Calculating Median of Values grouped by a Column 【发布时间】:2019-10-30 08:37:23 【问题描述】:我有下表:
+------------+-------+
| SchoolName | Marks |
+------------+-------+
| A | 71 |
| A | 71 |
| A | 71 |
| B | 254 |
| B | 135 |
| B | 453 |
| B | 153 |
| C | 453 |
| C | 344 |
| C | 223 |
| B | 453 |
| D | 300 |
| D | 167 |
+------------+-------+
这是按学校名称分组的平均分数:
+------------+------------+
| SchoolName | avg(Marks) |
+------------+------------+
| A | 71.0000 |
| B | 289.6000 |
| C | 340.0000 |
| D | 233.5000 |
+------------+------------+
https://www.db-fiddle.com/f/5t7N3Vx8FSQmwUJgKLqjfK/9
但是,我想计算按学校名称分组的分数的中位数,而不是平均分数。
我正在使用,
SELECT AVG(dd.Marks) as median_val
FROM (
SELECT d.Marks, @rownum:=@rownum+1 as `row_number`, @total_rows:=@rownum
FROM tablename d, (SELECT @rownum:=0) r
WHERE d.Marks is NOT NULL
ORDER BY d.Marks
) as dd
WHERE dd.row_number IN ( FLOOR((@total_rows+1)/2), FLOOR((@total_rows+2)/2) );
要计算整个Marks列的平均值,但我不知道如何分别为每个学校做。
【问题讨论】:
您使用的是哪个版本的 mysql? 我使用的是 MySQL 8。 您能告诉我们您的预期结果吗? 【参考方案1】:您的查询使用用户变量计算行号,这使得处理分区更加复杂。由于您使用的是 MySQL 8.0,因此我建议您改用窗口函数。
这应该会让你接近你的期望:
select
SchoolName,
avg(Marks) as median_val
from (
select
SchoolName,
Marks,
row_number() over(partition by SchoolName order by Marks) rn,
count(*) over(partition by SchoolName) cnt
from tablename
) as dd
where rn in ( FLOOR((cnt + 1) / 2), FLOOR( (cnt + 2) / 2) )
group by SchoolName
算法保持不变,但我们在具有相同SchoolName
的记录组中使用窗口函数(而不是初始查询中的全局分区)。然后,外部查询按SchoolName
过滤和聚合。
在 your DB Fiddlde 中,返回:
| SchoolName | median_val |
| ---------- | ---------- |
| A | 71 |
| B | 254 |
| C | 344 |
| D | 233.5 |
【讨论】:
符合我的要求!非常感谢! :) 欢迎@PardeepKumar!很高兴它有帮助。以上是关于MySQL:计算按列分组的值的中位数的主要内容,如果未能解决你的问题,请参考以下文章
R语言vtreat包自动处理dataframe的缺失值使用分组的中位数来标准化数据列中每个数据的值(和中位数表连接并基于中位数进行数据标化)计算数据列的中位数或者均值并进行数据标准化
R语言ggpubr包ggsummarystats函数可视化分组箱图(自定义分组颜色)并在X轴标签下方添加分组对应的统计值(样本数N中位数median四分位数的间距iqr统计值的色彩和分组图色匹配