ARTICLE DETAIL

资讯详情

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

媒体关注度指标构建与Stata清洗方法:从原始新闻到公司面板

媒体关注度指标构建与Stata清洗方法:从原始新闻到公司面板 做公司金融和资产定价这类实证研究的人每年都会遇到类似的问询媒体关注度数据去哪找怎么清洗成公司-年度面板Stata代码怎么处理才算规范。尤其是2001—2024年这么长一个窗口横跨主板、中小板、创业板的几千家上市公司光是新闻匹配、去重、日期对齐就能把人绕晕。这篇内容适合正在写论文或者在复现经典文献的同学我会把从原始新闻表一路清洗到可直接回归的面板数据这个过程拆成一套可以反复用的思路顺带把配套代码里的关键命令讲清楚。先说结论媒体关注度不是一个只有“新闻条数取对数”这种单一口径的变量。它可以是年度报道总量可以是是否被报道的虚拟变量可以是不同情感倾向的报道数量甚至可以做“异常关注度”做增量信息。选择哪一种取决于你的研究问题。但无论如何前期的数据处理部分高度相似把一篇篇文本新闻转成公司-年份层面的统计量同时保证每个公司在每个年度都有对应的观测值没有新闻的年份不能被随手丢掉。1. 媒体关注度在实证里的价值以及它对数据清洗的隐藏要求媒体关注度这个概念学术界讨论了几十年从经典的有效市场假说到后来的有限注意力理论再到中文文献里特别爱用的“媒体治理”“舆情冲击”本质上都在利用同一个事实新闻不是均匀地落在每家公司头上的。某些公司一年被报道几百次另一些公司常年没有一条新闻这种差异本身就是信息。在回归模型里它的身份非常多。最常见的是当解释变量去解释股价崩盘风险、盈余管理、过度投资也能当被解释变量研究哪些公司特征吸引了媒体注意力还能在机制检验里当中间变量比如高管减持、信息披露违规这类事件先引起媒体关注再进一步影响市场反应。如果数据质量不过关后面所有结果都会被审稿人一句话打回来你的媒体关注度变量是怎么测的这恰恰是对数据清洗提出了很高的要求。打个比方你拿到的原始数据通常不是干净的股票代码而是一堆新闻表的记录里面写着“贵州茅台”“五粮液”“宁德时代”这样的公司简称甚至还有“茅台集团”“五粮液集团”这种关联主体。直接按字符串匹配就会把集团和上市公司的报道混在一起。还有转载新闻的问题一条新闻被新浪、网易、搜狐同时转载计数时如果不去重同一事件在一天内会被统计成多条报道你的年度关注度就虚增了。所以媒体关注度数据的处理流程至少要回答三件事 第一新闻主体如何对应到具体的上市公司代码 第二多源转载之后如何定义“一条真正的报道” 第三没有新闻的年份应该如何补零避免样本缺失导致选择性偏差。这些问题看似琐碎但对最终变量的有效性和稳健性非常关键。下面的内容就是围绕这三件事展开的。2. 数据源选型为什么2001—2024这个窗口需要分阶段看待先说数据源。目前做中文上市公司媒体关注度主流的三条路是中国研究数据服务平台CNRDS的“中国上市公司财经新闻数据库”、知网的中国重要报纸全文数据库、以及自己用爬虫程序从新闻门户抓取的历史存档。三者各有优缺点但一个共同点是它们的收录起始年份往往和公开数据库的覆盖范围有关2001年这个起点刚好与中国资本市场信息披露制度逐步完善的时间段重合能覆盖较完整的两轮牛熊周期所以很多研究都把起点设在2001年。CNRDS的数据结构比较适合直接做研究它一般会列出新闻标题、发布日期、来源媒体、公司名称等字段有些版本还自带了情感倾向标识。这类结构化数据是最省事的处理重点放在去重和公司名称归一化上。知网报纸库的历史跨度长2001年左右的报纸资料很全缺点是文本字段依赖人工或者正则清洗而且它主要是报纸网络媒体的覆盖度不够。如果要做2001—2024年这么长的时间序列特别需要警惕数据源在不同年份的收录逻辑变化。2005年之前网络媒体远不如报纸活跃很多新闻源收录的是纸质媒体扫描件2005年之后网络新闻逐渐兴起到了移动互联网时代新闻发布数量更是爆发式增长。如果你的统计口径没有控制“媒体类型”这个维度那么2010年之后的高被关注度很可能不是因为公司真的更重要了而是因为媒体总量增加了。这一点在数据处理阶段就需要留好来源字段后续分析时可以按报纸新闻和网络新闻分组或者单独报告排除网络新闻后的稳健性结果。我在实际项目里用的是CNRDS公司财经新闻的年度下载数据再手工补充了一部分上市公司公告和交易所处罚公告。标题里的2001-2024窗口我也是这样处理的凡是新闻日期落在该时间窗口内就进入样本公司的上市状态按年报期判断退市公司当年如果还在交易也保留。这样做的好处是样本更干净不会出现公司在上市之前就有“上市公司媒体关注度”记录的矛盾。3. Stata数据清洗主线从原始新闻表到公司-年度面板这一节是我最想和你分享的实操内容。拿到原始新闻表后很多人第一反应是直接分组计数然后写一句collapse (count)了事。这样写当然也能出数字但凡是碰上公司简称有变化、新闻里出现多个公司主体、或者源数据有重复导入的情况就会得到一份看似完美实则充满噪声的结果。我一般把清洗流程拆成四个环节公司简称库准备、日期标准化、主体识别、加总合并。3.1 准备一个带历史简称的上市公司基本信息表第一步非常关键准备一张以股票代码为唯一标识的“公司名时间表”。不是每个公司只有一个简称A股里绝大多数公司都改过名比如“贵州茅台”虽然没有改名但大量公司经历过从“某某科技”到“ST某某”再到“某某科技”的变化。媒体新闻标题里通常用的是当年对应的简称。如果只用最新简称去匹配好几年前的新闻都会被漏掉。这张公司名时间表可以手动整理也可以从CSMAR或Wind导出关键是字段要包含股票代码、股票简称、起始日期、结束日期。也就是说每个股票代码在不同时间段可以对应多个简称但同一时间段只能有一个有效简称。后续去匹配新闻标题时不是简单地strpos(news_title, company_name)而是要先判断新闻发布日期落在哪个时间窗口再用那个窗口的简称去匹配。这个细节非常影响准确率。用Stata实现时我通常是先把基本面信息读进来* 读取公司名字-时间表 import excel company_name_history.xlsx, firstrow clear rename 证券代码 stock_code rename 证券简称 stock_name rename 开始日期 name_start_date rename 结束日期 name_end_date gen date_start date(name_start_date, YMD) gen date_end date(name_end_date, YMD) format date_start date_end %td keep stock_code stock_name date_start date_end save company_name_history.dta, replace这样每个股票代码就对应了一串时间区间匹配的时候按年份区间取当时有效的简称。3.2 新闻日期与文本字段的清洗新闻表里最怕的是日期字段不是标准格式。有的写成“2020年8月5日”有的写成“2020/8/5”还有的是“20200805”。我的习惯是先把它们统一转换成Stata的整数日期格式这样后面按年份加总会非常快。对于中文日期文本可以用正则表达式先做replace再转换成date()函数。遇到编码问题也要注意很多老库导出的是GBK编码的中文内容Stata直接读取会全是乱码。这个场景下推荐先统一转成UTF-8编码再导入具体到Stata操作可以用import delimited ..., encoding(utf-8)或者使用unicode encoding set gb18030这类设置。中文数据分析的人应该都碰到过这个坑代码报错反而不是逻辑问题而是读取阶段文本就错了。举个例子import delimited news_gbk.csv, varnames(1) encoding(gb18030) clear如果读取后中文正常那就继续如果还不正常就先用文本编辑器另存为UTF-8版本再读。这个步骤不要省因为后续所有匹配都是靠中文公司简称进行的任何编码污染都会导致匹配率严重偏低。3.3 识别新闻主体生成公司代码候选列主体识别是媒体关注度处理中最核心的环节。我的做法是先对新闻标题和正文建立索引然后把每家公司当年的有效简称放进去用模糊匹配找交集。为了控制速度一般不会让所有简称去匹配所有新闻而是先把新闻按年份分组再把该年份有效的公司简称集合放进内存做遍历。简化版的Stata思路如下* 假设数据已包含 news_title, news_date, year * 先生成日期对应的年份 gen year year(date) * 对公司-新闻做交叉匹配 joinby year using company_name_history.dta, unmatched(both) gen is_mentioned strpos(news_title, stock_name) 0 keep if is_mentioned 1这个写法背后的逻辑是基于year做了笛卡尔积再用公司当年简称到新闻标题里去检索。如果新闻标题中提到了当时简称就认为该新闻关注到了该公司。一个新闻标题可以同时命中多家公司这种是正常的后续统计时保留即可。这里不用strpos也可以改用更复杂的regexm以应对带“ST”前后缀的情形但strpos更直观。3.4 去重注意转载和重复报道经过主体识别之后你会得到一张“新闻标题—公司代码”的长表。这张表里存在大量重复条数同一条新闻被不同媒体转载进而被多条记录也可能同一个媒体在一天内对同一事件连续发布了几乎相同的快讯。我的去重策略按两个层级执行。 第一层对同一公司、同一新闻标题、同一日期的记录只保留一条。如果新闻标题完全相同可以认为是同一条新闻的转载。 第二层对同一公司、同一天内、标题相似度极高的记录做人工抽样确认。有些数据库或者爬虫会加个“【快讯】”前缀正文一样但标题微调这类属于转载。实际的Stata命令往往是这个模式* 生成唯一识别键 duplicates drop company_code news_title news_date, force * 更严格的指纹匹配时可以先生成清洗后的标题变量 gen clean_title lower(trim(news_title)) egen news_id group(company_code clean_title news_date) duplicates drop news_id, force如果你用的数据自带新闻ID也可以用那个ID去重但我发现自带ID在不同数据库之间并不统一还是自己生成一个标准键来得放心。3.5 加总成面板不要丢掉零值去重后的每条记录就是一次“公司-年度”的有效报道。接下来最常规的操作就是按公司和年份加总媒体报道次数。collapse (count) n_news news_id, by(company_code year)但问题来了很多公司在某些年度没有任何新闻记录上面的collapse只会保留至少有1条新闻的公司-年度那些没有被媒体报道的公司-年度会被直接省略掉。如果直接拿那张表去和财务数据merge这些公司年度就会变成非匹配样本被当作缺失值。这就会把“没有媒体关注”和“数据缺失”混在一起是非常大的隐患。正确做法是先生成完整的公司-年度面板框架再把新闻统计量匹配上去缺失值替换成0* 从公司代码表生成每年的平衡框架 expand 24 bysort company_code: gen year _n 2000 * 合并加总统计量 merge 1:1 company_code year using news_agg.dta, keep(1 3) nogen replace n_news 0 if missing(n_news)这一步操作看似简单但它决定了你后续回归时的样本量。很多做面板研究的人最后样本里只有被报道过的公司原因就是漏了补零这一步后果是样本中系统性漏掉了冷门公司产生了选择偏差。4. 关注度变量的设计层次不是只有新闻条数取对数有了 n_news 这个基础计数后面能派生出多个变量口径。4.1 基础口径年度报道数量与对数化最常用的是ln_media ln(n_news 1)。为什么要加1取对数因为媒体报道次数是典型的右偏分布。某些热门公司一年几千条而多数公司一年只有个位数直接放进回归模型极端值影响会非常大残差也远非正态。取对数能把这些极端值压缩让变量更接近对称分布。加1是为了避免0取对数无意义。gen ln_media ln(n_news 1)这个变量解释起来也方便它度量的是媒体关注度的强度每增加1个百分点意味着样本内媒体报道的相对比例提升。系数大小甚至可以在不同论文之间做个粗略比较。4.2 倾向口径是否关注有些研究关心的是“有或无”不是“多或少”。比如用PSM做处理效应分析时需要把样本划分为被关注组和非关注组这时可以生成gen media_dum (n_news 0)这类变量更适合做匹配时的分组变量或者做probit模型的被解释变量。4.3 增量口径异常媒体关注度学术界越来越常用的是“异常媒体关注度”也就是剔除公司基本面、行业、市场整体环境之后媒体关注度不能被解释的残差部分。这个思想的来源是注意力分配理论——媒体有限的版面需要分配给“有新闻价值”的公司所以一家公司的关注度有一部分是系统性因素决定的我们不能把那一部分当作外生冲击。计算异常关注度时一般会先对原始关注度做回归控制住公司上期规模、账面市值比、上期市场收益、行业效应、年度效应等等然后把残差保存下来xtset company_code year xtreg ln_media L.ln_size L.bm L.ret i.year, fe robust predict e_media, e这个e_media就可以作为异常媒体关注度指标在因果识别中被当作外部信息冲击的代理变量。很多做股价崩盘和媒体报道的论文其实用的是这个口径而不是单纯的总报道次数。4.4 情绪口径区分正面、中性、负面如果数据库提供了情感倾向字段或者你自己用情感词典做了文本分类就可以把篇新闻拆成正面报道数、中性报道数和负面报道数得到更细的指标。常见的处理是把正面减负面再除以总数得一个媒体情绪净倾向指标也可以分开统计后分别取对数。这个方向虽然更花时间但它在做“媒体监督”和“市场情绪传导”研究时很多场景下比总关注度更有解释力。同一个公司被100条正面新闻刷屏和被100条负面新闻密集轰炸市场反应完全不一样如果你只用一个总数等于把这个最重要的信息维度对冲掉了。5. 实操中常见的坑和对应的排查套路数据和代码本身不复杂复杂的是你会遇到各种版本迭代后产生的脏数据。下面几个坑我踩过的概率基本是百分之百每个项目都会碰到一两个。5.1 公司更名导致的匹配年份错位最典型的例子是某个公司在2015年改了名字但新闻库里很多编辑依然会用旧简称发稿甚至同年内新旧名称混用。如果我的“公司简称历史表”里新名称从2015年3月1日生效那么2015年上半年发布的旧名称新闻就匹配不上最终关注度被低估。我的处理办法是在标准化的公司简称外再加一组“媒体别名”。像“五粮液”有时会在标题中被写成“五粮液股份”“中信证券”有时直接被写成“中信”还有的公司简称是“中航光电”而新闻标题里写“中航光电科技”。这种别名并不是简单的更名它是媒体在文本里自我缩写的结果。最好整理一列别名让多个词条都能指向同一个股票代码。* 别名表结构示例company_code, alias, alias_start, alias_end别小看这个过程它通常能把匹配率提升大约3到8个百分点。5.2 一篇新闻报道多家公司去重会不会误删一家公司的年报发布会现场新闻标题往往把行业内的重点公司都列了一遍“多家机构调研贵州茅台、五粮液、泸州老窖”。如果我按“新闻标题”作为去重键同一条标题命中三家公司就会被保留成三行这个是正确的因为这三家公司确实都在同一篇报道中被关注了。如果使用新闻数据库自带的新闻ID进行去重问题就出现了——同一ID很可能因为标题中包含多个公司而被记录下来多次直接用ID去重会把另外两家的记录删掉。所以我的原则是去重键必须包含“公司代码 新闻ID 新闻日期”而不是只对新闻ID去重。5.3 非上市公司主体被误纳入新闻标题里经常出现“某集团”而不是“某股份有限公司”。“五粮液集团”不是上市公司五粮液但新闻标题常写“五粮液集团召开会议”这类记录如果匹配上就错了。解决办法是在文本匹配时尽量用“证券简称”即不含“集团”“控股”等后缀形式的短名称再配合标题中出现该短名称但上下文没有“集团”等排除词时需要人工抽查判断。比较省事的替代方案是采用“精确简称 前后位置不可出现集团字样”的正则规则。这个思路在Stata里可以写成gen is_mention_com regexm(news_title, 五粮液) !regexm(news_title, 五粮液集团)逐家公司做太慢可以生成一个公司简称的临时循环批处理这里不展开但思路是一致的。5.4 同一事件被其他媒体转发带来的计数翻倍一条公司公告本身并不是媒体关注度但当它被各大财经门户转载后新闻数会激增。这时候最好分清楚“原创报道”和“纯转载”。如果数据源里给了媒体转载关系就保留主报道剔除后续的重复新闻如果没有退而求其次至少对“同一标题、同一公司、同日”的记录去重。这样虽然不能完全消除转载问题但已经能降低计数里的噪声。5.5 面板两端年份的冷启动问题2001—2024年的数据跨度很大最前和最后的一段年份经常有特殊现象。2001年偏早期证券类报纸数量有限媒体报道总量少关注度均值偏低2024年最新的数据可能存在“半年度截断”即当年还没结束新闻记录不全。如果不做处理直接用2001和2024两个端点年份做对比时会得出误导性结论。一个常见做法是去掉首尾各一年做稳健性检验尤其是当回归结果对极端年份特别敏感时。另一个做法是把年度虚拟变量放进模型让近年整体的媒体数量激增效应被年份固定效应吸收。6. 一些值得在项目一开始就想清楚的设计决策除了上面这些技术层面的内容有几件事是决定后续工作效率的关键如果你现在是从头搭建这个项目趁早想清楚能省很多返工时间。第一个是每年都备份一份去重前的原始长表。Stata处理流程中每一步都可能出错但原始表是所有统计量的底线。我通常跑完主体识别后先保存一版company_news_long.dta里面只有四列公司代码、年份、新闻标题、新闻日期。后面无论是画数据的增长趋势还是重算指标口径都只需要回到这一层而不必重新从CSV开始。第二个是统计维度上把“所有新闻”“报纸新闻”“网络新闻”同时列出来。上面讲数据源时提过这两年“媒体泛滥”带来的统计口径问题如果你从一开始就在原表里保留来源分组字段那么至少在后续稳健性检验里你可以很快地证伪“关注度上升只是因为媒体总量增加”这种质疑。第三个是把变量生成代码和样本清洗代码分开保存。我发现很多研究助理会把这些操作都写进同一个do文件等到换样本、换极值剔除方式的时候改一个参数就会连累前面的数据清洗。更合理的做法是第一个do文件专门输出回归面板字段只保留公司代码、年份、基础统计量和几个辅助变量第二个do文件才开始跑描述性统计、相关系数、主回归、稳健性和机制检验。第四个也是最后一点这组数据不要只拿来跑一条回归就结束。媒体关注度做出来的面板可以和很多数据库做交叉验证比如把极值年份的关注度数据和重大行政处罚公告日期做对齐看关注度峰值是否来自公司发布的违规公告或问询函回复。这类工作不仅能加强对数据的信任感还能给后面的论文找到非常好的案例切入点。从我这些年实际体会看媒体关注度数据处理的难点从来不是统计命令本身而是如何用一套可复现、可追溯的逻辑把成千上万的文本清洗成一个可信度的变量。只要你手里的公司代码和历史简称对应关系建得足够完整去重规则定义得足够清晰后面再遇到什么衍生需求都不慌。如果你准备拿这套数据做实证建议先别急着写主回归先把你洗出来的年度平均关注度和现实中的大事记做一次目视化对比数据质量其实一眼就能看得出来比任何统计检验都直观。
返回列表