3、ESG因子构建:从原始数据到可用因子
好,咱们进入正题。ESG因子构建这块,说白了就是把那些评级机构给的原始分数,变成咱们量化模型能用的因子。我刚开始做这个的时候,也踩过不少坑——比如不同机构的评级压根儿不兼容,直接拼一起用,模型跑出来全是噪音。
今天我就把ESG因子构建的完整流程拆开讲。从数据源到标准化,每一步我都会结合自己的项目经验来说。
3.1 ESG评级数据来源:三大主流机构
目前市场上主流的ESG评级数据,主要来自三家机构:MSCI、Sustainalytics、Refinitiv。每家都有自己的打分逻辑,咱们得先搞清楚它们各自的特点。
| 机构 | 覆盖范围 | 评分区间 | 更新频率 | 我的评价 |
|---|---|---|---|---|
| MSCI | 全球约8500家公司 | AAA-CCC(7档) | 月度/季度 | 覆盖面广,但评级颗粒度偏粗 |
| Sustainalytics | 全球约12000家公司 | 0-100(分数越低越好) | 月度 | 风险导向,适合做风险因子 |
| Refinitiv | 全球约10000家公司 | 0-100(分数越高越好) | 季度 | 数据维度最细,适合做多维度因子 |
我个人习惯用Refinitiv的数据做基础因子构建。为什么?因为它把E、S、G三个维度拆成了10个主题、30多个指标,你能拿到非常细的颗粒度。MSCI的评级虽然名气大,但只有7档,做量化回测时区分度不够。
3.2 ESG综合得分计算:加权还是等权?
拿到原始数据后,第一步是算ESG综合得分。这里有个经典问题:E、S、G三个维度,该给它们分配多少权重?
我见过两种主流做法:
- 等权法:E、S、G各占1/3。简单粗暴,但问题在于——不同行业的环境风险差异巨大。比如一家石油公司和一家软件公司,E的权重能一样吗?
- 行业加权法:根据行业特性调整权重。比如高污染行业E的权重提到50%,金融行业G的权重提到40%。
嗯,这里要注意。我曾在项目中试过等权法,结果发现石油股的ESG得分被E维度严重拖低,而科技股的得分虚高。后来改用行业加权,效果好了不少。
下面是我常用的行业加权计算代码:
import pandas as pd
import numpy as np
def calc_esg_score(df, industry_weights):
"""
df: 包含E_score, S_score, G_score的DataFrame
industry_weights: 字典,key为行业代码,value为[E权重, S权重, G权重]
"""
df['ESG_score'] = 0.0
for industry, weights in industry_weights.items():
mask = df['industry'] == industry
df.loc[mask, 'ESG_score'] = (
weights[0] * df.loc[mask, 'E_score'] +
weights[1] * df.loc[mask, 'S_score'] +
weights[2] * df.loc[mask, 'G_score']
)
return df
# 示例:不同行业的权重配置
industry_weights = {
'能源': [0.5, 0.3, 0.2],
'金融': [0.2, 0.3, 0.5],
'科技': [0.3, 0.4, 0.3],
'消费': [0.3, 0.4, 0.3]
}
3.3 E/S/G各维度因子构建:拆开来看更清楚
ESG综合得分虽然方便,但说实话,它的预测能力往往不如单维度因子。我建议你至少构建以下三个维度的因子:
E维度因子:环境得分
- 碳排放强度:Scope 1+2排放量 / 营收。这个因子在能源、工业行业特别有效。
- 环境管理得分:Refinitiv的环境管理主题得分,反映公司是否有环保政策、目标。
- 绿色收入占比:来自绿色产品或服务的收入比例。这个数据不太好拿,但很有价值。
S维度因子:社会得分
- 员工满意度:可以用员工流失率、工伤率等指标代理。
- 供应链管理:供应商ESG审核覆盖率。我发现在消费品行业,这个因子对股价有显著影响。
- 产品责任:产品质量投诉率、数据隐私保护等。
G维度因子:治理得分
- 董事会独立性:独立董事占比。这个因子在A股市场效果不错。
- 高管薪酬合理性:CEO薪酬与员工中位数的比值。
- 股权结构:大股东持股比例、机构投资者占比。
你想想看,为什么要把E、S、G拆开?因为不同因子在不同市场环境下的表现差异很大。比如2020年疫情时,S维度因子(员工福利、供应链韧性)表现特别好;而2022年能源危机时,E维度因子(碳排放、能源效率)反而成了拖累。
3.4 ESG因子标准化处理:让数据说话
原始ESG数据的问题在于——不同维度的量纲不同,不同行业的分布也不同。比如E得分在0-100之间,但G得分可能集中在60-80之间。直接扔进模型,G维度会被E维度吃掉。
我常用的标准化方法有三种:
- Z-score标准化:减去均值,除以标准差。适合正态分布的数据。
- 分位数标准化:把原始分数映射到0-1之间的分位数。适合偏态分布。
- 行业中性化:在每个行业内做标准化,消除行业偏差。
我个人最推荐「行业中性化+分位数标准化」的组合。为什么?因为ESG数据在不同行业间的分布差异太大了——金融行业的G得分普遍高,能源行业的E得分普遍低。如果不做行业中性化,你构建的因子本质上是在做行业轮动,而不是选股。
def industry_neutral_rank(df, factor_col, industry_col='industry'):
"""
行业中性化+分位数标准化
"""
df['factor_rank'] = np.nan
for industry in df[industry_col].unique():
mask = df[industry_col] == industry
# 在行业内做分位数排名
rank = df.loc[mask, factor_col].rank(pct=True)
df.loc[mask, 'factor_rank'] = rank
# 再对整个截面做Z-score标准化
df['factor_standardized'] = (
df['factor_rank'] - df['factor_rank'].mean()
) / df['factor_rank'].std()
return df
知识体系总览
下面这张图,我把ESG因子构建的完整流程画出来了。你可以对照着看,每一步的输入输出是什么,以及它们之间的依赖关系。
好了,ESG因子构建的核心方法就这些。从数据源选择到综合得分计算,再到各维度因子构建和标准化处理,每一步都有讲究。我建议你拿到数据后,先画一张类似的流程图,把每个环节的输入输出理清楚,再动手写代码。
记住一句话:ESG因子的质量,90%取决于数据清洗和标准化,只有10%取决于模型本身。别在模型上花太多时间,先把数据搞干净。