什么是基尼系数
基尼系数是指国际上通用的、用以衡量一个国家或地区居民收入差距的常用指标。是20世纪初意大利经济学家基尼,于1922年提出的定量测定收入分配差异程度的指标。它是根据洛伦兹曲线找出了判断分配平等程度的指标(如下图)。
设实际收入分配曲线和收入分配绝对平等曲线之间的面积为A,实际收入分配曲线右下方的面积为B。并以A除以A+B的商表示不平等程度。这个数值被称为基尼系数或称洛伦茨系数。如果A为零,基尼系数为零,表示收入分配完全平等;如果B为零则系数为1,收入分配绝对不平等。该系数可在零和1之间取任何值。收入分配越是趋向平等,洛伦茨曲线的弧度越小,基尼系数也越小,反之,收入分配越是趋向不平等,洛伦茨曲线的弧度越大,那么基尼系数也越大。如果个人所得税能使收入均等化,那么,基尼系数即会变小。
基尼系数最大为“1”,最小等于“0”。基尼系数越接近0表明收入分配越是趋向平等。国际惯例把0.2以下视为收入绝对平均,0.2-0.3视为收入比较平均;0.3-0.4视为收入相对合理;0.4-0.5视为收入差距较大,当基尼系数达到0.5以上时,则表示收入悬殊。
基尼系数的计算公式推导
A+B的面积=1/2*100%*100%=1/2
其次计算B的面积的话,由于洛伦茨曲线是一条不规则的曲线,无法直接计算B的面积,因此采用近似梯形的面积来代替。
假定全部人口平均分为n组,已累积到第i组人口总收入占全部人口总收入的比重Wi为下底,已累计的第i-1组人口总收入收入占全部人口总收入的比重Wi-1为上底,以每组人口占全部人口的比例即1/n为高,计算一个个小梯形的面积,并加总,即得到近似B的面积:
因此基尼系数的计算公式为:
例子:用户补贴从小到大排列,均分n=100份,前1%用户的总补贴,(0%-2.0%) 用户的总补贴,。。。 0%-100%用户的总补贴为:[1,1+2,1+2+3,…,1+2+…+100]
1、全部用户总补贴累计为1+2+3+…+100=5050
2、每一组已累计补贴占用比重分别为[1/5050,(1+2)/5050,(1+2+3)/5050,…,(1+2+…+100)/5050],假设分别对应到y轴上的高为a,b,c,d, … ,ma,max,a=1/5050,……,max=(1+2+…+100)/5050
3、B的面积就是计算每一个小梯形面积之后进行累加,梯形的高均为1/n,面积累加就是1/n*[(0+a)/2+(a+b)/2+(b+c)/2+……(ma+max)/2] = 1/n*[(b+c+…+ma+max) - max/2]
第一个小梯形实际是个三角形,面积是1/n*[(0+a)/2],注意最后一个梯形的下底只加了一次max/2,最后汇总完之后会减去一个max/2
B的面积=[(1)+(1+2)+(1+2+3)+……+(1+2+3+……+100) - (1+2+3+……+100)/2 ]/5050/100
4、基尼系数G=1-2B=1-2[(1)+(1+2)+(1+2+3)+……+(1+2+3+……+100) - (1+2+3+……+100)/2 ]/5050/100
代码实现
Python实现
import numpy as np
n = 100
wealths = [i for i in range(1,101)] #[1,2,3…100]
cum_wealths = np.cumsum(sorted(np.append(wealths, 0))) #加上0,再排序,再计算cumsum
max = cum_wealths[-1] # 取最后一个,也就是原数组的和
print(np.sum(cum_wealths)) #np.sum(cum_wealths) 是将所有元素求和
print(1-2*((np.float(np.sum(cum_wealths))-max/2)/max/n) #代入基尼系数公式
其他的Python实现方式可参考: http://www.pianshen.com/article/85166463/
SQL实现
with userdaystat as (
select COALESCE(total_cash,0) total_cash
,ntile(100) over(order by COALESCE(total_cash,0) asc ) as bucket_id --按补贴升序的顺序平均分成100份
-- Ntile:是一个窗口函数,它把有序的数据集合 平均分配 到 指定的数量(num)个桶中, 将桶号分配给每一行。如果不能平均分配,则优先分配较小编号的桶,并且各个桶中能放的行数最多相差1。
from sync_mongo_box.extract_source__userdaystat
where pt = '2019-09-01'
) , subsidy_rank as (
select bucket_id
,avg(total_cash) total_cash_avg --按照分组分别计算每一组补贴的平均值
from userdaystat
group by bucket_id
)
select 1-(sum(total_cash_avg * (101-bucket_id))-sum(total_cash_avg)/2)/sum(total_cash_avg)/50 --代入基尼系数公式
from subsidy_rank
--最后结果公式约分后
with userdaystat as (
select COALESCE(total_cash,0) total_cash
,ntile(100) over(order by COALESCE(total_cash,0) asc ) as bucket_id --按补贴升序的顺序平均分成100份
-- Ntile:是一个窗口函数,它把有序的数据集合 平均分配 到 指定的数量(num)个桶中, 将桶号分配给每一行。如果不能平均分配,则优先分配较小编号的桶,并且各个桶中能放的行数最多相差1。
from sync_mongo_box.extract_source__userdaystat
where pt = '2019-09-01'
)
select 1-(sum(total_cash * (101-bucket_id))-sum(total_cash)/2)/sum(total_cash)/50
from userdaystat;