用Python实战LMDI模型:拆解城市碳排放的驱动因素
当你拿到所在城市近十年的GDP、人口和能源消费数据时,是否曾好奇这些数字背后隐藏着什么故事?经济增长真的是碳排放增加的唯一"罪魁祸首"吗?本文将带你用Python一步步构建LMDI分解模型,像侦探一样找出影响碳排放的真正"元凶"。
1. 环境准备与数据收集
1.1 安装必要的Python库
在开始分析前,我们需要准备以下工具链:
# 基础数据处理 import pandas as pd import numpy as np # 科学计算 from scipy import stats import statsmodels.api as sm # 可视化 import matplotlib.pyplot as plt import seaborn as sns # 特殊计算 from pyLMDI import LMDI # LMDI分解专用库提示:如果遇到pyLMDI安装问题,可以使用
pip install git+https://github.com/caominhvu/pyLMDI.git从源码安装
1.2 构建基础数据框架
典型的城市碳排放分析需要以下核心数据表:
| 数据表 | 关键字段 | 数据来源示例 |
|---|---|---|
| 经济指标 | 年份、GDP总量、三大产业增加值 | 城市统计年鉴 |
| 人口统计 | 常住人口、城镇化率、年龄结构 | 人口普查数据 |
| 能源消费 | 煤炭/石油/天然气消费量(分部门) | 能源平衡表 |
| 碳排放因子 | 各类能源的CO2排放系数 | IPCC缺省值或本地化测算 |
数据质量检查要点:
- 时间跨度建议≥5年以观察趋势
- 部门划分需保持一致口径
- 缺失值不超过总数据量的15%
2. 数据预处理与特征工程
2.1 构建分析指标体系
基于Kaya恒等式扩展,我们建立以下分析框架:
# 计算衍生指标 df['人均GDP'] = df['GDP'] / df['人口'] df['能源强度'] = df['能源消费总量'] / df['GDP'] df['碳强度'] = df['碳排放总量'] / df['能源消费总量'] # 部门结构分解 for sector in ['工业','建筑','交通','居民']: df[f'{sector}能源占比'] = df[f'{sector}能源消费'] / df['能源消费总量']2.2 数据标准化处理
为避免量纲影响,需对数据进行标准化:
from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() numeric_cols = ['GDP','人口','能源消费总量','碳排放总量'] df[numeric_cols] = scaler.fit_transform(df[numeric_cols])注意:标准化仅用于指标对比,原始数据仍需保留用于实际计算
3. LMDI模型构建与分解
3.1 理解LMDI分解原理
LMDI(对数平均迪氏指数)的核心是将碳排放变化分解为:
ΔC = ΔC_pop + ΔC_aff + ΔC_ens + ΔC_mix + ΔC_int其中:
- ΔC_pop:人口效应
- ΔC_aff:富裕度效应(人均GDP)
- ΔC_ens:能源强度效应
- ΔC_mix:能源结构效应
- ΔC_int:排放因子效应
3.2 Python实现步骤分解
# 准备输入数据 data = { 'C': df['碳排放总量'].values, # 碳排放量 'E': df['能源消费总量'].values, # 能源消费 'Y': df['GDP'].values, # 经济产出 'P': df['人口'].values # 人口 } # 执行LMDI分解 lmdi = LMDI(data) result = lmdi.decompose('LMDI-I') # 可视化结果 plt.figure(figsize=(10,6)) result.plot(kind='bar', stacked=True) plt.title('碳排放驱动因素分解结果') plt.ylabel('贡献量(万吨CO2)') plt.show()典型输出解读:
- 正值表示该因素促进碳排放增长
- 负值表示抑制碳排放增长
- 绝对值大小反映影响程度
4. 深度解析与可视化呈现
4.1 动态趋势分析
使用滚动窗口观察效应变化:
window_size = 3 # 3年滑动窗口 effects = ['人口效应','经济效应','强度效应','结构效应'] for effect in effects: df[f'{effect}_rolling'] = df[effect].rolling(window=window_size).mean() # 绘制趋势线 plt.figure(figsize=(12,6)) for effect in effects: plt.plot(df['年份'], df[f'{effect}_rolling'], label=effect) plt.legend() plt.show()4.2 部门贡献度矩阵
# 构建部门-因素贡献矩阵 sectors = ['工业','建筑','交通','居民'] contrib_matrix = pd.DataFrame(index=sectors, columns=effects) for sector in sectors: sector_data = df[df['部门']==sector] lmdi = LMDI(sector_data) contrib_matrix.loc[sector] = lmdi.decompose('LMDI-I').mean() # 热力图呈现 sns.heatmap(contrib_matrix, annot=True, cmap='coolwarm', center=0) plt.title('各部门驱动因素贡献度')5. 进阶应用与案例解读
5.1 情景模拟分析
通过调整参数模拟不同发展路径:
def scenario_simulation(base_year, target_year, params): """ params = { 'GDP增长率': 0.05, '能源强度下降率': -0.03, '清洁能源占比提升': 0.02 } """ base = df[df['年份']==base_year].iloc[0] years = target_year - base_year simulated = base.copy() for _ in range(years): simulated['GDP'] *= (1 + params['GDP增长率']) simulated['能源强度'] *= (1 + params['能源强度下降率']) simulated['清洁能源占比'] += params['清洁能源占比提升'] return calculate_emissions(simulated)5.2 典型城市模式识别
通过聚类分析识别碳排放特征相似的城市群:
from sklearn.cluster import KMeans # 选择特征指标 features = df[['人均GDP效应','能源强度效应','结构效应']] # 肘部法则确定最佳K值 inertia = [] for k in range(1,10): kmeans = KMeans(n_clusters=k).fit(features) inertia.append(kmeans.inertia_) plt.plot(range(1,10), inertia) plt.xlabel('K值') plt.ylabel('SSE')6. 模型优化与验证
6.1 敏感性分析方法
def sensitivity_analysis(base_value, variations): results = [] for var in variations: modified = base_value * (1 + var) effect = calculate_effect(modified) results.append(effect) return pd.DataFrame({ '变化率': variations, '影响程度': results }) # 示例:GDP增长率±10%的影响 sensitivity_analysis(0.06, np.linspace(-0.1, 0.1, 5))6.2 交叉验证策略
采用时间序列交叉验证评估模型稳定性:
from sklearn.model_selection import TimeSeriesSplit tscv = TimeSeriesSplit(n_splits=3) for train_idx, test_idx in tscv.split(df): train = df.iloc[train_idx] test = df.iloc[test_idx] # 训练模型并验证 lmdi_train = LMDI(train) lmdi_test = LMDI(test) # 比较分解结果一致性在实际项目中,我发现能源结构效应的测算对数据质量最为敏感。某次分析中,由于电力消费的部门划分标准发生变化,导致结构效应出现异常波动。后来通过一致性调整方法,将历史数据按新标准重新归类,才得到合理的结果。这也提醒我们,在做长期趋势分析时,要特别注意统计口径的变化。