基尼系数直接计算法_基尼系数简单的计算方法

2022-11-08 11:30:29 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

使用两种方法,通过python计算基尼系数。

在sql中如何计算基尼系数,可以查看我的另一篇文章。两篇文章取数相同,可以结合去看。

文章中方法1的代码来自于:(加入了一些注释,方便理解)。为精确计算。

如果对于基尼系数概念不太清楚,可以看原文的第一部分。

基尼系数计算方法 – longwind09 – 博客园

方法2和3借鉴资料:方法2和3是近似算法。其中方法3:只适用于一些特殊情况。

http://www.360doc.com/content/14/0911/13/87990_408644530.shtml

————————————————————————————————-

方法一:

代码语言:javascript复制
#方法1

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as pl

from scipy.integrate import odeint

def gini():
    # 计算数组累计值,从 0 开始
    wealths = [346,  559,  198,  420,  39,  709,  225,  731,  708,  369,  519,
               46,  48,  446,  117,  127,  905,  652,  528,  832,  217,  536, 
               942,  608,  37,  802,  422,  884,  746,  959,  759,  397,  245, 
               83,  542,  907,  128,  933,  740,  506,  458,  830,  874,  570,
               914,  592,  585,  574,  636,  462,  86,  321,  174,  238,  670, 
               690,  456,  918,  70,  801,  695,  908,  57,  497,  605,  334,  
               265,  255,  235,  199,  739,  81,  131,  68,  229,  602,  390, 
               571,  733,  440,  528,  409,  222,  55,  876,  606,  906,  549, 
               487,  552,  796,  454,  301,  914,  635,  304,  503,  688,  631,
               705]
    # 一共是100个数字
#    wealths = [1.5, 2, 3.5, 10, 4.2, 2.1, 1.1, 2.2, 3.1, 5.1, 9.5, 9.7, 1.7, 2.3, 3.8, 1.7, 2.3, 5, 4.7, 2.3, 4.3, 12]
    cum_wealths = np.cumsum(sorted(np.append(wealths, 0)))
    #加上0,再排序,再计算cumsum
    # 取最后一个,也就是原数组的和
    sum_wealths = cum_wealths[-1]
    #倒数第一个
    # 人数的累积占比
    #就是每个点都会产生一个横坐标
    xarray = np.array(range(0, len(cum_wealths))) / np.float(len(cum_wealths) - 1)
    # 均衡收入曲线
    #就是45度曲线
    upper = xarray
    # 收入累积占比
    yarray = cum_wealths / sum_wealths
    #cumsum的占比
    # 绘制基尼系数对应的洛伦兹曲线
    pl.plot(xarray, yarray)
    pl.plot(xarray, upper)
    # 上面画的是45度线
    #ax.plot(xarray, yarray)
    #ax.plot(xarray, upper)
    #ax.set_xlabel(u'人数累积占比')
    #ax.set_ylabel(u'收入累积占比')
    #pl.show()
    # 计算曲线下面积的通用方法
    B = np.trapz(yarray, x=xarray)
    # 总面积 0.5
    A = 0.5 - B
    G = A / (A   B)
    print (G)

# 执行函数输出结果
gini()
# 结果为
0.3109641735512392

画出来的图:

方法二:

近似的求上图中的面积,将其分割成多个梯形,通过近似计算多个梯形面积,将其加和得到蓝色线条线条下面的面积。

通过简化推到多个梯形面积求和公式,得到一个比较简单的公式,就是链接2中结尾的公式。

如果分组的数量跟样本数量相同,就可以得到精确的数字,计算出来的基尼系数跟上面方法1的结果相等。

如果分组数量降低,获得的基尼系数将稍低于准确的基尼系数,因为更多的将非直线的曲线假设成了直线,即梯形的一边。

代码语言:javascript复制
# 第二个方法
# 接着上面的定义
# 可能会出现样本数量不能被分组数量均分的情况,所以需要借助python自己包含的分布数组pd.cut

# 分成n个组
n = 100
m = pd.cut(pd.Series(range(1, len(cum_wealths))), bins = n, labels = False)
# 将1到样本数量的整数,分成‘均匀’的n个组
# labels = false生成一些组数,表示这个位置原来的值属于1到n的哪个组
y = m.groupby(by = m).size().cumsum()
# 得到每个分组中的最后一个数的位置在哪里
# size表示每个组里面有多少个元素
# cumsum之后显示每个组里面最后一个元素的位置
#就是图中分为点的位置
t = yarray[y[:]]
#取得在yarray上的值
#就是图中w0 w1 w2等的值
g = 1 - (1/n)*(2*(sum(t)-1) 1)
# 跟文档中的有一点不一样,在最后的计算中减去了1
# 但其实是一致的,文档中分成了5组,w1到w5,求和的是4个y轴值的和,即为w1-w4,是到n-1的和
# 所以可改写成(不要刻意减去1,按照公式,加总到n-1)
g = 1 - (1/n)*(2*(sum(t[0:n-1])) 1)
g
# 结果为
0.3109641735512395

# 相同的计算,只是起始位置稍有不同
# 上面是从1开始,这里是从0开始
# 如果是从0开始,如果第一组中有6个元素,需要取第6个元素,在python中的index是5,所以需要减去1
n = 100
m = pd.cut(pd.Series(range(0, len(cum_wealths))), bins = n, labels = False)
y = m.groupby(by = m).size().cumsum() - 1
t = yarray[y[:]]
g = 1 - (1/n)*(2*(sum(t)-1) 1)
#或者是
g = 1 - (1/n)*(2*(sum(t[0:n-1])) 1)
g

# 结果为
0.3109641735512395

n = 19
m = pd.cut(pd.Series(range(1, len(cum_wealths))), bins = n, labels = False)
y = m.groupby(by = m).size().cumsum()

t = yarray[y[:]]
g = 1 - (1/n)*(2*(sum(t)-1) 1)
g

# 结果为
0.3133532456894873


n = 9
m = pd.cut(pd.Series(range(1, len(cum_wealths))), bins = n, labels = False)
y = m.groupby(by = m).size().cumsum()

t = yarray[y[:]]
g = 1 - (1/n)*(2*(sum(t)-1) 1)
g

#结果为
0.300356286353766


n = 20
m = pd.cut(pd.Series(range(1, len(cum_wealths))), bins = n, labels = False)
y = m.groupby(by = m).size().cumsum()

t = yarray[y[:]]
g = 1 - (1/n)*(2*(sum(t[0:n-1])) 1)
g

#结果为
0.31025484587225693

———————————————————————————————————————————————————————–

最初开始计算时候做的比较简单的思路,但是并不适用于样本数量不能被分组数整除的情况。但可能有助于对基尼系数近似计算的理解,所以放在了这里。

方法三

样本数量能够被分组数均匀分配的情况(仅适用于这个情况),更好的方法详见方法二。

数据的精确度可能还会受样本量和分组量的关系。本文中采用的100个样本和分成100/20/50都是可均匀分配的情况。如果不能均匀分配,可能取m的方式需要优化,应该采取python内含的最大力度均匀分组的函数。

代码语言:javascript复制
# 第二个方法
#只适用于样本数量能够被分组数量整除的情况
# 接着上面的定义

n = 100
#分成100个组,100个数据分成100个组,每个点和点之间的梯形都计算其面积,‘最精确的近似‘
m = round(len(wealths) / n)
#每个组之间的距离
y = yarray[range(0, len(wealths), m)]
#在y轴上选择那些矩形底部x轴相对应的y轴值
g = 1 - (1/100)*(2*sum(y) 1)
g

# 结果为
0.3109641735512395
#与上面计算的图形下面的面积相等

# 分成20个组
n = 20
m = round(len(wealths) / n)
# 每个组的距离
y = yarray[range(0, len(wealths), m)]
# 这些点的y坐标
g = 1 - (1/n)*(2*sum(y) 1)
g

# 结果为
0.31025484587225693


n = 50
m = round(len(wealths) / n)
y = yarray[range(0, len(wealths), m)]
g = 1 - (1/n)*(2*sum(y) 1)
g
# 结果为
0.3108691564481606



# 当样本量不能被分组数量均匀分配,会出现比较大的偏差。需优化,见方法3。
n = 40
m = round(len(wealths) / n)
y = yarray[range(0, len(wealths), m)]
g = 1 - (1/n)*(2*sum(y) 1)
g
# 结果为
0.13858644556020072


# 不准确
n = 9
m = round(len(wealths) / n)
y = yarray[range(0, len(wealths), m)]
g = 1 - (1/n)*(2*sum(y) 1)
g
# 结果为
0.1003202798725994

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/182450.html原文链接:https://javaforall.cn

0 人点赞