ESG因子构建基础:从数据到信号

各位同学,欢迎来到实战课的第二讲。上一章我们聊了ESG因子为什么能赚钱,这一章我们得动真格的了——把ESG因子从概念变成可计算的数字。

说实话,ESG因子构建是整个策略中最枯燥、也最容易踩坑的环节。我做了这么多年量化,见过太多人拿着漂亮的ESG评分直接跑回测,结果一塌糊涂。为什么?因为数据源没搞清楚,指标定义有偏差,清洗步骤漏掉了。

今天我们就来拆解E、S、G三大维度的核心指标,以及数据怎么拿、怎么洗。嗯,这部分内容虽然基础,但决定了你后面所有工作的成败。

核心观点:ESG因子不是简单的评分加总,而是需要根据行业特性、数据质量、时效性进行精细化构建。一个粗糙的ESG因子,还不如不用。

ESG因子构建 环境(E) 社会(S) 治理(G) 碳排放 能源效率 水资源 员工关系 产品安全 社区关系 董事会结构 股东权利 信息披露 数据来源与清洗 缺失值处理 异常值检测 标准化 行业调整 标准化ESG因子分数

一、环境(E)因子:碳排与资源效率

环境因子是ESG里最「硬」的一块。为什么?因为碳排放、能耗这些数据相对可量化,不像「企业文化」那么虚。我个人习惯把E因子拆成三个子维度:

  1. 碳排放强度:范围1(直接排放)+ 范围2(能源间接排放),除以营收。这是最核心的指标。
  2. 能源效率:单位营收能耗,或者单位产品能耗。不同行业差异巨大,钢铁和互联网没法比。
  3. 环境管理:有没有环境认证?有没有环境违规记录?这个偏定性,但也很重要。

实战技巧:我在做A股ESG因子时发现,很多公司不披露范围3(供应链排放)。这时候别硬算,直接用范围1+2就够了。数据缺失本身也是一种信号——不披露的公司往往环境风险更高。

举个例子,我们拿万得ESG数据里的碳排放字段,通常长这样:

# 伪代码:碳排放强度计算
df['carbon_intensity'] = df['scope1_emission'] + df['scope2_emission']
df['carbon_intensity_ratio'] = df['carbon_intensity'] / df['revenue'] * 1e6  # 吨/百万元

你想想看,同样的碳排放量,放在一家万亿市值的银行和一家百亿市值的化工企业里,意义完全不同。所以一定要做营收标准化。

二、社会(S)因子:人、产品与社区

S因子是最难量化的。我刚开始做ESG研究时,最头疼的就是S因子——你说员工满意度怎么量化?总不能每个季度发问卷吧?

实践中,我们通常用这些代理变量:

子维度 常用指标 数据来源
员工关系 员工流失率、人均培训时长、薪酬水平 年报、社会责任报告
产品安全 产品召回次数、质量认证、客户投诉率 监管公告、第三方评测
社区关系 公益捐赠占比、本地化采购比例 企业ESG报告
供应链责任 供应商ESG审核覆盖率、冲突矿产政策 供应链披露文件

避坑指南:我曾经踩过一个坑——直接用「员工人数」作为S因子。结果发现,劳动密集型行业天然得分高,科技公司反而低。这完全颠倒了逻辑。后来我改用「人均培训投入」和「员工流失率」的组合,效果才正常。

这里有个关键点:S因子指标之间经常存在多重共线性。比如「人均薪酬」和「员工流失率」高度相关。我建议用PCA或者因子分析先降维,别一股脑全塞进去。

三、治理(G)因子:公司质量的底色

治理因子,说白了就是看这家公司是不是在「好好经营」。我个人认为G因子是ESG三兄弟里最稳定的——E和S可能受行业影响大,但好的治理在任何行业都管用。

核心指标包括:

  • 董事会独立性:独立董事占比、董事长是否兼任CEO
  • 股权结构:大股东持股比例、机构投资者占比
  • 信息披露质量:财务重述次数、审计意见类型
  • 高管薪酬:薪酬与业绩的挂钩程度、股权激励比例

我记得有一次做回测,发现G因子在熊市里特别能抗跌。为什么?因为治理好的公司,管理层不会乱投资、不会搞利益输送,现金流更稳健。嗯,这个逻辑在A股尤其明显。

# 治理评分示例
def governance_score(df):
    score = 0
    # 独立董事占比 > 1/3 加1分
    score += (df['indep_director_ratio'] > 0.333).astype(int)
    # 董事长不兼任CEO 加1分
    score += (df['chairman_ceo_separate'] == 1).astype(int)
    # 近3年无财务重述 加1分
    score += (df['restatement_3y'] == 0).astype(int)
    return score / 3  # 归一化到0-1

四、数据来源与清洗:80%的功夫在这里

做量化的人都知道一句话:garbage in, garbage out。ESG数据尤其如此。我见过太多人从万得或者Bloomberg拉下来数据就直接用,结果回测曲线漂亮得不像话——后来发现是数据前向填充导致的未来函数。

常用的数据源有:

  • 万得ESG数据:覆盖A股最全,但部分指标更新频率低(季度甚至年度)
  • 商道融绿:ESG评级数据,适合做截面比较
  • 中财绿金院:偏学术,有碳排放估算数据
  • 公司年报/ESG报告:最原始的数据源,但需要NLP提取

清洗环节,我建议按这个流程走:

  1. 缺失值处理:ESG数据缺失率经常超过30%。别直接删,试试行业均值填充,或者用「缺失即差」的逻辑(缺失值赋最低分)。
  2. 异常值检测:比如碳排放强度突然翻10倍,大概率是数据录入错误。用3-sigma或者IQR方法处理。
  3. 标准化:不同指标量纲差异巨大,必须做Z-score或者Min-Max归一化。
  4. 行业调整:这是ESG因子构建的灵魂。银行和钢铁的碳排放强度能比吗?不能。所以要做行业内标准化。

核心代码:行业调整标准化

def industry_neutralize(df, factor_col, industry_col):
    """
    行业中性化处理:在每个行业内做Z-score标准化
    """
    df['factor_z'] = df.groupby(industry_col)[factor_col].transform(
        lambda x: (x - x.mean()) / x.std()
    )
    return df

# 使用示例
df = industry_neutralize(df, 'carbon_intensity_ratio', 'sw_industry')
# 注意:碳排放是负向指标,标准化后要取负号
df['e_score'] = -df['factor_z']

你想想看,如果不做行业调整,你拿到的ESG因子其实反映的是「行业属性」而不是「公司质量」。煤炭股天然E因子低,但你不能说所有煤炭公司都不好——得在同行业里比谁做得更好。

我的经验:数据清洗这一步,我通常会花整个项目60%的时间。别嫌慢,后面回测阶段出问题再回头找数据原因,那才叫痛苦。我曾经因为一个数据对齐错误,浪费了两周时间——从那以后,我每步清洗都写日志。

好了,这一章的内容就到这里。ESG因子构建是个细活,E、S、G每个维度都有各自的脾气。下一章我们会把这些因子组合起来,看看怎么在行业轮动策略里真正用起来。


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