HIVE SQL计算一组值的中位数

product_name price
商品A 1.5
商品A 1.0
商品A 2.0
商品A 2.1
商品A 1.6
商品B 3.0
商品B 3.0
商品B 3.1
商品B 3.5
商品B 3.5
商品B 3.6
商品B 3.9
#建表语句
drop table if exists table_name;
create table table_name
(
id bigint comment 'id'
,product_name string comment '商品名称'
,price decimal(18,2) comment '价格'
)
;
insert overwrite table table_name
values 
(1,"商品A",1.5)
,(2,"商品A",1)
,(3,"商品A",2)
,(4,"商品A",2.1)
,(5,"商品A",1.6)
,(6,"商品B",3)
,(7,"商品B",3)
,(8,"商品B",3.1)
,(9,"商品B",3.5)
,(10,"商品B",3.5)
,(11,"商品B",3.6)
,(12,"商品B",3.9)
;

需求:求不同商品售价的中位数,以及所有商品售价的中位数
法一:percentile_approx()函数求中位数

##分组后求中位数
select product_name
	,percentile_approx(price,0.5,10000000) as med_price
from 
table_name
group by product_name
;

输出不同商品售价的中位数结果:

product_name med_price
商品A 1.55
商品B 3.2
##不分组直接求中位数
select 
percentile_approx(price,0.5,10000000) as med_price
from 
table_name;

输出所有商品售价的中位数结果:

med_price
2.55

percentile_approx(col, p,B)
p的取值为0-1,若为0.2,则结果为二分位数。参数B控制内存消耗的近似精度,B越大,结果的准确度越高。默认为10,000。当col字段中的distinct值的个数小于B时,结果就为准确的百分位数。
在不分组的情况下,也可一次性求多个分位数,percentile_approx(col,array(0.05,0.5,0.95),9999),结果返回一个分位数列表。
percentile(col, p,B)
col是要计算的列(值必须为int类型)

法二:排序后打分位点

##分组排序后计算中位数
#排序
with tmp1 as 
(
select id
	,product_name
	,price
	,row_number() over (partition by product_name order by price asc) as rn
from 
table_name)
#打分位数标签
,tmp2 as 
(
select a.*
	,b.cnt 
	,case when a.rn=ceil(b.cnt*0.5) then 'qt50'
		else null 
		end as quantile_flag
from 
tmp1 a 
left join 
(select product_name,count(*) as cnt from tmp1 group by product_name) b 
on a.product_name=b.product_name
)
#计算分位数标签对应的分为数值
select product_name
	,max(if(quantile_flag='qt50', price, null)) as qt50
from 
tmp2 
group by product_name
;

输出不同商品售价的中位数结果:

product_name med_price
商品A 1.60
商品B 3.5
##不分组排序直接求中位数

with tmp1 as 
(
select id
	,product_name
	,price
	,row_number() over (order by price asc) as rn
from 
hvprd_dmcp_udl.ptt_temp_1101
)
select 
price
from 
tmp1 a 
left join 
(select count(*) as cnt from tmp1) b 
on 1=1
where a.rn=ceil(b.cnt*0.5)
;
med_price
3.00

两种方式计算出来的结果出现了差异,这可能是由于法一percentile_approx计算百分数的方式与法二不一致导致。计算百分位数的时候主要有这样几种方法:
(1)最近序数方法(The Nearest Rank method)
(2)在最近序数间线性插值的方法(The Linear Interpolation Between Closest Ranks method)
(3)权重百分位数方法(The Weighted Percentile method)
(4)微软excel表格算法(Microsoft Excel method)
(5)NIST方法(NIST method)

具体差异以后有机会再研究吧。
关于百分位的含义,可参考这篇文章

猜你喜欢

转载自blog.csdn.net/p1306252/article/details/127643041
今日推荐