ESG数据获取与清洗:主流数据源与预处理实战

做ESG因子预测,第一步就是搞数据。说实话,这一步往往是最磨人的。我见过太多团队,模型建得花里胡哨,结果数据源选错了,或者清洗不到位,最后全白干。今天咱们就聊聊ESG数据从哪来、怎么洗、怎么标准化。

主流ESG数据源:三巨头对比

目前市场上主流的ESG数据供应商有三家:MSCI、Sustainalytics和Refinitiv。这三家我都用过,各有各的脾气。

数据源 覆盖范围 评分体系 更新频率 我的评价
MSCI 约8,500家公司 AAA-CCC七档 月度/季度 覆盖面广,但新兴市场数据稀疏
Sustainalytics 约12,000家公司 0-100分(低风险=高分) 月度 风险导向,适合做风险因子
Refinitiv 约9,000家公司 0-100分(百分制) 季度 数据颗粒度最细,但API调用限制多

核心观点:没有完美的数据源。我个人习惯是至少融合两家数据源,取交集或加权平均。你想想看,如果只用一家,万一它某个月评分逻辑调整了,你的模型就跟着抽风。

数据获取实战:API调用与爬虫策略

获取ESG数据,通常有两种方式:官方API和网页爬虫。我建议优先用API,除非你预算有限。

以Refinitiv为例,它的API调用代码大概长这样:

import requests
import pandas as pd

# Refinitiv API配置
api_key = "your_api_key_here"
base_url = "https://api.refinitiv.com/esg/v1/"

# 获取某只股票的ESG综合评分
def get_esg_score(ticker):
    endpoint = f"{base_url}scores/{ticker}"
    headers = {"Authorization": f"Bearer {api_key}"}
    response = requests.get(endpoint, headers=headers)
    
    if response.status_code == 200:
        data = response.json()
        return data['esgScore']
    else:
        print(f"请求失败: {response.status_code}")
        return None

# 批量获取
tickers = ['AAPL', 'MSFT', 'GOOGL']
scores = [get_esg_score(t) for t in tickers]
print(pd.DataFrame({'ticker': tickers, 'esg_score': scores}))

小技巧:调用API时,记得加个重试机制。我曾经遇到过Refinitiv的API在月底特别不稳定,不加重试的话,数据获取到一半就断了,气得我直接写了个带指数退避的重试函数。

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

ESG数据的缺失率有多高?我告诉你,A股公司的ESG数据缺失率经常超过40%。为什么会这样?因为很多中小公司根本不披露ESG信息。

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

  1. 删除法:如果某只股票缺失超过70%的ESG指标,直接删掉。别心疼,留着也是噪声。
  2. 均值/中位数填充:对于连续型指标,用行业均值填充。注意是按行业分,不是全局均值。科技公司的ESG评分和能源公司能一样吗?
  3. 前向填充:对于时间序列数据,用上一期的值填充。ESG评分变化很慢,这个办法挺靠谱。
  4. 模型预测填充:如果缺失值集中在某些特定指标,可以用随机森林或KNN来预测缺失值。这个方法计算量大,但精度最高。

避坑指南:我曾经在做一个跨市场策略时,直接用全局均值填充了所有缺失值。结果呢?模型在发达市场表现很好,在新兴市场一塌糊涂。后来才发现,新兴市场的ESG数据缺失模式跟发达市场完全不同。所以,填充前一定要先分析缺失模式。

数据标准化方法:让不同量纲的数据对齐

ESG数据来自不同源,量纲千差万别。MSCI是AAA-CCC的等级制,Sustainalytics是0-100分,Refinitiv也是0-100分但评分逻辑不同。不标准化的话,模型根本没法用。

我常用的标准化方法有三种:

方法 公式 适用场景 注意事项
Z-score标准化 (x - μ) / σ 数据近似正态分布 对异常值敏感
Min-Max归一化 (x - min) / (max - min) 数据有明确边界 新数据可能超出范围
排名百分位 rank(x) / N 数据分布未知或偏态 丢失了数值间的距离信息

我个人最常用的是排名百分位法。为什么?因为ESG数据往往不是正态分布,很多公司集中在中间分数段,两头少。用Z-score的话,中间那堆数据会被压缩得很厉害。用排名百分位,至少保留了相对顺序。

import pandas as pd
from sklearn.preprocessing import MinMaxScaler, StandardScaler

# 示例数据
esg_data = pd.DataFrame({
    'company': ['A', 'B', 'C', 'D', 'E'],
    'esg_score': [65, 78, 42, 91, 55]
})

# 方法1:Z-score标准化
scaler = StandardScaler()
esg_data['zscore'] = scaler.fit_transform(esg_data[['esg_score']])

# 方法2:Min-Max归一化
scaler = MinMaxScaler()
esg_data['minmax'] = scaler.fit_transform(esg_data[['esg_score']])

# 方法3:排名百分位
esg_data['percentile'] = esg_data['esg_score'].rank(pct=True)

print(esg_data)

知识体系总览

下面这张图,是我梳理的本章核心逻辑。你看一眼,心里就有谱了。

ESG数据获取与清洗流程 数据源选择 MSCI / Sustainalytics / Refinitiv 数据获取 API调用 / 爬虫 / 批量下载 数据清洗 缺失值处理 缺失值处理策略 • 删除法(缺失率>70%) • 均值/中位数填充(按行业) • 前向填充 / 模型预测 标准化方法 • Z-score标准化 • Min-Max归一化 • 排名百分位(推荐) 标准化后的ESG数据集

我的经验:整个流程走下来,最耗时的不是建模,而是数据清洗。我做过一个统计,ESG因子预测项目里,数据获取和清洗占了60%的时间,建模和调参只占30%,剩下10%是写报告。所以,别急着上模型,先把数据搞干净。

嗯,关于ESG数据获取与清洗,核心就是这些。数据源选对、缺失值处理好、标准化方法选合适,后面建模就顺了。记住一句话:垃圾进,垃圾出。数据质量决定了模型的天花板。

专注资料整理