
A股上市公司的内部控制评价报告一年少说也有几千份。我有一阵子天天跟这些PDF打交道痛点很直接文件都公开内容却很难批量用起来。后来用 CnOpenData 整理的 A股上市公司内部控制评价报告数据研究效率一下子就不一样了。这套数据的核心价值是把每年披露的《内部控制评价报告》从几十页的非结构化文本变成一张带证券代码、年份、内控结论、缺陷数量、审计意见类型的明细表。你不用再一家一家去巨潮资讯网下载附件也不用在几十页套话里找关键结论。拿到数据以后可以按年份、行业、板块做全市场统计也可以直接放进回归模型做实证研究还能用来搭一套内控质量负面清单辅助尽调和风控判断。这篇文章我会把数据本身的字段结构、内控结论的认定逻辑、实际使用时的典型场景以及我在使用过程中踩过的坑一次性说清楚给准备入手这套数据的朋友做个参考。1. 为什么内控评价报告值得做成一款结构化数据先说清楚一个背景问题内控评价报告是什么为什么它值得被单独做成一套库。按照《企业内部控制基本规范》和配套指引的要求A股上市公司需要定期对公司自身内部控制设计和运行的有效性进行自我评价并且对外披露《内部控制评价报告》。这份报告和年报审计报告不同它偏重的是“公司自己怎么看自己的内控”——董事会有没有建立合理的控制流程关键业务环节有没有控制措施控制措施有没有真正被执行有没有发现缺陷怎么整改。从披露要求看主板上市公司从2012年前后开始纳入强制披露范围境内外同时上市的公司更早一些。创业板、中小板公司随后也逐步纳入。所以如果你想看一个够长的时间序列2012年至今这个区间基本是完整的。问题在于这份报告本身是非结构化文本。每家公司写出来的格式、详略、措辞差别很大。有的公司把自己夸得很完整模板式地写“报告期内公司不存在财务报告内部控制重大缺陷”有的公司会非常具体地列出一两个重大缺陷说明原因、整改措施、责任人还有的公司会聘请会计师事务所出具内控审计报告单独形成一份意见。如果你只是在Wind或者Choice上看一两家公司问题不大翻一翻附件就行。但如果你要做全市场的研究需要同时看几千家公司的内控缺陷分布或者按行业、年份做统计分析靠人工整理几乎不可能完成。手工复制粘贴的误差、口径理解不一致、缺陷数量的漏统计都会让数据质量大打折扣。CnOpenData这套数据的定位就是把这个整理过程标准化。它把报告里的核心信息抽出来统一成固定的字段让研究者拿到手就能用。说实话这套数据对我最大的帮助不是“多了哪些新变量”而是把从原始文本到可用数据的时间从以周为单位缩短到了以小时为单位。2. 打开数据表先看什么核心字段与口径解读以我拿到的数据结构为例这套数据大致可以分成四组字段每一组对应报告里的不同内容模块。2.1 基本信息字段基本信息包括证券代码、证券简称、报告期年份、披露日期、报告名称等。证券代码建议统一按六位数字处理比如“000001”代表平安银行。“报告期年份”和“披露日期”要分清楚报告期年份指的是这份内控评价报告反映的是哪一年的内控情况而披露日期通常落在次年的三四月份。比如2023年度的内控评价报告披露日期一般在2024年4月30日之前报告中评价基准日通常是2023年12月31日。这个区分看着简单实际使用中极其容易出错。很多数据表里只给了一个“年份”字段你得先确认它到底是报告期还是披露期不然做事件研究时日期会算错一年。2.2 内控评价结论字段这部分是整套数据的信息密度最高区。核心字段包括内控有效性结论、内部控制评价范围、是否存在财务报告内部控制重大缺陷、是否存在非财务报告内部控制重大缺陷。内控有效性结论通常表述为“公司内部控制有效”或者“存在重大缺陷”对应数据里可能是一个分类变量比如“有效”和“无效”。这里需要特别注意报告本身的结论是公司董事会的自我评价不是外部审计意见。所以它本质上是一种管理层声明和注册会计师在《内部控制审计报告》里出具的意见是两回事。2.3 缺陷数量与等级字段缺陷数量字段一般会区分财务报告内部控制和内部控制两个维度再按严重程度分成重大缺陷、重要缺陷、一般缺陷三个等级。在数据表里你会看到类似这样的字段财务报告内部控制重大缺陷数量、财务报告内部控制重要缺陷数量、财务报告内部控制一般缺陷数量、非财务报告内部控制重大缺陷数量、非财务报告内部控制重要缺陷数量、非财务报告内部控制一般缺陷数量。这里有一个容易踩的坑一般缺陷数量在很多报告里是缺失的。因为按规定一般缺陷可以不具体披露数量很多公司只写“无重大缺陷、无重要缺陷”对一般缺陷可能只字不提。等你拿到数据时空值到底表示“审计后未披露”还是“公司认为无一般缺陷”需要小心判断。2.4 外部审计意见字段这部分数据来自上市公司同步披露的《内部控制审计报告》字段包括内控审计意见类型、审计机构名称、签字会计师等。内控审计意见类型大体上有标准无保留意见、带强调事项段的无保留意见、否定意见、无法表示意见几类。和财务报表审计意见一样内控审计意见也是外部独立第三方对公司内部控制有效性的判断参考价值比公司自己写的评价结论更硬。如果你在做研究或者风控判断时只看“公司自评是否有缺陷”会漏掉重要信息。一家公司可能自评一切正常但审计机构出具了否定意见这种情况在数据里会出现“自评无缺陷 外审否定意见”并存的组合处理的时候一定要把两类字段都纳入考虑。上面四组字段汇总成一张表的话大概是这样的字段分组字段示例说明基本信息证券代码证券简称报告期年份披露日期用于定位特定公司特定年度的披露评价结论内控有效性结论评价范围表述公司董事会对内控有效性的自我判断缺陷情况财务/非财务内控重大、重要、一般缺陷数量分维度、分等级统计缺陷披露情况外部审计内控审计意见类型审计机构名称注册会计师对公司内控的独立评价3. 内控结论背后是怎么认定的重大、重要与一般缺陷很多刚开始接触这套数据的人会对“重大缺陷”“重要缺陷”“一般缺陷”的分类感到困惑不太清楚这三个等级到底是怎么界定的。其实《企业内部控制评价指引》给出了基本框架具体认定标准由公司自己结合实际情况来确定。3.1 三个缺陷等级的定义按指引的定义重大缺陷是指一个或多个控制缺陷的组合可能导致企业严重偏离控制目标。重要缺陷是指一个或多个控制缺陷的组合其严重程度和经济后果低于重大缺陷但仍有可能导致企业偏离控制目标。一般缺陷是指除重大缺陷、重要缺陷之外的其他缺陷。光看定义比较抽象。落到实务里判断一个缺陷是不是重大主要看它对财务报告可靠性、资产安全、合规经营目标的影响程度。比如财务人员长期兼任不相容职务资金审批流程形同虚设导致大量资金被违规占用这种问题通常会被认定为重大缺陷而某个系统的权限设置不合理、某个流程的执行记录不完整影响范围小可能就落在一般缺陷或重要缺陷的区间。3.2 谁在定缺陷等级缺陷等级是由公司自己评估认定的这一点非常关键。同一件事两家公司披露出来可能等级完全不同。对研究者来说这套数据反映的不完全是“客观的内控质量”更多是“公司披露出来的内控信息”。比如同样一笔关联方资金占用问题一家公司可能认定自己是重大缺陷另一家公司可能说已经整改完成、不构成重大缺陷。这不是数据质量问题而是A股内控评价制度本身赋予公司的裁量空间。理解这一点你就不会把“无重大缺陷”读成“该公司内控完全没有问题”而是会把它理解成“公司内部评估认为不存在达到重大缺陷标准的控制缺陷”。这对研究和使用上有实质区别。3.3 财务报告内控和非财务报告内控的差异财务报告内部控制简单说就是与财务报告编制可靠性相关的内部控制包括财务核算、资金管理、收入确认、资产管理、关联交易等环节。这类内控出了问题直接影响财报数据真实性市场关注度最高。非财务报告内部控制覆盖的则是合规经营、资产安全、战略执行、经营效率等更广的范围。比如环保违规、产品质量事故、重大诉讼未及时应对这些可能归入非财务报告内控缺陷。数据表里这两类缺陷是分开的字段。使用的时候应该按研究目的决定用哪一类。如果研究主题是财务信息质量优先用财务报告内控缺陷字段如果研究主题是公司治理整体质量两个维度都要看。3.4 内控评价报告中“有效性结论”与“缺陷数量”的关系一般情况下如果公司披露了任何重大缺陷内控有效性结论就不会是“有效”而会变成“存在重大缺陷内控无效”之类的表述。但也要注意有的公司会在报告里写“公司内部控制有效但存在一项重大缺陷”严格来说这不符合规范表述实际披露里偶尔能见到。所以在处理数据时不要只盯着“内控有效性结论”这个字段要结合“财务报告内部控制重大缺陷数量”一起看。结论字段和数量字段有矛盾时优先以缺陷数量字段作为筛选条件因为数量是更细颗粒度的信息。4. 这套数据在研究与实务中的具体用法数据是工具关键还是看怎么用。基于我自己的实践这套数据在以下几个方向上都比较好使。4.1 学术研究内控质量与公司行为的关联分析这是最直接的应用方向。内控质量是一个在实证研究里很好用的解释变量“是否存在财务报告内部控制重大缺陷”可以直接当成一个0/1变量用来区分内控质量高和低的公司。研究主题可以有很多内控缺陷与财务重述的关系。有重大内控缺陷的公司后续出现财务重述的概率是不是更高内控缺陷披露的市场反应。公司发布“存在重大缺陷”的内控评价报告之后股价有没有显著的超额收益变化内控质量与审计费用。内控缺陷数量是否影响年报审计的定价内控缺陷对债务融资成本的影响。银行和债券投资者会不会因为内控否定意见要求更高的风险溢价这几个方向用这套数据作为核心解释变量再引入财务数据、市场数据作为控制变量逻辑上是顺的。数据量也够主板公司加创业板公司兼容跨度的面板数据跑固定效应模型没有问题。4.2 投研与风控负面清单筛选二级市场的投研分析经常需要排雷。内控评价报告特别是其中的否定意见和重大缺陷是很好的负面信息来源。我做过一个比较简单的筛选逻辑先筛出内控审计意见为“否定意见”或“无法表示意见”的公司再去掉已经退市的剩下的公司名单基本就是需要重点关注的名单。然后再看这些公司是否出现了高管频繁变动、审计机构辞任、关联方资金占用等信号。这套数据的优势在于可以做历史回看比如把过去五年每次被出具内控否定意见的公司列出来再对照它们后续的经营表现能看出不少规律。有些公司在被出具否定意见后的两年内就出现了债务违约内控缺陷实际上提前暴露了经营问题。4.3 审计与合规实务客户风险评估在事务所或者企业内审部门工作的人也可以把这套数据当作客商风险筛查的辅助工具。比如接一个新客户前先查一下对方近三年的内控评价报告和审计意见如果连续出现“重大缺陷”“重要缺陷”就要考虑这个客户的财务数据可信度、合作风险。再比如做供应商尽调时内控缺陷频发的供应商在合规方面大概率也存在隐患。4.4 构建内控质量指数如果你不满足于单个变量还可以用缺陷数量、审计意见类型、是否整改完成这几个字段构建一个简单的内控质量评分。比如内控审计意见为“标准无保留意见”计3分“带强调事项段”计2分“否定意见”计1分“无法表示意见”计0分。不存在重大缺陷再加1分存在则减1分。总分为基础分加调整分按行业做百分位排名就能得到一个行业内可比的内控质量排名。这个指数用于公司治理打分、ESG评价、量化选股里的风险因子构建都是可行的。缺陷越少的公司大概率在后续经营中表现出更好的稳定性。5. 使用这套数据容易踩的坑这部分是重头戏。数据虽然好用但如果不注意细节很容易得出错误结论。以下是我实际使用中遇到的问题。5.1 报告期与披露期混淆前面提过一次再强调一下。内控评价报告的年份是指报告期还是披露期直接影响面板数据的对齐。如果数据表里“年份”字段指的是报告期那2023年的内控数据对应的是2023年年报披露于2024年4月。如果你想看市场对“内控缺陷披露”的反应需要用披露日期做事件日如果你想看“当年内控质量对当年经营的影响”需要用报告期年份。两边混用会直接导致逻辑错误。5.2 空值不等于零这是最容易误判的一个点。数据表里大量出现空值的字段集中体现在“一般缺陷数量”上。很多公司不在报告里披露一般缺陷的详细数量所以这一列空值率可能很高。处理时你要先判断这个空值的语义。一种做法是全部置为0适合在一揽子统计时使用但会低估公司存在的实际缺陷数量另一种做法是保留空值只在研究“公司是否披露了一般缺陷”这个行为时使用。我一般建议根据研究目的选择如果做稳健性检验两种口径各跑一遍。5.3 公司自评与审计意见的矛盾公司自评“内控有效”审计机构却出具否定意见这种情况是真实存在的。遇到这种矛盾不要简单认为数据有问题。恰恰相反自评与外审的背离本身就是值得研究的信息。从披露制度的本意看审计意见的权威性更高实务中一般优先以审计意见作为实际内控有效性的判断标准。但如果你想研究“公司是否对外释放了过于乐观的内控信号”这种背离就非常有用。5.4 披露格式和监管要求的变化2012年至今A股内控评价报告的披露格式和指引要求发生过多次调整不同板块的要求也不完全一致。早期披露可能相对宽松近年逐渐严格。这种变化会导致数据在时序上的口径不完全一致。比如某一年份之前部分非财务报告缺陷不需要定量披露某一年份之后监管对缺陷认定标准提出了更细的要求。如果你做时间序列对比最好按年份把披露口径变化的影响单独考量别把单纯的口径调整当成公司内控质量的实际变化。5.5 停牌、退市与ST公司的数据缺失内控评价报告排除了部分停牌时间较长、退市风险较高的公司。这些公司恰恰可能是内控问题最集中的群体。如果样本里恰好缺少这些公司基于完整样本得到的统计结果会存在幸存者偏差。做严谨一点的研究时至少要说明样本筛选规则或者把退市公司的历史数据纳入进来做稳健性检验。CnOpenData的数据和官方披露保持一致原始公告没有覆盖到的内容库里自然也不会凭空多出来。5.6 股票代码和公司简称的历史变更A股的股票代码偶尔发生变化公司简称则年年都可能变。用简称去匹配合并数据非常不推荐。正确做法是始终用六位证券代码作为唯一标识同时关联一个“历史代码变更表”备用。还有一个细节是前导零问题。把证券代码导入Excel时000001会被自动转成1。数据合并前务必先把证券代码设为文本格式或者用填充函数补齐六位。6. 数据清洗与跨库合并的实操经验这部分细节比较多我按实际操作的顺序写一遍。6.1 拿到原始数据后的前三个动作第一步先看数据字典。确认每个字段的名称、类型、取值含义特别是判断“年份”字段是报告期还是披露期。第二步直接查看唯一性。用证券代码加年份两个字段做联合去重确认每家公司每年是否只有一条记录。如果出现重复通常是同一家公司当年发布了补充或修订版报告按披露日期取最新一条即可。第三步做缺失值统计。列出各字段的缺失率对缺失率高的字段单独标注根据自己的使用场景决定是剔除还是补全。6.2 证券代码标准化清洗前后最好加一步代码标准化统一处理成六位文本型代码。在Python里可以这样处理import pandas as pd df pd.read_csv(internal_control_data.csv, dtype{证券代码: str}) df[证券代码] df[证券代码].str.zfill(6) # 清洗后检查唯一性 print(df.duplicated(subset[证券代码, 报告期年份]).sum())如果你用的是R也有类似的处理逻辑本质就是保证代码不丢前导零、不加小数点、不做默认格式转换。6.3 与财务数据的合并学术界最常用的合并对象是CSMAR或者Wind里的财务数据。合并时注意两点内控评价报告数据按“报告期年份”关联年报数据两边是用同一会计年度的数据对齐。市场数据用披露日期关联内控缺陷披露事件前后的股价数据以披露日期为准。合并完成后可以做一次抽查挑几家你熟悉的公司核对一下它们的审计意见类型、缺陷数量是否和原始报告一致。这个步骤看着笨但能有效避免字段错位的隐患。6.4 文本字段的补充挖掘结构化字段之外报告原文里还有大量非结构化文本值得挖掘。特别是重大缺陷的具体描述这部分信息对理解缺陷成因非常有价值。CnOpenData这套库里如果包含了缺陷描述文本你就可以做关键词提取。比如用Python做简单的分词和关键词统计import jieba from collections import Counter def extract_keywords(text): words [w for w in jieba.cut(text) if len(w) 2] return Counter(words).most_common(20)对缺陷描述做文本分析后你会发现“资金占用”“关联交易”“违规担保”“财务造假”“审批流程”之类的高频词反复出现。这些关键词可以作为进一步识别风险的标签补充到结构化数据里。6.5 按板块和行业做分层统计清洗完成后最好先做一次基础描述性统计用交叉表看内控缺陷的分布结构。import pandas as pd df pd.read_csv(internal_control_data_clean.csv) # 按年份统计存在重大缺陷的公司数量 major_defect df[df[财务报告内部控制重大缺陷数量] 0] yearly major_defect.groupby(报告期年份)[证券代码].nunique() print(yearly)这种统计能帮你快速了解年份之间的趋势变化也方便检查数据是否有异常波动。7. 和它高度相关、可以一起用的周边数据内控评价报告数据单独用已经很有价值但如果你想做更完整的研究这套数据最好能和其他几类数据配合使用。7.1 内控审计报告数据内控审计报告和评价报告是一对。评价报告相当于公司的自评审计报告相当于外部体检。两组数据放到一起既能互相验证又能发现自评和外审意见背离的公司。7.2 上市公司违规处罚数据内控缺陷是风险的前置信号违规处罚是风险的最终暴露。把两者放在一起看能回答一个很有意思的问题公司出现内控缺陷之后多久会转化为实质性的违规在哪些情况下内控缺陷披露后公司会快速整改从而避免后续处罚7.3 审计意见与审计费用数据审计意见类型和内控质量强相关。把内控缺陷和年报审计意见、审计费用联合起来可以做审计定价、审计独立性相关的研究也可以用于构建更完整的公司治理指标。7.4 公司治理与高管特征数据内控缺陷的多少一定程度上反映了公司内部治理环境。结合董事会结构、高管变更、股权集中度等数据可以进一步解释为什么有的公司内控缺陷频发有的公司则一切平稳。从我自己的使用体验来说这套数据在做公司治理、财报质量相关课题时是不可缺的基础设施。它可以单独使用也可以作为数据生态的一环和审计、违规、财务数据相互印证。最后分享一个实操工具技巧建一个长期使用的内控风险研究库把内控评价数据、内控审计意见、违规记录、财务重述记录合并到一张宽表里按证券代码与报告期索引。后续每次做相关方向的问题直接查这张宽表效率会高很多。数据本身是静态的但如果你把它沉淀成体系化的研究组件价值会大得多。