IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> hive求解中位数的几种方法 -> 正文阅读

[大数据]hive求解中位数的几种方法

前言

假设我们有一张学生成绩表student_score,里面有三个字段:学生id:student_id,班级id:class_id,成绩:score,主键为student_id。现在让你求出每个班级学生成绩的中位数。

虽然hive里有内置的percentile()和percentile_approx()函数直接求解分位数,但在面试中,面试官老爷大概率不会让你直接就这么写,而是在你自信满满刷刷刷写完之后告诉你“哦,我们不能用内置函数”。

两种解法

谈到中位数,自然而然容易想到要先排序,然后根据个数的奇偶,如果是奇数个就取中间一位,如果是偶数就取中间两位的平均。关于排序,我们可以使用窗口函数row_number()1,关于奇偶,我们不妨看看奇偶个数有没有共性。

如果总共有n个数,当n=5时,n/2=2.5,我们想要的输出是第3位;当n=6时,n/2=3,我们想要的输出是第3位和第4位的平均,那么可以发现:无论奇偶,中位数必然是在n/2和n/2+1之间的数(包含两端)的平均

由此可以产生第一种解法

解法1:利用中位数的位次特征

先取出每个班级成绩排序以及总数,形成表t,再限制中位数是在n/2和n/2+1之间的数(包含两端)的平均2

select 
  class_id
  ,avg(score) as score_median
from
   (
    select 
          class_id
          ,score
          ,row_number() over (partition by class_id order by score asc) as score_rank
          ,count(student_id) over(partition by class_id) as student_num
    from student_score
    )t
where 
  score_rank between student_num/2 and student_num/2+1
group by 
  class_id

解法2:利用升序与降序的差值

观察如下升序编号和降序编号可以发现,当n为奇数时,中位数对应的升序编号和降序编号的差值为0,当n为偶数时,中位数对应的升序编号和降序编号的差值为1或-13

  • 奇数情况

在这里插入图片描述

  • 偶数情况

在这里插入图片描述
那么通过限定升序编号和降序编号的差值为1,-1或者0,我们可以有如下写法:

select 
  class_id
  ,avg(score) as score_median
from
   (
    select 
          class_id
          ,score
          ,row_number() over (partition by class_id order by score asc) as score_rank_asc
          ,row_number() over (partition by class_id order by score desc) as score_rank_desc
    from student_score
    )t
where 
  (score_rank_asc- score_rank_desc) in (1,-1,0)
group by 
  class_id

但是解法2有一个问题,我们知道row_number处理相同值的时候会随机给一个rank,所以对于不同student_id的相同分数,可能会产生不同的rank,具体来说:
在这里插入图片描述
这时候奇数情况也会存在升序编号和降序编号的差值为1或者-1,就会造成错误的输出。此时可以通过限定主键的方式来使得row_number对于相同分数的不同学生,降序排和升序排的名次在逻辑上是相同的(即保证五个人升序排我是第三名,降序排我也是第三名)。

解法2.1:

select 
  class_id
  ,avg(score) as score_median
from
   (
    select 
          class_id
          ,score
          ,row_number() over (partition by class_id order by score asc student_id asc) as score_rank_asc
          ,row_number() over (partition by class_id order by score desc student_id desc) as score_rank_desc
    from student_score
    )t
where 
  (score_rank_asc- score_rank_desc) in (1,-1,0)
group by 
  class_id

延伸问题:频次+分数

假设现在我们没有每个人的成绩了,只有每个班级的成绩及频次,即问题转换为我:学生成绩表student_score,里面有三个字段:班级id:class_id,成绩:score,频次:frequency。现在让你求出每个班级学生成绩的中位数。

这时候仍然可以考虑升序和降序的频数累积和,两个数都需要大于等于总数一半,即为中位数4

由此有如下写法:

select
    class_id 
    ,avg(score) as score_median
from
(
    select 
        class_id
        ,score
        ,sum(frequency) over(partition by class_id order by score asc) as total_asc
        ,sum(frequency) over(order by scoredesc) as total_desc
        ,sum(frequency) over(partition by class_id ) as total_num
    from 
      student_score
)t
where 
  total_asc>=total_num/2
and 
  total_desc>=total_num/2
group by 
  class_id 

参考文章


  1. SQL窗口函数 ??

  2. 中位数特征 ??

  3. 正序倒序差值 ??

  4. 延伸问题 ??

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-08-08 11:24:53  更:2021-08-08 11:26:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 16:16:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码