试图计算 StackOverflow 声誉分布的基尼指数?

机器算法验证 基尼
2022-02-27 16:22:37

我正在尝试使用 SO Data Explorer 计算 SO 声誉分布上的 Gini 指数。我试图实现的等式是这样的:

G(S)=1n1(n+12(i=1n(n+1i)yii=1nyi))
在哪里:n= 网站上的用户数量;i= 用户序列号 (1 - 1,225,000);yi= 用户声誉i.

这就是我实现它的方式(从这里复制):

DECLARE @numUsers int
SELECT @numUsers = COUNT(*) FROM Users
DECLARE @totalRep float
SELECT @totalRep = SUM(Users.Reputation) FROM Users
DECLARE @giniNominator float
SELECT @giniNominator = SUM( (@numUsers + 1 - CAST(Users.Id as Float)) * 
                              CAST(Users.Reputation as Float)) FROM Users
DECLARE @giniCalc float
SELECT @giniCalc = (@numUsers + 1 - 2*(@giniNominator / @totalRep)) / @numUsers
SELECT @giniCalc

我的结果是(目前)-0.53,但这没有任何意义:我什至不确定它是如何变成负数的,即使在绝对值中,考虑到声誉如何,我预计不平等会更接近 1你拥有的越多。

我是否在不知不觉中忽略了一些关于声誉/用户分布的假设?

我做错了什么?

4个回答

我不能SQL很容易地阅读代码,但如果它有帮助,如果我要计算基尼系数,这就是我会做的(用简单的英语)。

  1. 弄清楚nx(即在 SO 上有代表的人数)
  2. 种类x从最低到最高
  3. 求和x乘以其在排名中的顺序(即,如果有 10 人,则代表最低的人的代表乘以 1,代表最高的人的代表乘以 10)
  4. 取该值并将其除以乘积n和总和x(IE。n×rep) 然后将该结果乘以 2
  5. 取该结果并减去1(1/n)从中。
  6. 瞧!

我从用于计算基尼系数的R函数(在ineq包中)中非常简单的代码中采取了这些步骤。作为记录,这是该代码:

> ineq::Gini
function (x) 
{
    n <- length(x)
    x <- sort(x)
    G <- sum(x * 1:n)
    G <- 2 * G/(n * sum(x))
    G - 1 - (1/n)
}
<environment: namespace:ineq>

它看起来与您的代码有些相似SQL,但就像我说的那样,我真的不能很容易地阅读!

我相信有四种等效的基尼指数公式。对我来说,最自然的一个是 U 统计量:

G=2μn(n1)ij|xixj|
在哪里μ是平均值x的。您可以使用此公式仔细检查您的计算。显然,结果必须是非负的。就我所知的基尼指数而言,CV上的声誉分布应该是基尼指数在0.9以上;0.98 是否有意义,但我不能说。

以下是使用 SQL 计算它的方法:

with balances as (
    select '2018-01-01' as date, balance
    from unnest([1,2,3,4,5]) as balance -- Gini coef: 0.2666666666666667
    union all
    select '2018-01-02' as date, balance
    from unnest([3,3,3,3]) as balance -- Gini coef: 0.0
    union all
    select '2018-01-03' as date, balance
    from unnest([4,5,1,8,6,45,67,1,4,11]) as balance -- Gini coef: 0.625
),
ranked_balances as (
    select date, balance, row_number() over (partition by date order by balance desc) as rank
    from balances
)
SELECT date, 
    -- (1 − 2B) https://en.wikipedia.org/wiki/Gini_coefficient
    1 - 2 * sum((balance * (rank - 1) + balance / 2)) / count(*) / sum(balance) AS gini
FROM ranked_balances
GROUP BY date
ORDER BY date ASC
-- verify here http://shlegeris.com/gini

解释在这里https://medium.com/@medvedev1088/calculating-gini-coefficient-in-bigquery-3bc162c82168

根据提供的等式添加到@smillig 答案:

SELECT something AS x into #t FROM sometable
SELECT *,ROW_NUMBER() OVER(ORDER BY x) AS i INTO #tt FROM #t
SELECT 2.0*SUM(x*i)/(COUNT(x)*SUM(x))-1.0-(1.0/COUNT(x)) AS gini FROM #tt

给我我的测试集:

0.45503253636587840

这与 R 的 ineq 库 Gini(x) 相同