第三章:数据获取与预处理

各位同学,欢迎来到实战环节的第一步。说实话,很多做量化交易的朋友,模型搞得花里胡哨,最后死在哪?死在数据上。数据不干净,再牛的算法也是白搭。今天我们就来聊聊碳配额价格预测的「地基工程」——数据获取与预处理。

3.1 Python环境搭建:别让工具拖后腿

我个人习惯用 Anaconda 来管理环境。为什么?省心。你想想看,搞数据科学的人,最烦的就是装包报错。Anaconda 帮你把 numpy、pandas、scikit-learn 这些基础库都打包好了。

我建议你专门为碳交易项目建一个虚拟环境:

conda create -n carbon_trading python=3.9
conda activate carbon_trading
pip install pandas numpy matplotlib seaborn scikit-learn statsmodels

嗯,这里要注意。statsmodels 这个库做时间序列分析特别好用,后面我们做 ARIMA 模型时会频繁用到。我在项目中遇到过因为没装这个库,临时补装结果版本冲突的尴尬事。所以,一次性装齐,别偷懒。

小技巧: 如果你在国内,pip 安装慢的话,可以加个国内镜像源。比如清华源:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名

3.2 数据源选择:CEA 和 EUA 的门道

做碳配额价格预测,数据源就两个主流:中国碳配额(CEA)和欧盟碳配额(EUA)。两者差别很大,我分别说说。

3.2.1 CEA(中国碳配额)

CEA 的数据获取相对麻烦。目前国内有 8 个试点碳市场,加上全国碳市场,数据分散得很。我个人常用的渠道有:

  • 上海环境能源交易所:全国碳市场的交易数据在这里公布
  • 湖北碳排放权交易中心:历史数据比较全
  • Wind 金融终端:如果你有机构账号,这里的数据最干净

CEA 的数据频率一般是日频,偶尔有周频。注意,国内碳市场早期流动性很差,经常出现连续几天零成交的情况。这个后面处理缺失值时会讲到。

3.2.2 EUA(欧盟碳配额)

EUA 的数据就好拿多了。ICE(洲际交易所)是主要交易场所,数据公开透明。我建议直接从以下渠道获取:

  • ICE 官网:提供历史结算价,免费下载
  • Investing.com:可以导出 CSV,很方便
  • Quandl / FRED:如果你用 Python,可以直接调 API

EUA 的数据质量很高,流动性好,几乎不会出现连续零成交。但要注意,EUA 有期货和现货之分,我们做价格预测一般用主力期货合约的结算价。

核心区别: CEA 数据「脏、乱、少」,EUA 数据「干净、规整、多」。所以初学阶段,我建议先用 EUA 练手,等模型跑通了,再回头处理 CEA。

3.3 缺失值处理:别让空值毁了你的模型

数据拿到手,第一件事就是检查缺失值。我见过太多人,数据一拉就开始跑模型,结果跑出来一堆 NaN。为什么会这样?因为很多模型(比如 LSTM)不接受缺失值。

先看看数据长什么样:

import pandas as pd

df = pd.read_csv('EUA_data.csv', parse_dates=['Date'], index_col='Date')
print(df.isnull().sum())  # 检查每列的缺失值数量
print(df.info())          # 查看数据类型和缺失情况

处理缺失值,我一般按这个优先级来:

  1. 删除法:如果缺失比例小于 5%,直接删掉那几行。简单粗暴,但有效。
  2. 前向填充:用上一个非空值填充。适合价格数据,因为价格不会突变。代码:df.fillna(method='ffill', inplace=True)
  3. 插值法:用前后值的线性插值。适合时间序列。代码:df.interpolate(method='linear', inplace=True)
  4. 模型预测:如果缺失值太多(比如超过 20%),我会用 KNN 或随机森林来预测缺失值。但说实话,这种情况很少见。
避坑指南: 我曾经在 CEA 数据上直接用了前向填充,结果没注意到连续 10 天零成交。模型训练出来,预测值全是一条直线。后来我才发现,前向填充把零成交也当成正常价格传下去了。所以,处理缺失值之前,一定要先看看数据分布。

3.4 异常值检测:揪出那些「离谱」的数据点

异常值,说白了就是那些明显不符合规律的数据点。比如 EUA 价格突然从 50 欧元跳到 500 欧元,那大概率是数据录入错误。

我常用的检测方法有三种:

3.4.1 3σ 原则

假设数据服从正态分布,超出均值 ±3 倍标准差的值就是异常。代码很简单:

mean = df['Close'].mean()
std = df['Close'].std()
df['is_outlier'] = (df['Close'] > mean + 3*std) | (df['Close'] < mean - 3*std)

这个方法适合 EUA,因为 EUA 价格波动相对平稳。但 CEA 早期波动剧烈,用 3σ 可能会误删很多正常数据。

3.4.2 IQR 四分位距法

这个方法更稳健,不受极端值影响。计算 Q1(25%分位数)和 Q3(75%分位数),IQR = Q3 - Q1。超出 [Q1 - 1.5*IQR, Q3 + 1.5*IQR] 的就是异常。

Q1 = df['Close'].quantile(0.25)
Q3 = df['Close'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
df['is_outlier'] = (df['Close'] < lower_bound) | (df['Close'] > upper_bound)

我个人更推荐 IQR 法,尤其是处理 CEA 数据时。你想想看,CEA 早期价格从 20 元涨到 60 元,用 3σ 可能把 60 元判成异常,但那是正常的价格发现过程。

3.4.3 可视化辅助

别光靠代码,画个箱线图或者散点图,一眼就能看出问题:

import matplotlib.pyplot as plt

plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
df.boxplot(column='Close')
plt.title('箱线图 - 异常值一目了然')

plt.subplot(1, 2, 2)
plt.plot(df.index, df['Close'], 'b-', alpha=0.7)
plt.scatter(df.index[df['is_outlier']], df['Close'][df['is_outlier']], color='red', s=50)
plt.title('时间序列 - 红色点为异常值')
plt.tight_layout()
plt.show()
经验之谈: 发现异常值后,别急着删。先查一下那天有没有重大新闻。比如 2021 年 EUA 价格突然飙升,是因为欧盟公布了更激进的减排目标。那不是异常,那是市场在反应信息。

3.5 本章知识体系总览

下面这张图,把数据获取与预处理的整个流程串起来了。你可以把它当作一个检查清单,每次拿到新数据,按这个流程走一遍,基本不会出大问题。

数据获取与预处理流程 Python环境搭建 Anaconda + 虚拟环境 数据源选择 CEA vs EUA 数据加载 CSV / API / 数据库 缺失值处理 删除法 → 前向填充 → 插值法 → 模型预测 异常值检测 3σ原则 → IQR法 → 可视化辅助 ✅ 干净可用的数据集 注:CEA数据需额外注意流动性问题 EUA数据可直接使用标准流程

好了,数据获取和预处理这部分就讲到这里。记住一句话:数据质量决定了模型的天花板。你后面花再多时间调参,也弥补不了数据上的缺陷。所以,在这个阶段多花点功夫,绝对值得。


公众号:蓝海资料掘金营,微信deep3321