ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ESG评级分歧数据构建全流程:从清洗到指标计算与实证应用

ESG评级分歧数据构建全流程:从清洗到指标计算与实证应用 做ESG实证研究的朋友应该都有同感评级分歧这个变量看起来只是把几家评级机构的数据放在一起算个标准差但真到自己动手的时候光是数据清洗和匹配就能耗掉一两天。更别说不同评级机构的行业覆盖差异、Year-Company匹配精度、还有“评级打分和排名到底该用哪一个”这类细节稍微处理不好后面回归结果就全偏了。我最近整理了一份2009到2024年上市公司ESG评级分歧数据包含原始评级数据、计算代码和最终结果。这篇博文就把整个处理过程、碰到的坑和最终输出的字段设计全部摊开来讲让后面做相关研究的同学能少走点弯路。1. 项目背景与整体设计思路1.1 为什么ESG评级分歧值得单独做一份数据ESG评级分歧在近几年公司金融和资产定价研究里已经成了个高频变量。逻辑很直接不同评级机构对同一家公司的ESG表现给出不同评价这种分歧本身就能反映公司在ESG信息披露上的透明度、评级标准的不统一性、甚至管理层印象管理等深层次问题。但问题是这个变量的构建方式并没有统一的行业标准有的用标准差、有的用极差、有的用排名离散度不同算法做出来的结果对实证结论的支撑力度也不一样。这份数据的设计目标是解决三个痛点第一提供2009到2024年足够长的时间跨度覆盖A股ESG评级从起步到逐步完善的全周期第二把原始评级数据、中间计算代码、最终结果三层结构全部分离方便使用者根据自己研究需要调整算法第三输出多个分歧度量指标而不是只给一个标准差方便做稳健性检验时替换核心解释变量。1.2 评级数据源的选择与合并策略做ESG评级分歧数据第一步要解决的就是“拿哪几家机构的数据”。市面上常见的评级数据源包括华证、商道融绿、社会价值投资联盟社投盟、Wind自带的ESG评分、还有国外的MSCI和Sustainalytics。针对A股上市公司国内机构里华证和商道融绿的覆盖率最高社投盟虽然起步早但覆盖公司数量相对有限MSCI只覆盖纳入其指数的部分公司。我最终采用了华证、商道融绿、社投盟、Wind ESG四家机构的评级数据作为基础输入。选择这四家的理由是它们对A股的历史覆盖时间都比较长至少能追溯到2015年左右评级体系虽然有差异但都采用等级制如AAA到C、A到D等在已发表文献中被引用的频率较高审稿人也相对认可。需要注意每家机构的评级发布时间和覆盖范围存在差异需要统一到“公司-年度”维度进行对齐。1.3 时间跨度的特殊性2009到2024这个时间窗口其实是经过考虑的。2009年前后国内ESG评级机构开始对A股进行系统性覆盖商道融绿等机构的评级数据最早可追溯到这一阶段2024年是当前可获得完整数据的最近年度。做面板数据研究时间跨度越长越能支撑起固定效应模型的检验效力但过早年份的样本量较少评级覆盖度也不够完整这在后面数据处理中需要特别留意缺失值问题。2. 核心指标计算逻辑与代码实现2.1 四种分歧度量指标的推导我在数据集中提供了四类核心分歧指标每个指标从不同角度衡量评级分歧程度评级分歧标准差Std先将各机构评级转换为数值计算同一公司同一年的评级数值标准差。这个指标对极端值敏感能反映整体离散程度。评级分歧极差Range同一公司同一年度最高评级数值与最低评级数值的差值。极差的优势是直观易懂但容易受单一异常评级影响。评级排名分歧Rank先将各评级机构的评级转换为排名百分比再计算排名标准差。这样做的好处是部分消除了各机构评级分布偏好的影响更适合做截面比较。细分评级分歧E/S/G不只是总评级还分别计算环境E、社会S、治理G维度的分歧这样能更细致地研究各维度分歧对因变量的差异化影响。2.2 评级等级向数值转换的处理方式评级等级转数值是整个计算中最容易出现误差的环节。我对处理规则做了这样的设定以华证评级为例AAA赋值为9、AA为8、A为7、BBB为6、BB为5、B为4、CCC为3、CC为2、C为1商道融绿评级A定义为7、A为6、B为5、B为4、C为3、C为2、D为1社投盟评级AAA到D同样按9到1映射。Wind ESG评分是百分制为了统一量纲我将百分制分数除以10再向下取整转换为1到10的整数等级。这里有几个小技巧分享一是尽量在代码里保留评级等级的原始字符变量不要只保留数值这样后续如果要换映射规则还有原始数据可用二是在输出结果时把每家机构的原始评级也一同保留方便复现和核对。2.3 Python计算代码实现数据清洗和指标计算我用了Python完成核心逻辑并不复杂只是需要些耐心处理合并时产生的数据对齐问题。核心代码如下import pandas as pd import numpy as np # 读取原始评级数据 # 假设原始数据结构为stkcd(股票代码)、year(年度)、rating_huazheng、rating_syntao、rating_sheliantou、rating_wind df pd.read_excel(ESG_rating_original.xlsx) # 评级-数值映射字典 rating_map { AAA: 9, AA: 8, A: 7, BBB: 6, BB: 5, B: 4, CCC: 3, CC: 2, C: 1 } # 将评级等级转换为数值 for col in [rating_huazheng, rating_syntao, rating_sheliantou]: df[col _num] df[col].map(rating_map) # Wind评分转换为等级数值 df[rating_wind_num] np.floor(df[rating_wind] / 10) # 计算可用评级机构数量 rating_cols [rating_huazheng_num, rating_syntao_num, rating_sheliantou_num, rating_wind_num] df[rating_count] df[rating_cols].notna().sum(axis1) # 计算标准差和极差 df[esg_div_std] df[rating_cols].std(axis1, ddof0) df[esg_div_range] df[rating_cols].max(axis1) - df[rating_cols].min(axis1) # 排名转换后计算排名分歧 # 先对每个评级列按年度进行百分位数排名 for col in rating_cols: df[col _rank] df.groupby(year)[col].rank(pctTrue) rank_cols [col _rank for col in rating_cols] df[esg_div_rank] df[rank_cols].std(axis1, ddof0) # 保留关键字段 result df[[stkcd, year, esg_div_std, esg_div_range, esg_div_rank, rating_count]] result.to_csv(esg_disagreement_result.csv, indexFalse, encodingutf-8-sig)2.4 为什么用标准差而不是方差或变异系数在做指标设计时我也曾考虑用方差或变异系数但最终主指标选了标准差。原因有三一是标准差和方差在衡量离散程度上等价但标准差的单位和原始评级等级一致解释起来更直观二是在回归中标准差和方差只是线性变换不会影响显著性和符号方向但系数的经济含义更清晰三是文献中最常用的就是标准差用标准差做核心解释变量方便与已有研究结果对比。变异系数虽然能消除均值影响但在评级等级这种量纲固定的场景下反而会引入不必要的噪音。3. 实操过程从原始数据到最终结果3.1 原始数据清洗中的关键步骤拿到四家机构的原始评级数据后我做的第一件事不是急着合并而是先单独检查每家的数据结构。华证的评级列存在大量字符串前后空格商道融绿的评级列混入了“NR”无评级和“--”符号社投盟的数据在早期年份有部分评级为空的记录Wind的评分存在重复记录。这些都是典型的原始数据“脏数据”问题。处理原则是对于明确的“无评级”直接转为缺失值对于前后空格用strip函数清理对于重复记录保留最新发布日期的评级结果。清洗完成后我做了个简单的统计检查各年份各评级机构的覆盖公司数确保合并前数据的完整性。3.2 年度-公司维度的数据对齐四家机构的评级发布日期并不一致。华证的评级按月更新商道融绿按季度更新社投盟有临时调整Wind则是动态更新。在构建年度面板时我统一采用“当年年末12月31日最新可得评级”作为该年度的评级值。这样处理能最大化利用信息保证各机构评级在时间上尽量对齐。3.3 输出文件的格式设计我最终输出的结果文件包含以下关键字段证券代码、公司简称、统计截止日期、年度、华证评级等级、商道融绿评级等级、社投盟评级等级、Wind评级数值、评级分歧标准差、评级分歧极差、评级排名分歧、可用评级机构数量。每个字段都有用途评级等级和数值供使用者自己验证或调整映射规则分歧指标是核心变量可用评级机构数量在做样本筛选时非常有用比如要求至少3家机构同时覆盖时可以用这个字段过滤。3.4 样本量的动态调整在2009到2024年之间四家评级机构对A股的覆盖公司数并不是同步增加的。早期年份2009到2012只有少数机构有数据可用评级机构数量常常只有1家或2家这意味着计算不出分歧指标。随着年份推移特别是2018年以后四家机构的重叠覆盖公司数大幅增加到2024年有效样本基本能覆盖3000家以上上市公司。4. 各维度细分评级分歧的计算逻辑4.1 环境E、社会S、治理G维度的数据来源除了总评级分歧外这份数据还包含环境、社会、治理三个维度的分歧指标。这部分数据主要依赖华证和商道融绿两家的细分评级社投盟和Wind在细分维度的历史覆盖较浅强行纳入会导致大量缺失。因此细分维度分歧计算是在两家机构数据基础上进行的对于只有一家机构细分级别的公司则设为缺失值。4.2 细分分歧指标的算法细分分歧的计算相对简单先将各机构的环境维度评级转换为数值然后计算两两之间的绝对差作为环境分歧社会分歧和治理分歧同理。由于只有两家机构参与细分评分标准差和极差在数值上是等价的因此我直接输出细分级别的“分值差”作为细分分歧指标。为了便于区分我给变量名加了后缀如env_div、soc_div、gov_div。4.3 细分指标的价值与局限细分维度的分歧指标能帮助研究者更准确定位分歧来源——是环境信息披露不充分导致的分歧还是治理结构评估标准差异导致的分歧。但局限性也很明显只有两家机构参与计算稳健性略逊于总评级分歧早期年份2009到2014的细分数据覆盖非常有限做长时间窗口研究时需要注意样本减少的问题。5. 常见问题与排查技巧实录5.1 计算代码运行时的典型报错在实际跑数据的过程中有几个问题特别容易遇到评级列包含空字符串直接map后全部变成NaN这个问题最隐蔽。解决办法是map前先对列内容做空值替换df[col] df[col].replace(, np.nan)。同一公司同一年度有多条评级记录如果不做去重处理合并后的数据行数会翻倍。需要在合并前对各机构的数据按“公司年份”做唯一性确认。Excel打开CSV文件中文乱码输出CSV文件时要使用utf-8-sig编码而不是默认的utf-8。5.2 评级分歧计算中“可用机构数”的筛选逻辑在构造最终结果文件时我遇到了一个权衡问题如果要求四家机构必须有评级才能进入样本数据缺失率会非常高但如果只要求一家机构有评级就纳入那么很多观测值的分歧指标会因为没有对比而变成零反而引入测量误差。我最终的筛选逻辑是要求至少两家机构有评级时才计算分歧指标对于只有一家机构有评级的样本保留在数据集中但不计算分歧指标由使用者根据研究需求自行决定是否剔除。5.3 早期年份评级缺失的应对方法2009到2012年的数据覆盖度确实不理想这是由评级机构自身的业务推进节奏决定的不代表公司没有ESG表现。我的建议是如果研究的时间窗口能从2015年或2018年开始样本量和数据质量都会有明显提升。如果必须使用早期年份可以考虑只在稳健性检验中使用2009到2014年的子样本保证主回归的完整性和可靠性。5.4 与已有文献结果的对比验证数据做完后验证本身也很重要。我抽取了不同年份的若干样本公司与公开文献和新闻中提到的代表性公司ESG评级数据进行人工核对确认评级等级转换没有系统性偏差同时随机抽取了部分公司重新人工计算其分歧指标与代码输出结果进行比对确保计算逻辑无误。6. 进一步扩展与应用建议6.1 从年度分歧到动态分歧的扩展当前数据输出的是年度静态分歧但如果研究需要也可以基于逐月或逐季度的评级数据构建动态分歧指标比如年内评级分歧的波动率、评级上调下调的幅度等。这类动态指标在研究ESG评级修正、公司ESG信息披露策略调整等问题时往往比静态分歧更有解释力。6.2 结合市场数据做实证的常见思路拿到分歧数据后常见的实证方向包括ESG评级分歧与股价崩盘风险、与机构投资者持股决策、与审计收费、与公司债务融资成本的关系等。核心逻辑基本都是检验“评级分歧作为一种不确定性信号是否会显著影响市场参与者的行为决策”。这个方向目前发文的窗口期还在比较适合做交叉领域研究。6.3 常用稳健性检验替换方案如果你在审稿过程中被问到“更换分歧度量方式后结论是否依然成立”可以直接用我这份数据里的极差或排名分歧替换标准差重新跑一遍回归。也可以进一步调整评级等级映射规则比如把AAA到C改为9到-1的对称映射重新计算后检验结果是否一致这是最常用的稳健性检验做法。我自己的体会是做这类数据工作最耗时间的其实不是计算而是前期对数据口径的反复校准和对异常值的排查。把原始数据和代码一起放出来的好处是后续使用者可以清楚看到每一步的构造逻辑而不是拿着一个黑盒数据想改又不敢改。希望这份数据能为做相关研究的你省下几天的时间。
返回列表