超越总收入差距:如何用Dagum基尼分解洞察区域发展不均衡(Python实战)
超越总收入差距:用Dagum基尼分解洞察区域发展不均衡的Python实战指南
当面对一组区域经济数据时,我们常常会问:这些差异究竟来自哪里?是同一区域内不同县市的贫富悬殊,还是不同区域之间的整体落差?传统基尼系数虽然能告诉我们"差距有多大",却无法揭示"差距从何而来"。这正是Dagum基尼分解方法的用武之地——它像一台精密的CT扫描仪,能清晰呈现经济差距的内在结构。
1. 理解Dagum基尼分解的核心价值
在区域经济分析中,单纯知道"某省基尼系数为0.4"远远不够。政策制定者需要明确:是该优先解决省内发达县与落后县的差距(组内不平等),还是应该重点协调不同地市之间的整体发展水平(组间不平等)?Dagum方法通过三个关键指标给出了量化答案:
- 组内差距(G_w):反映同一分组内部的不平等程度。例如同一地级市内各县区的发展差异。
- 组间净值差距(G_nb):衡量不同分组之间的平均发展水平差异。例如苏南与苏北地区的整体经济差距。
- 超变密度(G_t):捕捉分组间分布重叠带来的影响,解释那些"富县中的穷区域"和"穷县中的富区域"现象。
这三个指标的独特之处在于它们的可加性——三者之和正好等于总体基尼系数。这意味着我们可以精确量化每种差距对总不平等的贡献比例。例如某省分析结果可能显示:
| 指标 | 数值 | 贡献率 |
|---|---|---|
| G_w | 0.15 | 37.5% |
| G_nb | 0.20 | 50.0% |
| G_t | 0.05 | 12.5% |
| 总计 | 0.40 | 100% |
这样的分解结果直接指明:该省的发展不平衡主要源于地区间的整体差距(G_nb占50%),而非单个地区内部的差异。这对资源配置决策具有直接指导意义。
2. 数据准备与预处理实战
2.1 构建分析数据集
理想的数据结构应该包含三个维度:区域分组标识、观测单位(如县区)和经济发展指标(如人均GDP)。以下是一个模拟数据创建的Python示例:
import pandas as pd import numpy as np # 模拟生成某省3个地市下辖县区的人均GDP数据 np.random.seed(2023) data = [] for city in ['A市', 'B市', 'C市']: # 每个地市有5-8个县区 n_counties = np.random.randint(5, 9) # 根据地市整体水平设置基准值 if city == 'A市': base = 80000 # 发达地区 elif city == 'B市': base = 50000 # 中等地区 else: base = 30000 # 欠发达地区 # 生成各县区数据,考虑组内差异 for i in range(n_counties): gdp = base * np.random.uniform(0.7, 1.3) # 上下浮动30% data.append({'city': city, 'county': f'{city}县区{i+1}', 'pc_gdp': gdp}) df = pd.DataFrame(data) print(df.head(8))2.2 数据质量检查
在进行分析前,必须进行四项关键检查:
- 缺失值检测:
df.isnull().sum() - 异常值识别:通过箱线图或3σ原则排查
- 分组平衡性:各组观测单位数量不宜差异过大
- 指标合理性:如人均GDP是否在可信区间
提示:对于存在极端值的情况,建议同时分析原始数据和经Winsorize处理后的数据,比较结果稳定性。
3. Dagum分解的Python实现详解
3.1 核心算法实现
以下是完整的Dagum基尼分解函数实现,包含详细的注释说明:
def dagum_gini_decomposition(df, group_col, value_col): """ 执行Dagum基尼系数分解 参数: df: 包含分组和数值的DataFrame group_col: 分组列名 value_col: 待分析数值列名 返回: 包含G, G_w, G_nb, G_t及各组间指标的字典 """ import numpy as np from itertools import combinations, product groups = df[group_col].unique() group_data = {g: df[df[group_col]==g][value_col].values for g in groups} n = len(df) y_mean = df[value_col].mean() # 计算总体基尼系数 def _gini(a, b): diffs = np.abs(np.subtract.outer(a, b)) return diffs.sum() / (2 * len(a) * len(b) * (a.mean() + b.mean())) G = _gini(df[value_col].values, df[value_col].values) # 计算各组统计量 stats = {} for g in groups: data = group_data[g] stats[g] = { 'p_j': len(data)/n, # 组内单位数占比 's_j': len(data)*data.mean()/(n*y_mean), # 组内收入份额 'mean': data.mean() } # 按均值降序排列组别 sorted_groups = sorted(groups, key=lambda g: -stats[g]['mean']) # 计算组内差距G_w G_w = sum(_gini(group_data[g], group_data[g]) * stats[g]['p_j'] * stats[g]['s_j'] for g in groups) # 计算组间贡献 G_nb, G_t = 0, 0 D_jh = {} # 储存组间影响系数 for j, h in combinations(sorted_groups, 2): data_j = group_data[j] data_h = group_data[h] # 计算D_jh影响系数 diff_jh = np.subtract.outer(data_j, data_h) M_jh = np.where(diff_jh > 0, diff_jh, 0).mean() N_jh = np.where(diff_jh < 0, -diff_jh, 0).mean() D_jh[(j,h)] = (M_jh - N_jh) / (M_jh + N_jh) if (M_jh + N_jh) > 0 else 0 # 计算组间贡献 cross_gini = _gini(data_j, data_h) weight = stats[j]['p_j']*stats[h]['s_j'] + stats[h]['p_j']*stats[j]['s_j'] G_nb += cross_gini * D_jh[(j,h)] * weight G_t += cross_gini * (1 - D_jh[(j,h)]) * weight return { 'G_total': G, 'G_within': G_w, 'G_net_between': G_nb, 'G_transvariation': G_t, 'D_jh': D_jh, 'components_share': { 'within_share': G_w/G, 'between_share': G_nb/G, 'transvar_share': G_t/G } }3.2 结果可视化解读
分解结果的直观呈现至关重要。以下是使用matplotlib创建雷达图的示例:
def plot_dagum_results(result): import matplotlib.pyplot as plt import numpy as np labels = ['组内差距(G_w)', '组间净值差距(G_nb)', '超变密度(G_t)'] values = [result['G_within'], result['G_net_between'], result['G_transvariation']] shares = [result['components_share']['within_share'], result['components_share']['between_share'], result['components_share']['transvar_share']] fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5), subplot_kw={'polar': True}) # 绝对值雷达图 angles = np.linspace(0, 2*np.pi, len(labels), endpoint=False) values += values[:1] angles = np.concatenate((angles, [angles[0]])) ax1.plot(angles, values, 'o-', linewidth=2) ax1.fill(angles, values, alpha=0.25) ax1.set_xticks(angles[:-1]) ax1.set_xticklabels(labels) ax1.set_title('Dagum分解绝对值(G={:.3f})'.format(result['G_total']), y=1.1) # 相对贡献雷达图 shares = np.array(shares) * 100 shares = np.concatenate((shares, [shares[0]])) ax2.plot(angles, shares, 'o-', linewidth=2) ax2.fill(angles, shares, alpha=0.25) ax2.set_xticks(angles[:-1]) ax2.set_xticklabels(labels) ax2.set_title('各成分贡献比例(%)', y=1.1) plt.tight_layout() plt.show()4. 从数据到决策:深度解读与应用建议
4.1 典型结果场景分析
假设我们对某省三大经济带进行分析,得到以下结果:
总基尼系数: 0.42 - 组内差距(G_w): 0.15 (35.7%) - 组间净值差距(G_nb): 0.22 (52.4%) - 超变密度(G_t): 0.05 (11.9%)这显示该省的发展不平衡主要源于经济带之间的整体差距(G_nb占52.4%)。进一步分析组间影响系数D_jh:
| 对比组 | D_jh值 |
|---|---|
| 经济带A vs 经济带B | 0.82 |
| 经济带A vs 经济带C | 0.91 |
| 经济带B vs 经济带C | 0.68 |
高D_jh值(接近1)表明经济带之间存在明显的层级差异,特别是A与C之间。这提示政策应优先考虑:
- 跨区域基础设施投资:加强经济带之间的交通网络
- 产业协同规划:避免重复建设,形成互补产业链
- 人才流动机制:促进发达地区人才向欠发达地区流动
4.2 不同场景下的分析策略
根据G_w、G_nb的相对重要性,可采取不同的分析视角:
场景一:高G_w主导(组内差异大)
- 关注点:同一地市内县区发展不平衡
- 对策建议:
- 优化县域经济结构
- 加强市域内财政转移支付
- 建立县域协同发展机制
场景二:高G_nb主导(组间差异大)
- 关注点:区域整体发展落差
- 对策建议:
- 制定区域性发展战略
- 设立专项发展基金
- 推动跨区域合作项目
场景三:高G_t显著(重叠影响大)
- 关注点:发展水平的非均匀分布
- 对策建议:
- 精准识别"发展洼地"
- 实施靶向扶持政策
- 建立跨区域帮扶机制
5. 方法局限性与进阶技巧
5.1 注意事项与常见问题
在实际应用中,我们需要注意以下关键点:
- 分组合理性:组别划分需要基于实质性的社会经济特征(如地理分区、产业类型),而非随意分组
- 数据尺度效应:分析县域差距和使用乡镇级数据可能得出不同结论,需明确研究尺度
- 时间维度分析:建议进行多年份追踪,观察各成分的变化趋势
注意:当某些分组样本量过小时(如少于5个观测单位),相应的分解结果可能不够稳定,建议合并相关分组或谨慎解释。
5.2 方法扩展与交叉验证
为增强分析深度,可以结合其他方法:
空间自相关分析:检验地区差距是否存在空间集聚性
from esda.moran import Moran w = ... # 空间权重矩阵 moran = Moran(df[value_col], w) print(f"Moran's I: {moran.I:.3f}, p-value: {moran.p_sim:.4f}")分位数回归:考察不同发展水平地区的影响因素差异
动态分解分析:将基尼系数变化分解为各成分的贡献
下表对比了几种常见的不平等分析方法:
| 方法 | 优势 | 局限 | 适用场景 |
|---|---|---|---|
| Dagum分解 | 区分组内/组间来源 | 需要明确分组 | 区域政策评估 |
| Theil指数 | 可逐层分解 | 对低端敏感 | 多层次结构分析 |
| 变异系数 | 计算简单 | 缺乏分解能力 | 快速评估 |
| 空间基尼 | 考虑地理因素 | 计算复杂 | 区域集群研究 |
在实际研究中,建议先用基尼系数评估总体不平等程度,再通过Dagum分解识别主要矛盾来源,最后结合空间分析或回归方法探究深层原因。这种组合策略能提供更全面、更有操作性的分析结果。
