基尼系数函数需排序→累积占比→套公式:1 - 2×sum(cumsum)/n + 1/n;自动剔nan、支持负值但建议平移处理;不依赖scipy,避免np.diff/np.trapz误差,时间复杂度o(n log n)。

用 numpy 写最简基尼系数函数,别碰 scipy.stats.gini
Python 标准库和主流科学计算包里没有内置的基尼系数函数——scipy 从没提供过 gini,网上搜到的所谓“scipy.stats.gini”全是错觉或过时文档。真要算,得自己写,而且必须从排序和累积和出发。
核心逻辑就三步:排序 → 算累积占比 → 套公式 1 - sum(累计权重 × 对应排序后值占比)。下面这个版本够用、易懂、抗负值(比如财富数据含负债):
import numpy as np <p>def gini(x): x = np.asarray(x) if len(x) == 0: return np.nan x = x[~np.isnan(x)] # 自动剔除 NaN if len(x) </p><p>注意:这个实现默认把 <code>x</code> 当作原始数值(如个人净资产),不强制要求非负;若你传入的是已归一化的概率分布(和为 1),结果一样,但语义不同。</p><h3>传入负值或零值会怎样?为什么不能直接用 <code>np.diff</code> 或 <code>np.trapz</code> </h3><p>基尼本质是洛伦兹曲线下的面积,而洛伦兹曲线定义域是 [0,1],值域也必须是非负的——所以当数据含负数(比如净财富为负的人群),严格来说“财富基尼”无定义。但实操中常做平移处理:<code>x = x - x.min() + 1e-8</code>,避免除零或负占比。</p><p>有人想用 <code>np.trapz</code> 数值积分洛伦兹曲线,容易翻车:</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill8054" title="python-parallelization"><img src="https://img.php.cn/upload/skill/000/000/081/179181013081932.jpg" alt="python-parallelization" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill8054" title="python-parallelization" class="overflowclass">python-parallelization</a> <p class="overflowclass">将顺序 Python 代码转换为并行/并发实现,用于在需要并行化 Python 代码、提升性能时使用。</p> </div> <a rel="nofollow" href="/xiazai/skill8054" title="python-parallelization" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div>
-
np.trapz要求横纵坐标严格等长且单调,而原始数据未排序时直接喂进去会得到垃圾结果 -
np.diff搭配排序后数组算“阶梯高度”,容易漏掉首尾点,导致面积偏差 >5% - 更隐蔽的坑:用
np.mean(np.abs(x[:, None] - x[None, :])) / (2 * np.mean(x))这种两重循环形式,时间复杂度 O(n²),万级数据就卡住
和 statsmodels 的 gini 结果对不上?检查权重参数和排序方向
statsmodels.stats.weightstats.gini(注意路径)支持加权,但默认按升序排,而有些论文或工具(如 World Bank 的 PovCalNet)默认降序——顺序反了,基尼值会变。
关键差异点:
-
statsmodels版本:接受weights参数,适合分组汇总数据(如各省人均收入+人口数) - 自定义函数默认无权重,若要加权,得先展开成重复数组(小数据可行)或改用加权累积和:
cumsum = np.cumsum(w * x_sorted) / np.sum(w * x_sorted) - 两者在
x=[1,1,1,1]时都返回 0.0;但在x=[0,0,0,1]时,不加权结果是 0.75,加权(权重全为 1)也一致;但若权重是[1,1,1,100],结果跳到 ~0.98
实际算居民收入基尼时,三个硬性前置动作不能省
真实数据不是教科书数字,直接扔进函数大概率得出荒谬值(比如 >1 或负数):
- 先做
np.clip(x, a_min=0, a_max=None):剔除明显异常负值(统计误差、录入错误),别靠“理论允许”硬扛 - 确认单位统一:全省数据混着“元/月”和“万元/年”?必须全部转成同单位再归一化或直接计算
- 样本代表性检查:如果只拿到前 10% 高收入者数据,基尼会被严重高估——这不是算法问题,是数据缺陷,函数没法救
基尼系数本身对极值敏感,一个百万收入混在万元群体里,就能让结果跳升 0.03 以上。与其纠结公式细节,不如花两倍时间清洗和理解数据来源。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










