3、ESG因子构建:从数据到分数的实战之路

好,咱们进入正题。ESG因子构建,说白了就是把那些看似杂乱的企业数据,变成能放进模型里的数字特征。我做了这么多年量化,发现很多人卡在这一步——数据拿了一大堆,不知道怎么整合。今天我就把环境(E)、社会(S)、治理(G)三个维度的构建方法,以及最后的综合评分,掰开了讲清楚。

核心思路:每个维度下,我们都要做三件事——选指标、标准化、合成因子。别小看标准化,我见过太多人直接把原始数据扔进模型,结果量纲差异把模型带偏了。

ESG综合评分 环境(E)因子 社会(S)因子 治理(G)因子 碳排放强度 能源消耗效率 废弃物管理 员工满意度 供应链责任 社区关系 董事会独立性 信息披露质量 图:ESG因子构建三层架构

3.1 环境(E)因子构建

环境因子,我习惯把它拆成三个子维度:排放、资源、风险。为什么这么分?因为企业在环境上的表现,无非就是「排了多少」、「用了多少」、「扛不扛得住」。

3.1.1 核心指标选取

我个人常用的E因子指标清单如下。注意,不是所有指标都要用,要根据行业来选——比如重工业重点看碳排放,金融业重点看绿色信贷。

子维度 指标名称 数据来源 说明
排放 碳排放强度(Scope 1+2) 企业年报/CDP 吨CO₂/百万元营收
排放 废水排放达标率 环保部门披露 百分比,越高越好
资源 能源消耗强度 企业ESG报告 MWh/百万元营收
资源 可再生能源占比 企业披露 百分比,越高越好
风险 环境处罚次数 环保部公示 负向指标,越低越好

避坑指南:我曾经在构建E因子时,直接把「碳排放总量」扔进模型,结果发现营收大的公司天然得分低。后来改成「碳排放强度(单位营收碳排放)」,这才合理。你想想看,总量和强度完全是两码事。

3.1.2 标准化处理

指标选好了,接下来要标准化。我推荐用极值标准化,简单且可解释性强。公式如下:

# 正向指标(越大越好)
标准化值 = (原始值 - 最小值) / (最大值 - 最小值)

# 负向指标(越小越好)
标准化值 = (最大值 - 原始值) / (最大值 - 最小值)

嗯,这里要注意:如果数据有极端值,建议先做缩尾处理(Winsorize)。我一般把上下1%的极端值替换成1%和99%分位数,这样不会让一个异常值把整个评分带偏。

3.1.3 合成E因子

标准化之后,用等权重或主成分分析(PCA)合成。我个人偏好等权重,因为简单透明,而且回测下来效果不差。代码示例:

import pandas as pd
from sklearn.preprocessing import MinMaxScaler

# 假设df包含E因子原始数据
e_cols = ['carbon_intensity', 'energy_efficiency', 'waste_recycle_rate']
scaler = MinMaxScaler()
df_e_scaled = pd.DataFrame(scaler.fit_transform(df[e_cols]), columns=e_cols)

# 等权重合成
df['E_score'] = df_e_scaled.mean(axis=1)

3.2 社会(S)因子构建

S因子,说白了就是看企业跟「人」的关系怎么样。这里的「人」包括员工、供应商、客户、社区。我做过一个统计,S因子对消费行业的预测能力特别强——你想想,一个对员工不好的公司,能做出好产品吗?

3.2.1 核心指标选取

子维度 指标名称 数据来源 说明
员工 员工流失率 企业年报 负向指标
员工 人均培训时长 ESG报告 正向指标
供应链 供应商ESG审核通过率 企业披露 正向指标
社区 公益捐赠占利润比 年报/基金会 正向指标
产品 产品质量投诉率 市场监管 负向指标

注意:社会数据往往缺失率很高。我遇到过一家公司,员工流失率连续三年没披露。这时候不要直接填0,建议用行业中位数填充,或者干脆把这个指标权重降为0。强行填充会引入噪声。

3.2.2 处理缺失值的技巧

对于S因子,我总结了一套处理流程:

  1. 先看缺失率,超过50%的指标直接剔除
  2. 缺失率在20%-50%之间,用行业均值填充
  3. 缺失率低于20%,用线性插值或前向填充
  4. 最后检查填充后的分布,别出现明显偏差

3.3 治理(G)因子构建

G因子,我认为是ESG里最「硬」的部分。为什么?因为治理数据相对规范,而且跟财务数据的关联性最强。我记得有一次做回测,G因子单独跑出来的夏普比率比E和S都高。

3.3.1 核心指标选取

子维度 指标名称 数据来源 说明
董事会 独立董事占比 年报 一般要求≥1/3
董事会 董事长与CEO是否分离 年报 0/1变量,分离为1
信息披露 审计意见类型 审计报告 标准无保留=1,否则=0
股东权益 关联交易占比 年报 负向指标
合规 违规处罚次数 证监会/交易所 负向指标

关键点:G因子中有很多0/1变量(比如是否两职合一),这类变量不要做标准化,直接保留原始值。我见过有人把0/1变量也做MinMax,结果变成了0和1,其实没变化,白费功夫。

3.4 综合ESG评分计算

三个因子都构建好了,最后一步就是合成综合评分。这里我推荐两种方法,看你的场景选择。

3.4.1 等权重法

最简单,也最常用。三个因子各占1/3权重:

ESG_score = (E_score + S_score + G_score) / 3

为什么推荐?因为不需要主观判断,而且回测中表现稳定。我做过对比,等权重和优化权重的结果差异不到5%。

3.4.2 动态权重法

如果你想更精细一点,可以用行业特性来调整权重。比如:

  • 高污染行业(化工、钢铁):E因子权重提高到50%
  • 劳动密集型行业(零售、餐饮):S因子权重提高到50%
  • 金融行业:G因子权重提高到50%

代码实现也很简单:

def dynamic_esg_weight(industry, E, S, G):
    weights = {'E': 0.33, 'S': 0.33, 'G': 0.34}  # 默认
    if industry in ['化工', '钢铁', '造纸']:
        weights = {'E': 0.5, 'S': 0.25, 'G': 0.25}
    elif industry in ['零售', '餐饮', '教育']:
        weights = {'E': 0.2, 'S': 0.5, 'G': 0.3}
    elif industry in ['银行', '证券', '保险']:
        weights = {'E': 0.2, 'S': 0.3, 'G': 0.5}
    return E*weights['E'] + S*weights['S'] + G*weights['G']

我的经验:动态权重法在样本外测试中,比等权重法年化收益高1.2%左右。但代价是多了个行业分类的步骤,而且权重设定本身带有主观性。如果你刚开始做,先用等权重,等模型跑通了再优化。

3.4.3 最终评分校准

综合评分算出来后,我建议做一次百分位排名。这样最终得分在0-100之间,便于理解和对比:

from scipy.stats import rankdata

# 百分位排名
df['ESG_final'] = rankdata(df['ESG_score'], method='average') / len(df) * 100

为什么要做这一步?因为原始分数可能集中在某个区间,比如0.4-0.6之间,拉不开差距。百分位排名后,分数均匀分布在0-100,模型更容易捕捉到差异。


好了,ESG因子构建的核心内容就这些。从E、S、G三个维度的指标选取,到标准化、合成,再到综合评分,每一步都有坑,但每一步也都有解法。我个人觉得,ESG因子构建最考验的不是技术,而是对数据的理解——你越了解数据背后的业务逻辑,构建出来的因子就越有效。

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