数据采集与预处理:碳排放数据来源、数据清洗方法、异常值处理、数据标准化
好,咱们正式开始动手干活了。
前面几章聊了那么多理论,什么影子价格、因子映射、机器学习模型……说实话,没有数据,这些都是空中楼阁。我做了这么多年碳排放相关的研究,最深的体会就是:数据质量决定了模型的天花板。你模型再花哨,喂进去一堆垃圾数据,出来的结果就是垃圾——这在业内叫「Garbage In, Garbage Out」。
所以这一章,咱们就踏踏实实地把数据这块地基打牢。我会把我在实际项目中踩过的坑、总结的经验,都揉碎了讲给你听。
4.1 碳排放数据的主要来源
先说说数据从哪来。很多人一上来就问:「老师,有没有现成的碳排放数据集?」我的回答是:有,但很少能直接拿来用。
我个人习惯把数据来源分成三类:
- 官方统计与报告数据:比如中国碳排放交易网、各省市的统计年鉴、生态环境部发布的温室气体排放清单。这些数据权威性高,但更新慢,而且粒度比较粗——通常是年度数据,按行业或省份汇总。
- 企业披露与碳交易数据:来自碳交易市场的实际成交数据,包括配额价格、交易量、履约情况等。我在做碳金融项目时,就经常从上海环境能源交易所、湖北碳排放权交易中心抓取这些数据。优点是真实、高频,缺点是噪声大、缺失值多。
- 卫星遥感与监测数据:比如NASA的OCO-2卫星、欧洲的Sentinel-5P卫星,可以提供大气CO₂浓度数据。这类数据空间覆盖广,但时间分辨率有限,而且需要专业处理。
4.2 数据清洗方法
数据拿到手,第一件事不是建模,而是清洗。说白了,就是给数据「洗澡」。
我遇到过最离谱的一次:某省碳排放数据里,有个企业的排放量是-5000吨。负排放?这企业难道是种树的?后来一查,是录入时把小数点打错了位置。
数据清洗的核心步骤,我总结为以下四点:
- 格式统一:日期格式、单位、编码方式必须一致。比如有的数据用「吨CO₂」,有的用「万吨」,不统一的话后面全乱套。
- 缺失值处理:对于时间序列数据,我一般先用线性插值填充短期缺失;如果缺失超过30%,我会直接删除该样本——强行填充反而会引入偏差。
- 重复值去重:同一个企业同一天的数据出现两次?保留第一条,删除重复项。但要注意,有些重复是合理的(比如不同口径的统计),需要结合业务逻辑判断。
- 数据类型转换:把字符串转成数值、把时间戳转成datetime对象。这一步看似简单,但80%的代码报错都出在这里。
# 一个简单的数据清洗示例(Python)
import pandas as pd
# 加载数据
df = pd.read_csv('carbon_emissions.csv')
# 统一日期格式
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
# 填充缺失值(线性插值)
df['emission'].interpolate(method='linear', inplace=True)
# 删除重复行
df.drop_duplicates(subset=['company_id', 'date'], keep='first', inplace=True)
# 转换数据类型
df['emission'] = pd.to_numeric(df['emission'], errors='coerce')
4.3 异常值处理
异常值,说白了就是「看着不对劲」的数据。但「不对劲」不一定是错误,也可能是真实的极端事件——比如某工厂发生事故导致排放骤降。
怎么判断?我一般用两种方法:
- 统计方法:3σ原则(超过均值±3倍标准差的数据视为异常)或箱线图法(超出1.5倍四分位距的数据)。适合数据分布比较规整的情况。
- 业务规则法:比如某行业单位产出的碳排放不可能低于某个阈值。我在做钢铁行业项目时,就发现有些企业的排放强度低得不合理——后来核实是数据造假。
处理方式上,我通常分三步走:
- 标记异常:先不急着删除,把异常值标记出来,单独分析原因。
- 核实来源:联系数据提供方,或者交叉验证其他数据源。如果是录入错误,直接修正;如果是真实事件,保留并备注。
- 替换或剔除:对于无法核实的异常值,我倾向于用中位数或前后均值替换,而不是直接删除——删除会破坏时间序列的连续性。
# 使用箱线图法检测异常值
Q1 = df['emission'].quantile(0.25)
Q3 = df['emission'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 标记异常
df['is_outlier'] = (df['emission'] < lower_bound) | (df['emission'] > upper_bound)
# 用中位数替换异常值
median_val = df['emission'].median()
df.loc[df['is_outlier'], 'emission'] = median_val
4.4 数据标准化
数据标准化,说白了就是把不同量纲的数据拉到同一个尺度上。你想想看,碳排放量可能是几十万吨,而GDP增速只有几个百分点——如果不做标准化,模型会天然地「偏爱」数值大的特征。
常用的标准化方法有两种:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score标准化 | z = (x - μ) / σ | 数据近似正态分布,或存在明显异常值 |
| Min-Max归一化 | x' = (x - min) / (max - min) | 数据有明确边界,或需要保持原始分布形状 |
我个人习惯:如果后续要用线性模型(比如线性回归、SVM),我会优先用Z-score;如果用神经网络或深度学习,Min-Max更常见——因为激活函数对输入范围敏感。
# Z-score标准化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df[['emission', 'gdp_growth', 'energy_price']] = scaler.fit_transform(
df[['emission', 'gdp_growth', 'energy_price']]
)
# Min-Max归一化
from sklearn.preprocessing import MinMaxScaler
minmax_scaler = MinMaxScaler()
df[['emission', 'gdp_growth', 'energy_price']] = minmax_scaler.fit_transform(
df[['emission', 'gdp_growth', 'energy_price']]
)
本章知识体系总览
下面这张图,是我梳理的本章核心逻辑。你可以把它当作一个「数据预处理路线图」:
你看,整个流程是环环相扣的。从数据来源到清洗,再到异常值处理,最后标准化——每一步都在为下一步做准备。跳过任何一步,模型都可能出问题。
核心要点回顾:
- 数据来源要多元,互相校验
- 清洗时保留原始备份,别直接覆盖
- 异常值不一定是错误,先分析再处理
- 标准化参数只从训练集计算,防止数据泄露
好了,数据预处理这块就聊到这儿。下一章咱们会把这些干净的数据喂进模型,看看影子价格到底怎么算出来的。不过在那之前,我建议你找个真实数据集,亲手跑一遍上面的代码——光看不练,等于白看。