数据采集与预处理:碳排放数据来源、数据清洗方法、异常值处理、数据标准化

好,咱们正式开始动手干活了。

前面几章聊了那么多理论,什么影子价格、因子映射、机器学习模型……说实话,没有数据,这些都是空中楼阁。我做了这么多年碳排放相关的研究,最深的体会就是:数据质量决定了模型的天花板。你模型再花哨,喂进去一堆垃圾数据,出来的结果就是垃圾——这在业内叫「Garbage In, Garbage Out」。

所以这一章,咱们就踏踏实实地把数据这块地基打牢。我会把我在实际项目中踩过的坑、总结的经验,都揉碎了讲给你听。

4.1 碳排放数据的主要来源

先说说数据从哪来。很多人一上来就问:「老师,有没有现成的碳排放数据集?」我的回答是:有,但很少能直接拿来用。

我个人习惯把数据来源分成三类:

  • 官方统计与报告数据:比如中国碳排放交易网、各省市的统计年鉴、生态环境部发布的温室气体排放清单。这些数据权威性高,但更新慢,而且粒度比较粗——通常是年度数据,按行业或省份汇总。
  • 企业披露与碳交易数据:来自碳交易市场的实际成交数据,包括配额价格、交易量、履约情况等。我在做碳金融项目时,就经常从上海环境能源交易所、湖北碳排放权交易中心抓取这些数据。优点是真实、高频,缺点是噪声大、缺失值多。
  • 卫星遥感与监测数据:比如NASA的OCO-2卫星、欧洲的Sentinel-5P卫星,可以提供大气CO₂浓度数据。这类数据空间覆盖广,但时间分辨率有限,而且需要专业处理。
我的经验之谈:别只依赖单一来源。我建议至少融合2-3个来源的数据,互相校验。比如用卫星数据验证企业报告的排放量,你会发现有些企业报的数据……嗯,你懂的。

4.2 数据清洗方法

数据拿到手,第一件事不是建模,而是清洗。说白了,就是给数据「洗澡」。

我遇到过最离谱的一次:某省碳排放数据里,有个企业的排放量是-5000吨。负排放?这企业难道是种树的?后来一查,是录入时把小数点打错了位置。

数据清洗的核心步骤,我总结为以下四点:

  1. 格式统一:日期格式、单位、编码方式必须一致。比如有的数据用「吨CO₂」,有的用「万吨」,不统一的话后面全乱套。
  2. 缺失值处理:对于时间序列数据,我一般先用线性插值填充短期缺失;如果缺失超过30%,我会直接删除该样本——强行填充反而会引入偏差。
  3. 重复值去重:同一个企业同一天的数据出现两次?保留第一条,删除重复项。但要注意,有些重复是合理的(比如不同口径的统计),需要结合业务逻辑判断。
  4. 数据类型转换:把字符串转成数值、把时间戳转成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倍四分位距的数据)。适合数据分布比较规整的情况。
  • 业务规则法:比如某行业单位产出的碳排放不可能低于某个阈值。我在做钢铁行业项目时,就发现有些企业的排放强度低得不合理——后来核实是数据造假。

处理方式上,我通常分三步走:

  1. 标记异常:先不急着删除,把异常值标记出来,单独分析原因。
  2. 核实来源:联系数据提供方,或者交叉验证其他数据源。如果是录入错误,直接修正;如果是真实事件,保留并备注。
  3. 替换或剔除:对于无法核实的异常值,我倾向于用中位数或前后均值替换,而不是直接删除——删除会破坏时间序列的连续性。
# 使用箱线图法检测异常值
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
避坑指南:我曾经用3σ原则处理一批数据,结果把真实的碳价波动(比如政策发布后的剧烈上涨)当成了异常值给剔除了。后来模型预测效果极差。所以记住:异常值不一定是错误,也可能是信号

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']]
)
重要提醒:标准化参数(均值和标准差、最大值和最小值)必须从训练集计算,然后应用到测试集。千万不能在整个数据集上统一标准化——那会造成数据泄露,让你的模型「作弊」。

本章知识体系总览

下面这张图,是我梳理的本章核心逻辑。你可以把它当作一个「数据预处理路线图」:

数据采集与预处理核心流程 数据来源 数据清洗 异常值处理 数据标准化 • 官方统计报告 • 企业碳交易数据 • 卫星遥感监测 • 格式统一 • 缺失值处理 • 重复值去重 • 统计方法检测 • 业务规则判断 • 替换或剔除 Z-score标准化 Min-Max归一化 输出:干净、标准化的特征矩阵

你看,整个流程是环环相扣的。从数据来源到清洗,再到异常值处理,最后标准化——每一步都在为下一步做准备。跳过任何一步,模型都可能出问题。

核心要点回顾

  • 数据来源要多元,互相校验
  • 清洗时保留原始备份,别直接覆盖
  • 异常值不一定是错误,先分析再处理
  • 标准化参数只从训练集计算,防止数据泄露

好了,数据预处理这块就聊到这儿。下一章咱们会把这些干净的数据喂进模型,看看影子价格到底怎么算出来的。不过在那之前,我建议你找个真实数据集,亲手跑一遍上面的代码——光看不练,等于白看。

专注资料整理